OpenTTD: src/network/core/tcp_listen.h Source File

OpenTTD

- Main Page
- Related Pages
- Modules
- Namespaces
- Data Structures
- Files

- File List
- Globals

tcp_listen.h
Go to the documentation of this file.
1 /* $Id: tcp_listen.h 26046 2013-11-22 21:41:19Z rubidium $ */
2
3 /*
4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
8 */
9
14 #ifndef NETWORK_CORE_TCP_LISTEN_H
15 #define NETWORK_CORE_TCP_LISTEN_H
16
17 #include "tcp.h"
18 #include "../network.h"
19 #include "../../core/pool_type.hpp"
20 #include "../../debug.h"
21 #include "table/strings.h"
22
23 #ifdef ENABLE_NETWORK
24
31 template <class Tsocket, PacketType Tfull_packet, PacketType Tban_packet>
32 class TCPListenHandler {
34 static SocketList sockets;
35
36 public:
41 static void AcceptClient(SOCKET ls)
42 {
43 for (;;) {
44 struct sockaddr_storage sin;
45 memset(&sin, 0, sizeof(sin));
46 socklen_t sin_len = sizeof(sin);
47 SOCKET s = accept(ls, (struct sockaddr*)&sin, &sin_len);
48 if (s == INVALID_SOCKET) return;
49
50 SetNonBlocking(s); // XXX error handling?
51
52 NetworkAddress address(sin, sin_len);
53 DEBUG(net, 1, "[%s] Client connected from %s on frame %d", Tsocket::GetName(), address.GetHostname(), _frame_counter);
54
55 SetNoDelay(s); // XXX error handling?
56
57 /* Check if the client is banned */
58 bool banned = false;
59 for (char **iter = _network_ban_list.Begin(); iter != _network_ban_list.End(); iter++) {
60 banned = address.IsInNetmask(*iter);
61 if (banned) {
62 Packet p(Tban_packet);
63 p.PrepareToSend();
64
65 DEBUG(net, 1, "[%s] Banned ip tried to join (%s), refused", Tsocket::GetName(), *iter);
66
67 if (send(s, (const char*)p.buffer, p.size, 0) < 0) {
68 DEBUG(net, 0, "send failed with error %d", GET_LAST_ERROR());
69 }
70 closesocket(s);
71 break;
72 }
73 }
74 /* If this client is banned, continue with next client */
75 if (banned) continue;
76
77 /* Can we handle a new client? */
78 if (!Tsocket::AllowConnection()) {
79 /* no more clients allowed?
80 * Send to the client that we are full! */
81 Packet p(Tfull_packet);
82 p.PrepareToSend();
83
84 if (send(s, (const char*)p.buffer, p.size, 0) < 0) {
85 DEBUG(net, 0, "send failed with error %d", GET_LAST_ERROR());
86 }
87 closesocket(s);
88
89 continue;
90 }
91
92 Tsocket::AcceptConnection(s, address);
93 }
94 }
95
100 static bool Receive()
101 {
102 fd_set read_fd, write_fd;
103 struct timeval tv;
104
105 FD_ZERO(&read_fd);
106 FD_ZERO(&write_fd);
107
108
109 Tsocket *cs;
110 FOR_ALL_ITEMS_FROM(Tsocket, idx, cs, 0) {
111 FD_SET(cs->sock, &read_fd);
112 FD_SET(cs->sock, &write_fd);
113 }
114
115 /* take care of listener port */
116 for (SocketList::iterator s = sockets.Begin(); s != sockets.End(); s++) {
117 FD_SET(s->second, &read_fd);
118 }
119
120 tv.tv_sec = tv.tv_usec = 0; // don't block at all.
121 #if !defined(__MORPHOS__) && !defined(__AMIGA__)
122 if (select(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv) < 0) return false;
123 #else
124 if (WaitSelect(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv, NULL) < 0) return false;
125 #endif
126
127 /* accept clients.. */
128 for (SocketList::iterator s = sockets.Begin(); s != sockets.End(); s++) {
129 if (FD_ISSET(s->second, &read_fd)) AcceptClient(s->second);
130 }
131
132 /* read stuff from clients */
133 FOR_ALL_ITEMS_FROM(Tsocket, idx, cs, 0) {
134 cs->writable = !!FD_ISSET(cs->sock, &write_fd);
135 if (FD_ISSET(cs->sock, &read_fd)) {
136 cs->ReceivePackets();
137 }
138 }
139 return _networking;
140 }
141
147 static bool Listen(uint16 port)
148 {
149 assert(sockets.Length() == 0);
150
151 NetworkAddressList addresses;
152 GetBindAddresses(&addresses, port);
153
154 for (NetworkAddress *address = addresses.Begin(); address != addresses.End(); address++) {
155 address->Listen(SOCK_STREAM, &sockets);
156 }
157
158 if (sockets.Length() == 0) {
159 DEBUG(net, 0, "[server] could not start network: could not create listening socket");
160 NetworkError(STR_NETWORK_ERROR_SERVER_START);
161 return false;
162 }
163
164 return true;
165 }
166
168 static void CloseListeners()
169 {
170 for (SocketList::iterator s = sockets.Begin(); s != sockets.End(); s++) {
171 closesocket(s->second);
172 }
173 sockets.Clear();
174 DEBUG(net, 1, "[%s] closed listeners", Tsocket::GetName());
175 }
176 };
177
178 template <class Tsocket, PacketType Tfull_packet, PacketType Tban_packet> SocketList TCPListenHandler<Tsocket, Tfull_packet, Tban_packet>::sockets;
179
180 #endif /* ENABLE_NETWORK */
181
182 #endif /* NETWORK_CORE_TCP_LISTEN_H */