switched from PracticalSocket to libasio
[anytun.git] / src / Sockets / ListenSocket.h
blobd782fc526882bc616133ac76725aaedde62144ae
1 /** \file ListenSocket.h
2 ** \date 2004-02-13
3 ** \author grymse@alhem.net
4 **/
5 /*
6 Copyright (C) 2004-2007 Anders Hedstrom
8 This library is made available under the terms of the GNU GPL.
10 If you would like to use this library in a closed-source application,
11 a separate license agreement is available. For information about
12 the closed-source license agreement for the C++ sockets library,
13 please visit http://www.alhem.net/Sockets/license.html and/or
14 email license@alhem.net.
16 This program is free software; you can redistribute it and/or
17 modify it under the terms of the GNU General Public License
18 as published by the Free Software Foundation; either version 2
19 of the License, or (at your option) any later version.
21 This program is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #ifndef _SOCKETS_ListenSocket_H
31 #define _SOCKETS_ListenSocket_H
32 #include "sockets-config.h"
34 #ifdef _WIN32
35 #include <stdlib.h>
36 #else
37 #include <errno.h>
38 #endif
40 #include <cstring>
41 #include "ISocketHandler.h"
42 #include "Socket.h"
43 #include "Utility.h"
44 #include "SctpSocket.h"
45 #include "Ipv4Address.h"
46 #include "Ipv6Address.h"
47 #ifdef ENABLE_EXCEPTIONS
48 #include "Exception.h"
49 #endif
51 #ifdef SOCKETS_NAMESPACE
52 namespace SOCKETS_NAMESPACE {
53 #endif
56 /** Binds incoming port number to new Socket class X.
57 \ingroup basic */
58 template <class X>
59 class ListenSocket : public Socket
61 public:
62 /** Constructor.
63 \param h ISocketHandler reference
64 \param use_creator Optional use of creator (default true) */
65 ListenSocket(ISocketHandler& h,bool use_creator = true) : Socket(h), m_depth(0), m_creator(NULL)
66 ,m_bHasCreate(false)
68 if (use_creator)
70 m_creator = new X(h);
71 Socket *tmp = m_creator -> Create();
72 if (tmp && dynamic_cast<X *>(tmp))
74 m_bHasCreate = true;
76 if (tmp)
78 delete tmp;
82 ~ListenSocket() {
83 if (m_creator)
85 delete m_creator;
89 /** Close file descriptor. */
90 int Close() {
91 if (GetSocket() != INVALID_SOCKET)
93 closesocket(GetSocket());
95 return 0;
98 /** Bind and listen to any interface.
99 \param port Port (0 is random)
100 \param depth Listen queue depth */
101 int Bind(port_t port,int depth = 20) {
102 #ifdef ENABLE_IPV6
103 #ifdef IPPROTO_IPV6
104 if (IsIpv6())
106 Ipv6Address ad(port);
107 return Bind(ad, depth);
109 else
110 #endif
111 #endif
113 Ipv4Address ad(port);
114 return Bind(ad, depth);
118 int Bind(SocketAddress& ad,int depth) {
119 #ifdef USE_SCTP
120 if (dynamic_cast<SctpSocket *>(m_creator))
122 return Bind(ad, "sctp", depth);
124 #endif
125 return Bind(ad, "tcp", depth);
128 /** Bind and listen to any interface, with optional protocol.
129 \param port Port (0 is random)
130 \param protocol Network protocol
131 \param depth Listen queue depth */
132 int Bind(port_t port,const std::string& protocol,int depth = 20) {
133 #ifdef ENABLE_IPV6
134 #ifdef IPPROTO_IPV6
135 if (IsIpv6())
137 Ipv6Address ad(port);
138 return Bind(ad, protocol, depth);
140 else
141 #endif
142 #endif
144 Ipv4Address ad(port);
145 return Bind(ad, protocol, depth);
149 /** Bind and listen to specific interface.
150 \param intf Interface hostname
151 \param port Port (0 is random)
152 \param depth Listen queue depth */
153 int Bind(const std::string& intf,port_t port,int depth = 20) {
154 #ifdef ENABLE_IPV6
155 #ifdef IPPROTO_IPV6
156 if (IsIpv6())
158 Ipv6Address ad(intf, port);
159 if (ad.IsValid())
161 return Bind(ad, depth);
163 Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL);
164 return -1;
166 else
167 #endif
168 #endif
170 Ipv4Address ad(intf, port);
171 if (ad.IsValid())
173 return Bind(ad, depth);
175 Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL);
176 return -1;
180 /** Bind and listen to specific interface.
181 \param intf Interface hostname
182 \param port Port (0 is random)
183 \param protocol Network protocol
184 \param depth Listen queue depth */
185 int Bind(const std::string& intf,port_t port,const std::string& protocol,int depth = 20) {
186 #ifdef ENABLE_IPV6
187 #ifdef IPPROTO_IPV6
188 if (IsIpv6())
190 Ipv6Address ad(intf, port);
191 if (ad.IsValid())
193 return Bind(ad, protocol, depth);
195 Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL);
196 return -1;
198 else
199 #endif
200 #endif
202 Ipv4Address ad(intf, port);
203 if (ad.IsValid())
205 return Bind(ad, protocol, depth);
207 Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL);
208 return -1;
212 /** Bind and listen to ipv4 interface.
213 \param a Ipv4 interface address
214 \param port Port (0 is random)
215 \param depth Listen queue depth */
216 int Bind(ipaddr_t a,port_t port,int depth = 20) {
217 Ipv4Address ad(a, port);
218 #ifdef USE_SCTP
219 if (dynamic_cast<SctpSocket *>(m_creator))
221 return Bind(ad, "sctp", depth);
223 #endif
224 return Bind(ad, "tcp", depth);
226 /** Bind and listen to ipv4 interface.
227 \param a Ipv4 interface address
228 \param port Port (0 is random)
229 \param protocol Network protocol
230 \param depth Listen queue depth */
231 int Bind(ipaddr_t a,port_t port,const std::string& protocol,int depth) {
232 Ipv4Address ad(a, port);
233 return Bind(ad, protocol, depth);
236 #ifdef ENABLE_IPV6
237 #ifdef IPPROTO_IPV6
238 /** Bind and listen to ipv6 interface.
239 \param a Ipv6 interface address
240 \param port Port (0 is random)
241 \param depth Listen queue depth */
242 int Bind(in6_addr a,port_t port,int depth = 20) {
243 Ipv6Address ad(a, port);
244 #ifdef USE_SCTP
245 if (dynamic_cast<SctpSocket *>(m_creator))
247 return Bind(ad, "sctp", depth);
249 #endif
250 return Bind(ad, "tcp", depth);
252 /** Bind and listen to ipv6 interface.
253 \param a Ipv6 interface address
254 \param port Port (0 is random)
255 \param protocol Network protocol
256 \param depth Listen queue depth */
257 int Bind(in6_addr a,port_t port,const std::string& protocol,int depth) {
258 Ipv6Address ad(a, port);
259 return Bind(ad, protocol, depth);
261 #endif
262 #endif
264 /** Bind and listen to network interface.
265 \param ad Interface address
266 \param protocol Network protocol
267 \param depth Listen queue depth */
268 int Bind(SocketAddress& ad,const std::string& protocol,int depth) {
269 SOCKET s;
270 if ( (s = CreateSocket(ad.GetFamily(), SOCK_STREAM, protocol)) == INVALID_SOCKET)
272 return -1;
274 if (bind(s, ad, ad) == -1)
276 Handler().LogError(this, "bind", Errno, StrError(Errno), LOG_LEVEL_FATAL);
277 closesocket(s);
278 #ifdef ENABLE_EXCEPTIONS
279 throw Exception("bind() failed for port " + Utility::l2string(ad.GetPort()) + ": " + StrError(Errno));
280 #endif
281 return -1;
283 if (listen(s, depth) == -1)
285 Handler().LogError(this, "listen", Errno, StrError(Errno), LOG_LEVEL_FATAL);
286 closesocket(s);
287 #ifdef ENABLE_EXCEPTIONS
288 throw Exception("listen() failed for port " + Utility::l2string(ad.GetPort()) + ": " + StrError(Errno));
289 #endif
290 return -1;
292 m_depth = depth;
293 Attach(s);
294 return 0;
297 /** Return assigned port number. */
298 port_t GetPort()
300 return GetSockPort();
303 /** Return listen queue depth. */
304 int GetDepth()
306 return m_depth;
309 /** OnRead on a ListenSocket receives an incoming connection. */
310 void OnRead()
312 struct sockaddr sa;
313 socklen_t sa_len = sizeof(struct sockaddr);
314 SOCKET a_s = accept(GetSocket(), &sa, &sa_len);
316 if (a_s == INVALID_SOCKET)
318 Handler().LogError(this, "accept", Errno, StrError(Errno), LOG_LEVEL_ERROR);
319 return;
321 if (!Handler().OkToAccept(this))
323 Handler().LogError(this, "accept", -1, "Not OK to accept", LOG_LEVEL_WARNING);
324 closesocket(a_s);
325 return;
327 if (Handler().GetCount() >= FD_SETSIZE)
329 Handler().LogError(this, "accept", (int)Handler().GetCount(), "ISocketHandler fd_set limit reached", LOG_LEVEL_FATAL);
330 closesocket(a_s);
331 return;
333 Socket *tmp = m_bHasCreate ? m_creator -> Create() : new X(Handler());
334 #ifdef ENABLE_IPV6
335 tmp -> SetIpv6( IsIpv6() );
336 #endif
337 tmp -> SetParent(this);
338 tmp -> Attach(a_s);
339 tmp -> SetNonblocking(true);
341 #ifdef ENABLE_IPV6
342 #ifdef IPPROTO_IPV6
343 if (sa_len == sizeof(struct sockaddr_in6))
345 struct sockaddr_in6 *p = (struct sockaddr_in6 *)&sa;
346 if (p -> sin6_family == AF_INET6)
348 Ipv6Address ad(p -> sin6_addr,ntohs(p -> sin6_port));
349 ad.SetFlowinfo(p -> sin6_flowinfo);
350 #ifndef _WIN32
351 ad.SetScopeId(p -> sin6_scope_id);
352 #endif
353 tmp -> SetRemoteAddress(ad);
356 #endif
357 #endif
358 if (sa_len == sizeof(struct sockaddr_in))
360 struct sockaddr_in *p = (struct sockaddr_in *)&sa;
361 if (p -> sin_family == AF_INET)
363 Ipv4Address ad(p -> sin_addr,ntohs(p -> sin_port));
364 tmp -> SetRemoteAddress(ad);
368 tmp -> SetConnected(true);
369 tmp -> Init();
370 tmp -> SetDeleteByHandler(true);
371 Handler().Add(tmp);
372 #ifdef HAVE_OPENSSL
373 if (tmp -> IsSSL()) // SSL Enabled socket
375 // %! OnSSLAccept calls SSLNegotiate that can finish in this one call.
376 // %! If that happens and negotiation fails, the 'tmp' instance is
377 // %! still added to the list of active sockets in the sockethandler.
378 // %! See bugfix for this in SocketHandler::Select - don't Set rwx
379 // %! flags if CloseAndDelete() flag is true.
380 // %! An even better fugbix (see TcpSocket::OnSSLAccept) now avoids
381 // %! the Add problem altogether, so ignore the above.
382 // %! (OnSSLAccept does no longer call SSLNegotiate().)
383 tmp -> OnSSLAccept();
385 else
386 #endif
388 tmp -> OnAccept();
392 /** Please don't use this method.
393 "accept()" is handled automatically in the OnRead() method. */
394 virtual SOCKET Accept(SOCKET socket, struct sockaddr *saptr, socklen_t *lenptr)
396 return accept(socket, saptr, lenptr);
399 bool HasCreator() { return m_bHasCreate; }
401 void OnOptions(int,int,int,SOCKET) {
402 SetSoReuseaddr(true);
405 protected:
406 ListenSocket(const ListenSocket& s) : Socket(s) {}
407 private:
408 ListenSocket& operator=(const ListenSocket& ) { return *this; }
409 int m_depth;
410 X *m_creator;
411 bool m_bHasCreate;
416 #ifdef SOCKETS_NAMESPACE
418 #endif
420 #endif // _SOCKETS_ListenSocket_H