 28e2075280
			
		
	
	28e2075280
	
	
	
		
			
			trunk/talk git-svn-id: http://webrtc.googlecode.com/svn/trunk@4318 4adac7df-926f-26a2-2b94-8c16560cd09d
		
			
				
	
	
		
			191 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			191 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * libjingle
 | |
|  * Copyright 2011, Google Inc.
 | |
|  *
 | |
|  * Redistribution and use in source and binary forms, with or without
 | |
|  * modification, are permitted provided that the following conditions are met:
 | |
|  *
 | |
|  *  1. Redistributions of source code must retain the above copyright notice,
 | |
|  *     this list of conditions and the following disclaimer.
 | |
|  *  2. Redistributions in binary form must reproduce the above copyright notice,
 | |
|  *     this list of conditions and the following disclaimer in the documentation
 | |
|  *     and/or other materials provided with the distribution.
 | |
|  *  3. The name of the author may not be used to endorse or promote products
 | |
|  *     derived from this software without specific prior written permission.
 | |
|  *
 | |
|  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 | |
|  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | |
|  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 | |
|  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | |
|  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 | |
|  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 | |
|  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | |
|  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 | |
|  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 | |
|  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| 
 | |
| #include <vector>
 | |
| 
 | |
| #include "talk/base/flags.h"
 | |
| #include "talk/examples/peerconnection/server/data_socket.h"
 | |
| #include "talk/examples/peerconnection/server/peer_channel.h"
 | |
| #include "talk/examples/peerconnection/server/utils.h"
 | |
| 
 | |
| DEFINE_bool(help, false, "Prints this message");
 | |
| DEFINE_int(port, 8888, "The port on which to listen.");
 | |
| 
 | |
| static const size_t kMaxConnections = (FD_SETSIZE - 2);
 | |
| 
 | |
| void HandleBrowserRequest(DataSocket* ds, bool* quit) {
 | |
|   assert(ds && ds->valid());
 | |
|   assert(quit);
 | |
| 
 | |
|   const std::string& path = ds->request_path();
 | |
| 
 | |
|   *quit = (path.compare("/quit") == 0);
 | |
| 
 | |
|   if (*quit) {
 | |
|     ds->Send("200 OK", true, "text/html", "",
 | |
|              "<html><body>Quitting...</body></html>");
 | |
|   } else if (ds->method() == DataSocket::OPTIONS) {
 | |
|     // We'll get this when a browsers do cross-resource-sharing requests.
 | |
|     // The headers to allow cross-origin script support will be set inside
 | |
|     // Send.
 | |
|     ds->Send("200 OK", true, "", "", "");
 | |
|   } else {
 | |
|     // Here we could write some useful output back to the browser depending on
 | |
|     // the path.
 | |
|     printf("Received an invalid request: %s\n", ds->request_path().c_str());
 | |
|     ds->Send("500 Sorry", true, "text/html", "",
 | |
|              "<html><body>Sorry, not yet implemented</body></html>");
 | |
|   }
 | |
| }
 | |
| 
 | |
| int main(int argc, char** argv) {
 | |
|   FlagList::SetFlagsFromCommandLine(&argc, argv, true);
 | |
|   if (FLAG_help) {
 | |
|     FlagList::Print(NULL, false);
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   // Abort if the user specifies a port that is outside the allowed
 | |
|   // range [1, 65535].
 | |
|   if ((FLAG_port < 1) || (FLAG_port > 65535)) {
 | |
|     printf("Error: %i is not a valid port.\n", FLAG_port);
 | |
|     return -1;
 | |
|   }
 | |
| 
 | |
|   ListeningSocket listener;
 | |
|   if (!listener.Create()) {
 | |
|     printf("Failed to create server socket\n");
 | |
|     return -1;
 | |
|   } else if (!listener.Listen(FLAG_port)) {
 | |
|     printf("Failed to listen on server socket\n");
 | |
|     return -1;
 | |
|   }
 | |
| 
 | |
|   printf("Server listening on port %i\n", FLAG_port);
 | |
| 
 | |
|   PeerChannel clients;
 | |
|   typedef std::vector<DataSocket*> SocketArray;
 | |
|   SocketArray sockets;
 | |
|   bool quit = false;
 | |
|   while (!quit) {
 | |
|     fd_set socket_set;
 | |
|     FD_ZERO(&socket_set);
 | |
|     if (listener.valid())
 | |
|       FD_SET(listener.socket(), &socket_set);
 | |
| 
 | |
|     for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i)
 | |
|       FD_SET((*i)->socket(), &socket_set);
 | |
| 
 | |
|     struct timeval timeout = { 10, 0 };
 | |
|     if (select(FD_SETSIZE, &socket_set, NULL, NULL, &timeout) == SOCKET_ERROR) {
 | |
|       printf("select failed\n");
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i) {
 | |
|       DataSocket* s = *i;
 | |
|       bool socket_done = true;
 | |
|       if (FD_ISSET(s->socket(), &socket_set)) {
 | |
|         if (s->OnDataAvailable(&socket_done) && s->request_received()) {
 | |
|           ChannelMember* member = clients.Lookup(s);
 | |
|           if (member || PeerChannel::IsPeerConnection(s)) {
 | |
|             if (!member) {
 | |
|               if (s->PathEquals("/sign_in")) {
 | |
|                 clients.AddMember(s);
 | |
|               } else {
 | |
|                 printf("No member found for: %s\n",
 | |
|                     s->request_path().c_str());
 | |
|                 s->Send("500 Error", true, "text/plain", "",
 | |
|                         "Peer most likely gone.");
 | |
|               }
 | |
|             } else if (member->is_wait_request(s)) {
 | |
|               // no need to do anything.
 | |
|               socket_done = false;
 | |
|             } else {
 | |
|               ChannelMember* target = clients.IsTargetedRequest(s);
 | |
|               if (target) {
 | |
|                 member->ForwardRequestToPeer(s, target);
 | |
|               } else if (s->PathEquals("/sign_out")) {
 | |
|                 s->Send("200 OK", true, "text/plain", "", "");
 | |
|               } else {
 | |
|                 printf("Couldn't find target for request: %s\n",
 | |
|                     s->request_path().c_str());
 | |
|                 s->Send("500 Error", true, "text/plain", "",
 | |
|                         "Peer most likely gone.");
 | |
|               }
 | |
|             }
 | |
|           } else {
 | |
|             HandleBrowserRequest(s, &quit);
 | |
|             if (quit) {
 | |
|               printf("Quitting...\n");
 | |
|               FD_CLR(listener.socket(), &socket_set);
 | |
|               listener.Close();
 | |
|               clients.CloseAll();
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       } else {
 | |
|         socket_done = false;
 | |
|       }
 | |
| 
 | |
|       if (socket_done) {
 | |
|         printf("Disconnecting socket\n");
 | |
|         clients.OnClosing(s);
 | |
|         assert(s->valid());  // Close must not have been called yet.
 | |
|         FD_CLR(s->socket(), &socket_set);
 | |
|         delete (*i);
 | |
|         i = sockets.erase(i);
 | |
|         if (i == sockets.end())
 | |
|           break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     clients.CheckForTimeout();
 | |
| 
 | |
|     if (FD_ISSET(listener.socket(), &socket_set)) {
 | |
|       DataSocket* s = listener.Accept();
 | |
|       if (sockets.size() >= kMaxConnections) {
 | |
|         delete s;  // sorry, that's all we can take.
 | |
|         printf("Connection limit reached\n");
 | |
|       } else {
 | |
|         sockets.push_back(s);
 | |
|         printf("New connection...\n");
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i)
 | |
|     delete (*i);
 | |
|   sockets.clear();
 | |
| 
 | |
|   return 0;
 | |
| }
 |