tcp_listen.h

Go to the documentation of this file.
00001 /* $Id: tcp_listen.h 26046 2013-11-22 21:41:19Z rubidium $ */
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           if (send(s, (const char*)p.buffer, p.size, 0) < 0) {
00068             DEBUG(net, 0, "send failed with error %d", GET_LAST_ERROR());
00069           }
00070           closesocket(s);
00071           break;
00072         }
00073       }
00074       /* If this client is banned, continue with next client */
00075       if (banned) continue;
00076 
00077       /* Can we handle a new client? */
00078       if (!Tsocket::AllowConnection()) {
00079         /* no more clients allowed?
00080          * Send to the client that we are full! */
00081         Packet p(Tfull_packet);
00082         p.PrepareToSend();
00083 
00084         if (send(s, (const char*)p.buffer, p.size, 0) < 0) {
00085           DEBUG(net, 0, "send failed with error %d", GET_LAST_ERROR());
00086         }
00087         closesocket(s);
00088 
00089         continue;
00090       }
00091 
00092       Tsocket::AcceptConnection(s, address);
00093     }
00094   }
00095 
00100   static bool Receive()
00101   {
00102     fd_set read_fd, write_fd;
00103     struct timeval tv;
00104 
00105     FD_ZERO(&read_fd);
00106     FD_ZERO(&write_fd);
00107 
00108 
00109     Tsocket *cs;
00110     FOR_ALL_ITEMS_FROM(Tsocket, idx, cs, 0) {
00111       FD_SET(cs->sock, &read_fd);
00112       FD_SET(cs->sock, &write_fd);
00113     }
00114 
00115     /* take care of listener port */
00116     for (SocketList::iterator s = sockets.Begin(); s != sockets.End(); s++) {
00117       FD_SET(s->second, &read_fd);
00118     }
00119 
00120     tv.tv_sec = tv.tv_usec = 0; // don't block at all.
00121 #if !defined(__MORPHOS__) && !defined(__AMIGA__)
00122     if (select(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv) < 0) return false;
00123 #else
00124     if (WaitSelect(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv, NULL) < 0) return false;
00125 #endif
00126 
00127     /* accept clients.. */
00128     for (SocketList::iterator s = sockets.Begin(); s != sockets.End(); s++) {
00129       if (FD_ISSET(s->second, &read_fd)) AcceptClient(s->second);
00130     }
00131 
00132     /* read stuff from clients */
00133     FOR_ALL_ITEMS_FROM(Tsocket, idx, cs, 0) {
00134       cs->writable = !!FD_ISSET(cs->sock, &write_fd);
00135       if (FD_ISSET(cs->sock, &read_fd)) {
00136         cs->ReceivePackets();
00137       }
00138     }
00139     return _networking;
00140   }
00141 
00147   static bool Listen(uint16 port)
00148   {
00149     assert(sockets.Length() == 0);
00150 
00151     NetworkAddressList addresses;
00152     GetBindAddresses(&addresses, port);
00153 
00154     for (NetworkAddress *address = addresses.Begin(); address != addresses.End(); address++) {
00155       address->Listen(SOCK_STREAM, &sockets);
00156     }
00157 
00158     if (sockets.Length() == 0) {
00159       DEBUG(net, 0, "[server] could not start network: could not create listening socket");
00160       NetworkError(STR_NETWORK_ERROR_SERVER_START);
00161       return false;
00162     }
00163 
00164     return true;
00165   }
00166 
00168   static void CloseListeners()
00169   {
00170     for (SocketList::iterator s = sockets.Begin(); s != sockets.End(); s++) {
00171       closesocket(s->second);
00172     }
00173     sockets.Clear();
00174     DEBUG(net, 1, "[%s] closed listeners", Tsocket::GetName());
00175   }
00176 };
00177 
00178 template <class Tsocket, PacketType Tfull_packet, PacketType Tban_packet> SocketList TCPListenHandler<Tsocket, Tfull_packet, Tban_packet>::sockets;
00179 
00180 #endif /* ENABLE_NETWORK */
00181 
00182 #endif /* NETWORK_CORE_TCP_LISTEN_H */