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