blob: fdc84ddbc293d54ea8aa2995b4457f070933cf60 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
Donald E Curtisa8736442015-08-05 15:48:13 -07002 * Copyright 2011 The WebRTC Project Authors. All rights reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
Donald E Curtisa8736442015-08-05 15:48:13 -07004 * 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.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
Niels Möller433eafe2018-10-04 14:33:20 +020011#include <assert.h>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012#include <stdio.h>
13#include <stdlib.h>
Yves Gerey3e707812018-11-28 16:47:49 +010014#if defined(WEBRTC_POSIX)
15#include <sys/select.h>
16#endif
17#include <time.h>
18#include <string>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000019#include <vector>
20
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "examples/peerconnection/server/data_socket.h"
22#include "examples/peerconnection/server/peer_channel.h"
Bjorn Terelius3e676762018-10-29 15:26:27 +010023#include "rtc_base/flags.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "rtc_tools/simple_command_line_parser.h"
Bjorn Terelius3e676762018-10-29 15:26:27 +010025#include "system_wrappers/include/field_trial.h"
26#include "test/field_trial.h"
27
28WEBRTC_DEFINE_string(
29 force_fieldtrials,
30 "",
31 "Field trials control experimental features. This flag specifies the field "
32 "trials in effect. E.g. running with "
33 "--force_fieldtrials=WebRTC-FooFeature/Enabled/ "
34 "will assign the group Enabled to field trial WebRTC-FooFeature. Multiple "
35 "trials are separated by \"/\"");
henrike@webrtc.org28e20752013-07-10 00:45:36 +000036
37static const size_t kMaxConnections = (FD_SETSIZE - 2);
38
39void HandleBrowserRequest(DataSocket* ds, bool* quit) {
40 assert(ds && ds->valid());
41 assert(quit);
42
43 const std::string& path = ds->request_path();
44
45 *quit = (path.compare("/quit") == 0);
46
47 if (*quit) {
48 ds->Send("200 OK", true, "text/html", "",
49 "<html><body>Quitting...</body></html>");
50 } else if (ds->method() == DataSocket::OPTIONS) {
51 // We'll get this when a browsers do cross-resource-sharing requests.
52 // The headers to allow cross-origin script support will be set inside
53 // Send.
54 ds->Send("200 OK", true, "", "", "");
55 } else {
56 // Here we could write some useful output back to the browser depending on
57 // the path.
58 printf("Received an invalid request: %s\n", ds->request_path().c_str());
59 ds->Send("500 Sorry", true, "text/html", "",
60 "<html><body>Sorry, not yet implemented</body></html>");
61 }
62}
63
Robin Raymond1c62ffa2017-12-03 16:45:56 -050064int main(int argc, char* argv[]) {
tkchinbad7b092016-03-11 20:45:16 -080065 std::string program_name = argv[0];
66 std::string usage = "Example usage: " + program_name + " --port=8888";
67 webrtc::test::CommandLineParser parser;
68 parser.Init(argc, argv);
69 parser.SetUsageMessage(usage);
70 parser.SetFlag("port", "8888");
71 parser.SetFlag("help", "false");
72 parser.ProcessFlags();
73
74 if (parser.GetFlag("help") == "true") {
75 parser.PrintUsageMessage();
henrike@webrtc.org28e20752013-07-10 00:45:36 +000076 return 0;
77 }
78
Bjorn Terelius3e676762018-10-29 15:26:27 +010079 webrtc::test::ValidateFieldTrialsStringOrDie(FLAG_force_fieldtrials);
80 // InitFieldTrialsFromString stores the char*, so the char array must outlive
81 // the application.
82 webrtc::field_trial::InitFieldTrialsFromString(FLAG_force_fieldtrials);
83
tkchinbad7b092016-03-11 20:45:16 -080084 int port = strtol((parser.GetFlag("port")).c_str(), NULL, 10);
85
henrike@webrtc.org28e20752013-07-10 00:45:36 +000086 // Abort if the user specifies a port that is outside the allowed
87 // range [1, 65535].
tkchinbad7b092016-03-11 20:45:16 -080088 if ((port < 1) || (port > 65535)) {
89 printf("Error: %i is not a valid port.\n", port);
henrike@webrtc.org28e20752013-07-10 00:45:36 +000090 return -1;
91 }
92
93 ListeningSocket listener;
94 if (!listener.Create()) {
95 printf("Failed to create server socket\n");
96 return -1;
tkchinbad7b092016-03-11 20:45:16 -080097 } else if (!listener.Listen(port)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000098 printf("Failed to listen on server socket\n");
99 return -1;
100 }
101
tkchinbad7b092016-03-11 20:45:16 -0800102 printf("Server listening on port %i\n", port);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000103
104 PeerChannel clients;
105 typedef std::vector<DataSocket*> SocketArray;
106 SocketArray sockets;
107 bool quit = false;
108 while (!quit) {
109 fd_set socket_set;
110 FD_ZERO(&socket_set);
111 if (listener.valid())
112 FD_SET(listener.socket(), &socket_set);
113
114 for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i)
115 FD_SET((*i)->socket(), &socket_set);
116
Yves Gerey665174f2018-06-19 15:03:05 +0200117 struct timeval timeout = {10, 0};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000118 if (select(FD_SETSIZE, &socket_set, NULL, NULL, &timeout) == SOCKET_ERROR) {
119 printf("select failed\n");
120 break;
121 }
122
123 for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i) {
124 DataSocket* s = *i;
125 bool socket_done = true;
126 if (FD_ISSET(s->socket(), &socket_set)) {
127 if (s->OnDataAvailable(&socket_done) && s->request_received()) {
128 ChannelMember* member = clients.Lookup(s);
129 if (member || PeerChannel::IsPeerConnection(s)) {
130 if (!member) {
131 if (s->PathEquals("/sign_in")) {
132 clients.AddMember(s);
133 } else {
Yves Gerey665174f2018-06-19 15:03:05 +0200134 printf("No member found for: %s\n", s->request_path().c_str());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000135 s->Send("500 Error", true, "text/plain", "",
136 "Peer most likely gone.");
137 }
138 } else if (member->is_wait_request(s)) {
139 // no need to do anything.
140 socket_done = false;
141 } else {
142 ChannelMember* target = clients.IsTargetedRequest(s);
143 if (target) {
144 member->ForwardRequestToPeer(s, target);
145 } else if (s->PathEquals("/sign_out")) {
146 s->Send("200 OK", true, "text/plain", "", "");
147 } else {
148 printf("Couldn't find target for request: %s\n",
Yves Gerey665174f2018-06-19 15:03:05 +0200149 s->request_path().c_str());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000150 s->Send("500 Error", true, "text/plain", "",
151 "Peer most likely gone.");
152 }
153 }
154 } else {
155 HandleBrowserRequest(s, &quit);
156 if (quit) {
157 printf("Quitting...\n");
158 FD_CLR(listener.socket(), &socket_set);
159 listener.Close();
160 clients.CloseAll();
161 }
162 }
163 }
164 } else {
165 socket_done = false;
166 }
167
168 if (socket_done) {
169 printf("Disconnecting socket\n");
170 clients.OnClosing(s);
171 assert(s->valid()); // Close must not have been called yet.
172 FD_CLR(s->socket(), &socket_set);
173 delete (*i);
174 i = sockets.erase(i);
175 if (i == sockets.end())
176 break;
177 }
178 }
179
180 clients.CheckForTimeout();
181
182 if (FD_ISSET(listener.socket(), &socket_set)) {
183 DataSocket* s = listener.Accept();
184 if (sockets.size() >= kMaxConnections) {
185 delete s; // sorry, that's all we can take.
186 printf("Connection limit reached\n");
187 } else {
188 sockets.push_back(s);
189 printf("New connection...\n");
190 }
191 }
192 }
193
194 for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i)
195 delete (*i);
196 sockets.clear();
197
198 return 0;
199}