main.cc revision a8736448970fedd82f051c6b2cc89185b755ddf3
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#include <string.h>
14
15#include <vector>
16
17#include "webrtc/examples/peerconnection/server/data_socket.h"
18#include "webrtc/examples/peerconnection/server/peer_channel.h"
19#include "webrtc/examples/peerconnection/server/utils.h"
20#include "webrtc/base/flags.h"
21
22DEFINE_bool(help, false, "Prints this message");
23DEFINE_int(port, 8888, "The port on which to listen.");
24
25static const size_t kMaxConnections = (FD_SETSIZE - 2);
26
27void HandleBrowserRequest(DataSocket* ds, bool* quit) {
28  assert(ds && ds->valid());
29  assert(quit);
30
31  const std::string& path = ds->request_path();
32
33  *quit = (path.compare("/quit") == 0);
34
35  if (*quit) {
36    ds->Send("200 OK", true, "text/html", "",
37             "<html><body>Quitting...</body></html>");
38  } else if (ds->method() == DataSocket::OPTIONS) {
39    // We'll get this when a browsers do cross-resource-sharing requests.
40    // The headers to allow cross-origin script support will be set inside
41    // Send.
42    ds->Send("200 OK", true, "", "", "");
43  } else {
44    // Here we could write some useful output back to the browser depending on
45    // the path.
46    printf("Received an invalid request: %s\n", ds->request_path().c_str());
47    ds->Send("500 Sorry", true, "text/html", "",
48             "<html><body>Sorry, not yet implemented</body></html>");
49  }
50}
51
52int main(int argc, char** argv) {
53  rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
54  if (FLAG_help) {
55    rtc::FlagList::Print(NULL, false);
56    return 0;
57  }
58
59  // Abort if the user specifies a port that is outside the allowed
60  // range [1, 65535].
61  if ((FLAG_port < 1) || (FLAG_port > 65535)) {
62    printf("Error: %i is not a valid port.\n", FLAG_port);
63    return -1;
64  }
65
66  ListeningSocket listener;
67  if (!listener.Create()) {
68    printf("Failed to create server socket\n");
69    return -1;
70  } else if (!listener.Listen(FLAG_port)) {
71    printf("Failed to listen on server socket\n");
72    return -1;
73  }
74
75  printf("Server listening on port %i\n", FLAG_port);
76
77  PeerChannel clients;
78  typedef std::vector<DataSocket*> SocketArray;
79  SocketArray sockets;
80  bool quit = false;
81  while (!quit) {
82    fd_set socket_set;
83    FD_ZERO(&socket_set);
84    if (listener.valid())
85      FD_SET(listener.socket(), &socket_set);
86
87    for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i)
88      FD_SET((*i)->socket(), &socket_set);
89
90    struct timeval timeout = { 10, 0 };
91    if (select(FD_SETSIZE, &socket_set, NULL, NULL, &timeout) == SOCKET_ERROR) {
92      printf("select failed\n");
93      break;
94    }
95
96    for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i) {
97      DataSocket* s = *i;
98      bool socket_done = true;
99      if (FD_ISSET(s->socket(), &socket_set)) {
100        if (s->OnDataAvailable(&socket_done) && s->request_received()) {
101          ChannelMember* member = clients.Lookup(s);
102          if (member || PeerChannel::IsPeerConnection(s)) {
103            if (!member) {
104              if (s->PathEquals("/sign_in")) {
105                clients.AddMember(s);
106              } else {
107                printf("No member found for: %s\n",
108                    s->request_path().c_str());
109                s->Send("500 Error", true, "text/plain", "",
110                        "Peer most likely gone.");
111              }
112            } else if (member->is_wait_request(s)) {
113              // no need to do anything.
114              socket_done = false;
115            } else {
116              ChannelMember* target = clients.IsTargetedRequest(s);
117              if (target) {
118                member->ForwardRequestToPeer(s, target);
119              } else if (s->PathEquals("/sign_out")) {
120                s->Send("200 OK", true, "text/plain", "", "");
121              } else {
122                printf("Couldn't find target for request: %s\n",
123                    s->request_path().c_str());
124                s->Send("500 Error", true, "text/plain", "",
125                        "Peer most likely gone.");
126              }
127            }
128          } else {
129            HandleBrowserRequest(s, &quit);
130            if (quit) {
131              printf("Quitting...\n");
132              FD_CLR(listener.socket(), &socket_set);
133              listener.Close();
134              clients.CloseAll();
135            }
136          }
137        }
138      } else {
139        socket_done = false;
140      }
141
142      if (socket_done) {
143        printf("Disconnecting socket\n");
144        clients.OnClosing(s);
145        assert(s->valid());  // Close must not have been called yet.
146        FD_CLR(s->socket(), &socket_set);
147        delete (*i);
148        i = sockets.erase(i);
149        if (i == sockets.end())
150          break;
151      }
152    }
153
154    clients.CheckForTimeout();
155
156    if (FD_ISSET(listener.socket(), &socket_set)) {
157      DataSocket* s = listener.Accept();
158      if (sockets.size() >= kMaxConnections) {
159        delete s;  // sorry, that's all we can take.
160        printf("Connection limit reached\n");
161      } else {
162        sockets.push_back(s);
163        printf("New connection...\n");
164      }
165    }
166  }
167
168  for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i)
169    delete (*i);
170  sockets.clear();
171
172  return 0;
173}
174