128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org/*
2a8736448970fedd82f051c6b2cc89185b755ddf3Donald E Curtis *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org *
4a8736448970fedd82f051c6b2cc89185b755ddf3Donald E Curtis *  Use of this source code is governed by a BSD-style license
5a8736448970fedd82f051c6b2cc89185b755ddf3Donald E Curtis *  that can be found in the LICENSE file in the root of the source
6a8736448970fedd82f051c6b2cc89185b755ddf3Donald E Curtis *  tree. An additional intellectual property rights grant can be found
7a8736448970fedd82f051c6b2cc89185b755ddf3Donald E Curtis *  in the file PATENTS.  All contributing project authors may
8a8736448970fedd82f051c6b2cc89185b755ddf3Donald E Curtis *  be found in the AUTHORS file in the root of the source tree.
928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org */
1028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
1128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#include <stdio.h>
1228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#include <stdlib.h>
1328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#include <string.h>
1428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
1528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#include <vector>
1628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
17a8736448970fedd82f051c6b2cc89185b755ddf3Donald E Curtis#include "webrtc/examples/peerconnection/server/data_socket.h"
18a8736448970fedd82f051c6b2cc89185b755ddf3Donald E Curtis#include "webrtc/examples/peerconnection/server/peer_channel.h"
19a8736448970fedd82f051c6b2cc89185b755ddf3Donald E Curtis#include "webrtc/examples/peerconnection/server/utils.h"
20a09a99950ec40aef6421e4ba35eee7196b7a6e68buildbot@webrtc.org#include "webrtc/base/flags.h"
2128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
2228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgDEFINE_bool(help, false, "Prints this message");
2328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgDEFINE_int(port, 8888, "The port on which to listen.");
2428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
2528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgstatic const size_t kMaxConnections = (FD_SETSIZE - 2);
2628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
2728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgvoid HandleBrowserRequest(DataSocket* ds, bool* quit) {
2828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  assert(ds && ds->valid());
2928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  assert(quit);
3028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
3128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  const std::string& path = ds->request_path();
3228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
3328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  *quit = (path.compare("/quit") == 0);
3428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
3528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (*quit) {
3628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    ds->Send("200 OK", true, "text/html", "",
3728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org             "<html><body>Quitting...</body></html>");
3828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  } else if (ds->method() == DataSocket::OPTIONS) {
3928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // We'll get this when a browsers do cross-resource-sharing requests.
4028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // The headers to allow cross-origin script support will be set inside
4128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // Send.
4228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    ds->Send("200 OK", true, "", "", "");
4328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  } else {
4428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // Here we could write some useful output back to the browser depending on
4528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // the path.
4628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    printf("Received an invalid request: %s\n", ds->request_path().c_str());
4728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    ds->Send("500 Sorry", true, "text/html", "",
4828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org             "<html><body>Sorry, not yet implemented</body></html>");
4928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
5028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
5128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
5228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgint main(int argc, char** argv) {
53d4e598d57aed714a599444a7eab5e8fdde52a950buildbot@webrtc.org  rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
5428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (FLAG_help) {
55d4e598d57aed714a599444a7eab5e8fdde52a950buildbot@webrtc.org    rtc::FlagList::Print(NULL, false);
5628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return 0;
5728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
5828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
5928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // Abort if the user specifies a port that is outside the allowed
6028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // range [1, 65535].
6128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if ((FLAG_port < 1) || (FLAG_port > 65535)) {
6228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    printf("Error: %i is not a valid port.\n", FLAG_port);
6328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return -1;
6428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
6528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
6628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  ListeningSocket listener;
6728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (!listener.Create()) {
6828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    printf("Failed to create server socket\n");
6928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return -1;
7028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  } else if (!listener.Listen(FLAG_port)) {
7128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    printf("Failed to listen on server socket\n");
7228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return -1;
7328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
7428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
7528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  printf("Server listening on port %i\n", FLAG_port);
7628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
7728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  PeerChannel clients;
7828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  typedef std::vector<DataSocket*> SocketArray;
7928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  SocketArray sockets;
8028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  bool quit = false;
8128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  while (!quit) {
8228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    fd_set socket_set;
8328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    FD_ZERO(&socket_set);
8428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    if (listener.valid())
8528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      FD_SET(listener.socket(), &socket_set);
8628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
8728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i)
8828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      FD_SET((*i)->socket(), &socket_set);
8928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
9028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    struct timeval timeout = { 10, 0 };
9128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    if (select(FD_SETSIZE, &socket_set, NULL, NULL, &timeout) == SOCKET_ERROR) {
9228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      printf("select failed\n");
9328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      break;
9428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    }
9528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
9628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i) {
9728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      DataSocket* s = *i;
9828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      bool socket_done = true;
9928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      if (FD_ISSET(s->socket(), &socket_set)) {
10028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org        if (s->OnDataAvailable(&socket_done) && s->request_received()) {
10128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org          ChannelMember* member = clients.Lookup(s);
10228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org          if (member || PeerChannel::IsPeerConnection(s)) {
10328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org            if (!member) {
10428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org              if (s->PathEquals("/sign_in")) {
10528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                clients.AddMember(s);
10628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org              } else {
10728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                printf("No member found for: %s\n",
10828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                    s->request_path().c_str());
10928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                s->Send("500 Error", true, "text/plain", "",
11028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                        "Peer most likely gone.");
11128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org              }
11228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org            } else if (member->is_wait_request(s)) {
11328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org              // no need to do anything.
11428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org              socket_done = false;
11528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org            } else {
11628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org              ChannelMember* target = clients.IsTargetedRequest(s);
11728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org              if (target) {
11828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                member->ForwardRequestToPeer(s, target);
11928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org              } else if (s->PathEquals("/sign_out")) {
12028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                s->Send("200 OK", true, "text/plain", "", "");
12128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org              } else {
12228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                printf("Couldn't find target for request: %s\n",
12328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                    s->request_path().c_str());
12428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                s->Send("500 Error", true, "text/plain", "",
12528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                        "Peer most likely gone.");
12628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org              }
12728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org            }
12828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org          } else {
12928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org            HandleBrowserRequest(s, &quit);
13028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org            if (quit) {
13128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org              printf("Quitting...\n");
13228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org              FD_CLR(listener.socket(), &socket_set);
13328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org              listener.Close();
13428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org              clients.CloseAll();
13528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org            }
13628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org          }
13728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org        }
13828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      } else {
13928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org        socket_done = false;
14028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      }
14128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
14228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      if (socket_done) {
14328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org        printf("Disconnecting socket\n");
14428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org        clients.OnClosing(s);
14528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org        assert(s->valid());  // Close must not have been called yet.
14628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org        FD_CLR(s->socket(), &socket_set);
14728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org        delete (*i);
14828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org        i = sockets.erase(i);
14928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org        if (i == sockets.end())
15028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org          break;
15128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      }
15228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    }
15328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
15428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    clients.CheckForTimeout();
15528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
15628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    if (FD_ISSET(listener.socket(), &socket_set)) {
15728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      DataSocket* s = listener.Accept();
15828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      if (sockets.size() >= kMaxConnections) {
15928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org        delete s;  // sorry, that's all we can take.
16028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org        printf("Connection limit reached\n");
16128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      } else {
16228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org        sockets.push_back(s);
16328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org        printf("New connection...\n");
16428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      }
16528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    }
16628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
16728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
16828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i)
16928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    delete (*i);
17028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  sockets.clear();
17128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
17228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  return 0;
17328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
174