# tcp_listen.h

Go to the documentation of this file.

    00001 /* $Id: tcp_listen.h 21875 2011-01-21 01:38:30Z smatz $ */
    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 */