webrtc/talk/examples/peerconnection/server/main.cc

191 lines
6.5 KiB
C++
Raw Normal View History

/*
* 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/examples/peerconnection/server/data_socket.h"
#include "talk/examples/peerconnection/server/peer_channel.h"
#include "talk/examples/peerconnection/server/utils.h"
#include "webrtc/base/flags.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) {
rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
if (FLAG_help) {
rtc::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;
}