161 lines
5.0 KiB
C++
161 lines
5.0 KiB
C++
/*
|
|
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <vector>
|
|
|
|
#include "peerconnection/samples/server/data_socket.h"
|
|
#include "peerconnection/samples/server/peer_channel.h"
|
|
#include "peerconnection/samples/server/utils.h"
|
|
|
|
static const int 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) {
|
|
// TODO(tommi): make configurable.
|
|
static const unsigned short port = 8888;
|
|
|
|
ListeningSocket listener;
|
|
if (!listener.Create()) {
|
|
printf("Failed to create server socket\n");
|
|
return -1;
|
|
} else if (!listener.Listen(port)) {
|
|
printf("Failed to listen on server socket\n");
|
|
return -1;
|
|
}
|
|
|
|
printf("Server listening on port %i\n", 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_waiting_socket(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;
|
|
}
|