tcp_listen.h

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00014 #ifndef NETWORK_CORE_TCP_LISTEN_H
00015 #define NETWORK_CORE_TCP_LISTEN_H
00016 
00017 #include "tcp.h"
00018 #include "../network.h"
00019 #include "../../core/pool_type.hpp"
00020 #include "../../debug.h"
00021 #include "table/strings.h"
00022 
00023 #ifdef ENABLE_NETWORK
00024 
00031 template <class Tsocket, PacketType Tfull_packet, PacketType Tban_packet>
00032 class TCPListenHandler {
00034   static SocketList sockets;
00035 
00036 public:
00041   static void AcceptClient(SOCKET ls)
00042   {
00043     for (;;) {
00044       struct sockaddr_storage sin;
00045       memset(&sin, 0, sizeof(sin));
00046       socklen_t sin_len = sizeof(sin);
00047       SOCKET s = accept(ls, (struct sockaddr*)&sin, &sin_len);
00048       if (s == INVALID_SOCKET) return;
00049 
00050       SetNonBlocking(s); // XXX error handling?
00051 
00052       NetworkAddress address(sin, sin_len);
00053       DEBUG(net, 1, "[%s] Client connected from %s on frame %d", Tsocket::GetName(), address.GetHostname(), _frame_counter);
00054 
00055       SetNoDelay(s); // XXX error handling?
00056 
00057       /* Check if the client is banned */
00058       bool banned = false;
00059       for (char **iter = _network_ban_list.Begin(); iter != _network_ban_list.End(); iter++) {
00060         banned = address.IsInNetmask(*iter);
00061         if (banned) {
00062           Packet p(Tban_packet);
00063           p.PrepareToSend();
00064 
00065           DEBUG(net, 1, "[%s] Banned ip tried to join (%s), refused", Tsocket::GetName(), *iter);
00066 
00067           send(s, (const char*)p.buffer, p.size, 0);
00068           closesocket(s);
00069           break;
00070         }
00071       }
00072       /* If this client is banned, continue with next client */
00073       if (banned) continue;
00074 
00075       /* Can we handle a new client? */
00076       if (!Tsocket::AllowConnection()) {
00077         /* no more clients allowed?
00078          * Send to the client that we are full! */
00079         Packet p(Tfull_packet);
00080         p.PrepareToSend();
00081 
00082         send(s, (const char*)p.buffer, p.size, 0);
00083         closesocket(s);
00084 
00085         continue;
00086       }
00087 
00088       Tsocket::AcceptConnection(s, address);
00089     }
00090   }
00091 
00096   static bool Receive()
00097   {
00098     fd_set read_fd, write_fd;
00099     struct timeval tv;
00100 
00101     FD_ZERO(&read_fd);
00102     FD_ZERO(&write_fd);
00103 
00104 
00105     Tsocket *cs;
00106     FOR_ALL_ITEMS_FROM(Tsocket, idx, cs, 0) {
00107       FD_SET(cs->sock, &read_fd);
00108       FD_SET(cs->sock, &write_fd);
00109     }
00110 
00111     /* take care of listener port */
00112     for (SocketList::iterator s = sockets.Begin(); s != sockets.End(); s++) {
00113       FD_SET(s->second, &read_fd);
00114     }
00115 
00116     tv.tv_sec = tv.tv_usec = 0; // don't block at all.
00117 #if !defined(__MORPHOS__) && !defined(__AMIGA__)
00118     select(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv);
00119 #else
00120     WaitSelect(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv, NULL);
00121 #endif
00122 
00123     /* accept clients.. */
00124     for (SocketList::iterator s = sockets.Begin(); s != sockets.End(); s++) {
00125       if (FD_ISSET(s->second, &read_fd)) AcceptClient(s->second);
00126     }
00127 
00128     /* read stuff from clients */
00129     FOR_ALL_ITEMS_FROM(Tsocket, idx, cs, 0) {
00130       cs->writable = !!FD_ISSET(cs->sock, &write_fd);
00131       if (FD_ISSET(cs->sock, &read_fd)) {
00132         cs->ReceivePackets();
00133       }
00134     }
00135     return _networking;
00136   }
00137 
00143   static bool Listen(uint16 port)
00144   {
00145     assert(sockets.Length() == 0);
00146 
00147     NetworkAddressList addresses;
00148     GetBindAddresses(&addresses, port);
00149 
00150     for (NetworkAddress *address = addresses.Begin(); address != addresses.End(); address++) {
00151       address->Listen(SOCK_STREAM, &sockets);
00152     }
00153 
00154     if (sockets.Length() == 0) {
00155       DEBUG(net, 0, "[server] could not start network: could not create listening socket");
00156       NetworkError(STR_NETWORK_ERROR_SERVER_START);
00157       return false;
00158     }
00159 
00160     return true;
00161   }
00162 
00164   static void CloseListeners()
00165   {
00166     for (SocketList::iterator s = sockets.Begin(); s != sockets.End(); s++) {
00167       closesocket(s->second);
00168     }
00169     sockets.Clear();
00170     DEBUG(net, 1, "[%s] closed listeners", Tsocket::GetName());
00171   }
00172 };
00173 
00174 template <class Tsocket, PacketType Tfull_packet, PacketType Tban_packet> SocketList TCPListenHandler<Tsocket, Tfull_packet, Tban_packet>::sockets;
00175 
00176 #endif /* ENABLE_NETWORK */
00177 
00178 #endif /* NETWORK_CORE_TCP_LISTEN_H */

Generated on Mon May 9 05:18:54 2011 for OpenTTD by  doxygen 1.6.1