Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / libjingle / source / talk / examples / peerconnection / server / main.cc
1 /*
2  * libjingle
3  * Copyright 2011, Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include <vector>
33
34 #include "talk/examples/peerconnection/server/data_socket.h"
35 #include "talk/examples/peerconnection/server/peer_channel.h"
36 #include "talk/examples/peerconnection/server/utils.h"
37 #include "webrtc/base/flags.h"
38
39 DEFINE_bool(help, false, "Prints this message");
40 DEFINE_int(port, 8888, "The port on which to listen.");
41
42 static const size_t kMaxConnections = (FD_SETSIZE - 2);
43
44 void HandleBrowserRequest(DataSocket* ds, bool* quit) {
45   assert(ds && ds->valid());
46   assert(quit);
47
48   const std::string& path = ds->request_path();
49
50   *quit = (path.compare("/quit") == 0);
51
52   if (*quit) {
53     ds->Send("200 OK", true, "text/html", "",
54              "<html><body>Quitting...</body></html>");
55   } else if (ds->method() == DataSocket::OPTIONS) {
56     // We'll get this when a browsers do cross-resource-sharing requests.
57     // The headers to allow cross-origin script support will be set inside
58     // Send.
59     ds->Send("200 OK", true, "", "", "");
60   } else {
61     // Here we could write some useful output back to the browser depending on
62     // the path.
63     printf("Received an invalid request: %s\n", ds->request_path().c_str());
64     ds->Send("500 Sorry", true, "text/html", "",
65              "<html><body>Sorry, not yet implemented</body></html>");
66   }
67 }
68
69 int main(int argc, char** argv) {
70   rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
71   if (FLAG_help) {
72     rtc::FlagList::Print(NULL, false);
73     return 0;
74   }
75
76   // Abort if the user specifies a port that is outside the allowed
77   // range [1, 65535].
78   if ((FLAG_port < 1) || (FLAG_port > 65535)) {
79     printf("Error: %i is not a valid port.\n", FLAG_port);
80     return -1;
81   }
82
83   ListeningSocket listener;
84   if (!listener.Create()) {
85     printf("Failed to create server socket\n");
86     return -1;
87   } else if (!listener.Listen(FLAG_port)) {
88     printf("Failed to listen on server socket\n");
89     return -1;
90   }
91
92   printf("Server listening on port %i\n", FLAG_port);
93
94   PeerChannel clients;
95   typedef std::vector<DataSocket*> SocketArray;
96   SocketArray sockets;
97   bool quit = false;
98   while (!quit) {
99     fd_set socket_set;
100     FD_ZERO(&socket_set);
101     if (listener.valid())
102       FD_SET(listener.socket(), &socket_set);
103
104     for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i)
105       FD_SET((*i)->socket(), &socket_set);
106
107     struct timeval timeout = { 10, 0 };
108     if (select(FD_SETSIZE, &socket_set, NULL, NULL, &timeout) == SOCKET_ERROR) {
109       printf("select failed\n");
110       break;
111     }
112
113     for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i) {
114       DataSocket* s = *i;
115       bool socket_done = true;
116       if (FD_ISSET(s->socket(), &socket_set)) {
117         if (s->OnDataAvailable(&socket_done) && s->request_received()) {
118           ChannelMember* member = clients.Lookup(s);
119           if (member || PeerChannel::IsPeerConnection(s)) {
120             if (!member) {
121               if (s->PathEquals("/sign_in")) {
122                 clients.AddMember(s);
123               } else {
124                 printf("No member found for: %s\n",
125                     s->request_path().c_str());
126                 s->Send("500 Error", true, "text/plain", "",
127                         "Peer most likely gone.");
128               }
129             } else if (member->is_wait_request(s)) {
130               // no need to do anything.
131               socket_done = false;
132             } else {
133               ChannelMember* target = clients.IsTargetedRequest(s);
134               if (target) {
135                 member->ForwardRequestToPeer(s, target);
136               } else if (s->PathEquals("/sign_out")) {
137                 s->Send("200 OK", true, "text/plain", "", "");
138               } else {
139                 printf("Couldn't find target for request: %s\n",
140                     s->request_path().c_str());
141                 s->Send("500 Error", true, "text/plain", "",
142                         "Peer most likely gone.");
143               }
144             }
145           } else {
146             HandleBrowserRequest(s, &quit);
147             if (quit) {
148               printf("Quitting...\n");
149               FD_CLR(listener.socket(), &socket_set);
150               listener.Close();
151               clients.CloseAll();
152             }
153           }
154         }
155       } else {
156         socket_done = false;
157       }
158
159       if (socket_done) {
160         printf("Disconnecting socket\n");
161         clients.OnClosing(s);
162         assert(s->valid());  // Close must not have been called yet.
163         FD_CLR(s->socket(), &socket_set);
164         delete (*i);
165         i = sockets.erase(i);
166         if (i == sockets.end())
167           break;
168       }
169     }
170
171     clients.CheckForTimeout();
172
173     if (FD_ISSET(listener.socket(), &socket_set)) {
174       DataSocket* s = listener.Accept();
175       if (sockets.size() >= kMaxConnections) {
176         delete s;  // sorry, that's all we can take.
177         printf("Connection limit reached\n");
178       } else {
179         sockets.push_back(s);
180         printf("New connection...\n");
181       }
182     }
183   }
184
185   for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i)
186     delete (*i);
187   sockets.clear();
188
189   return 0;
190 }