Home | History | Annotate | Download | only in server
      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 
     22 DEFINE_bool(help, false, "Prints this message");
     23 DEFINE_int(port, 8888, "The port on which to listen.");
     24 
     25 static const size_t kMaxConnections = (FD_SETSIZE - 2);
     26 
     27 void 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 
     52 int 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