• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #if defined(WEBRTC_POSIX)
14 #include <sys/select.h>
15 #endif
16 #include <time.h>
17 
18 #include <string>
19 #include <vector>
20 
21 #include "absl/flags/flag.h"
22 #include "absl/flags/parse.h"
23 #include "absl/flags/usage.h"
24 #include "examples/peerconnection/server/data_socket.h"
25 #include "examples/peerconnection/server/peer_channel.h"
26 #include "rtc_base/checks.h"
27 #include "system_wrappers/include/field_trial.h"
28 #include "test/field_trial.h"
29 
30 ABSL_FLAG(
31     std::string,
32     force_fieldtrials,
33     "",
34     "Field trials control experimental features. This flag specifies the field "
35     "trials in effect. E.g. running with "
36     "--force_fieldtrials=WebRTC-FooFeature/Enabled/ "
37     "will assign the group Enabled to field trial WebRTC-FooFeature. Multiple "
38     "trials are separated by \"/\"");
39 ABSL_FLAG(int, port, 8888, "default: 8888");
40 
41 static const size_t kMaxConnections = (FD_SETSIZE - 2);
42 
HandleBrowserRequest(DataSocket * ds,bool * quit)43 void HandleBrowserRequest(DataSocket* ds, bool* quit) {
44   RTC_DCHECK(ds && ds->valid());
45   RTC_DCHECK(quit);
46 
47   const std::string& path = ds->request_path();
48 
49   *quit = (path.compare("/quit") == 0);
50 
51   if (*quit) {
52     ds->Send("200 OK", true, "text/html", "",
53              "<html><body>Quitting...</body></html>");
54   } else if (ds->method() == DataSocket::OPTIONS) {
55     // We'll get this when a browsers do cross-resource-sharing requests.
56     // The headers to allow cross-origin script support will be set inside
57     // Send.
58     ds->Send("200 OK", true, "", "", "");
59   } else {
60     // Here we could write some useful output back to the browser depending on
61     // the path.
62     printf("Received an invalid request: %s\n", ds->request_path().c_str());
63     ds->Send("500 Sorry", true, "text/html", "",
64              "<html><body>Sorry, not yet implemented</body></html>");
65   }
66 }
67 
main(int argc,char * argv[])68 int main(int argc, char* argv[]) {
69   absl::SetProgramUsageMessage(
70       "Example usage: ./peerconnection_server --port=8888\n");
71   absl::ParseCommandLine(argc, argv);
72 
73   // InitFieldTrialsFromString stores the char*, so the char array must outlive
74   // the application.
75   const std::string force_field_trials = absl::GetFlag(FLAGS_force_fieldtrials);
76   webrtc::field_trial::InitFieldTrialsFromString(force_field_trials.c_str());
77 
78   int port = absl::GetFlag(FLAGS_port);
79 
80   // Abort if the user specifies a port that is outside the allowed
81   // range [1, 65535].
82   if ((port < 1) || (port > 65535)) {
83     printf("Error: %i is not a valid port.\n", port);
84     return -1;
85   }
86 
87   ListeningSocket listener;
88   if (!listener.Create()) {
89     printf("Failed to create server socket\n");
90     return -1;
91   } else if (!listener.Listen(port)) {
92     printf("Failed to listen on server socket\n");
93     return -1;
94   }
95 
96   printf("Server listening on port %i\n", port);
97 
98   PeerChannel clients;
99   typedef std::vector<DataSocket*> SocketArray;
100   SocketArray sockets;
101   bool quit = false;
102   while (!quit) {
103     fd_set socket_set;
104     FD_ZERO(&socket_set);
105     if (listener.valid())
106       FD_SET(listener.socket(), &socket_set);
107 
108     for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i)
109       FD_SET((*i)->socket(), &socket_set);
110 
111     struct timeval timeout = {10, 0};
112     if (select(FD_SETSIZE, &socket_set, NULL, NULL, &timeout) == SOCKET_ERROR) {
113       printf("select failed\n");
114       break;
115     }
116 
117     for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i) {
118       DataSocket* s = *i;
119       bool socket_done = true;
120       if (FD_ISSET(s->socket(), &socket_set)) {
121         if (s->OnDataAvailable(&socket_done) && s->request_received()) {
122           ChannelMember* member = clients.Lookup(s);
123           if (member || PeerChannel::IsPeerConnection(s)) {
124             if (!member) {
125               if (s->PathEquals("/sign_in")) {
126                 clients.AddMember(s);
127               } else {
128                 printf("No member found for: %s\n", s->request_path().c_str());
129                 s->Send("500 Error", true, "text/plain", "",
130                         "Peer most likely gone.");
131               }
132             } else if (member->is_wait_request(s)) {
133               // no need to do anything.
134               socket_done = false;
135             } else {
136               ChannelMember* target = clients.IsTargetedRequest(s);
137               if (target) {
138                 member->ForwardRequestToPeer(s, target);
139               } else if (s->PathEquals("/sign_out")) {
140                 s->Send("200 OK", true, "text/plain", "", "");
141               } else {
142                 printf("Couldn't find target for request: %s\n",
143                        s->request_path().c_str());
144                 s->Send("500 Error", true, "text/plain", "",
145                         "Peer most likely gone.");
146               }
147             }
148           } else {
149             HandleBrowserRequest(s, &quit);
150             if (quit) {
151               printf("Quitting...\n");
152               FD_CLR(listener.socket(), &socket_set);
153               listener.Close();
154               clients.CloseAll();
155             }
156           }
157         }
158       } else {
159         socket_done = false;
160       }
161 
162       if (socket_done) {
163         printf("Disconnecting socket\n");
164         clients.OnClosing(s);
165         RTC_DCHECK(s->valid());  // Close must not have been called yet.
166         FD_CLR(s->socket(), &socket_set);
167         delete (*i);
168         i = sockets.erase(i);
169         if (i == sockets.end())
170           break;
171       }
172     }
173 
174     clients.CheckForTimeout();
175 
176     if (FD_ISSET(listener.socket(), &socket_set)) {
177       DataSocket* s = listener.Accept();
178       if (sockets.size() >= kMaxConnections) {
179         delete s;  // sorry, that's all we can take.
180         printf("Connection limit reached\n");
181       } else {
182         sockets.push_back(s);
183         printf("New connection...\n");
184       }
185     }
186   }
187 
188   for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i)
189     delete (*i);
190   sockets.clear();
191 
192   return 0;
193 }
194