svn cleanup
[anytun.git] / syncListenSocket.h
blob2b62bf2980423128833b4b939e3d784454f062a1
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_SyncListenSocket_H
31 #define _SOCKETS_SyncListenSocket_H
32 #include "Sockets/sockets-config.h"
34 #ifdef _WIN32
35 #include <stdlib.h>
36 #else
37 #include <errno.h>
38 #endif
40 #include "Sockets/ISocketHandler.h"
41 #include "Sockets/Socket.h"
42 #include "Sockets/Utility.h"
43 #include "Sockets/SctpSocket.h"
44 #include "Sockets/Ipv4Address.h"
45 #include "Sockets/Ipv6Address.h"
46 #ifdef ENABLE_EXCEPTIONS
47 #include "Sockets/Exception.h"
48 #endif
50 #ifdef SOCKETS_NAMESPACE
51 namespace SOCKETS_NAMESPACE {
52 #endif
55 /** Binds incoming port number to new Socket class X.
56 \ingroup basic */
57 template <class X,class Y>
58 class SyncListenSocket : public Socket
60 public:
61 /** Constructor.
62 \param h ISocketHandler reference
63 \param use_creator Optional use of creator (default true) */
64 SyncListenSocket(ISocketHandler& h, Y & y,bool use_creator = true) : Socket(h), m_depth(0), m_creator(NULL),
65 m_bHasCreate(false),y_(y)
67 if (use_creator)
69 m_creator = new X(h,y);
70 Socket *tmp = m_creator -> Create();
71 if (tmp && dynamic_cast<X *>(tmp))
73 m_bHasCreate = true;
75 if (tmp)
77 delete tmp;
81 ~SyncListenSocket() {
82 if (m_creator)
84 delete m_creator;
88 /** Close file descriptor. */
89 int Close() {
90 if (GetSocket() != INVALID_SOCKET)
92 closesocket(GetSocket());
94 return 0;
97 /** Bind and listen to any interface.
98 \param port Port (0 is random)
99 \param depth Listen queue depth */
100 int Bind(port_t port,int depth = 20) {
101 #ifdef ENABLE_IPV6
102 #ifdef IPPROTO_IPV6
103 if (IsIpv6())
105 Ipv6Address ad(port);
106 return Bind(ad, depth);
108 else
109 #endif
110 #endif
112 Ipv4Address ad(port);
113 return Bind(ad, depth);
117 int Bind(SocketAddress& ad,int depth) {
118 #ifdef USE_SCTP
119 if (dynamic_cast<SctpSocket *>(m_creator))
121 return Bind(ad, "sctp", depth);
123 #endif
124 return Bind(ad, "tcp", depth);
127 /** Bind and listen to any interface, with optional protocol.
128 \param port Port (0 is random)
129 \param protocol Network protocol
130 \param depth Listen queue depth */
131 int Bind(port_t port,const std::string& protocol,int depth = 20) {
132 #ifdef ENABLE_IPV6
133 #ifdef IPPROTO_IPV6
134 if (IsIpv6())
136 Ipv6Address ad(port);
137 return Bind(ad, protocol, depth);
139 else
140 #endif
141 #endif
143 Ipv4Address ad(port);
144 return Bind(ad, protocol, depth);
148 /** Bind and listen to specific interface.
149 \param intf Interface hostname
150 \param port Port (0 is random)
151 \param depth Listen queue depth */
152 int Bind(const std::string& intf,port_t port,int depth = 20) {
153 #ifdef ENABLE_IPV6
154 #ifdef IPPROTO_IPV6
155 if (IsIpv6())
157 Ipv6Address ad(intf, port);
158 if (ad.IsValid())
160 return Bind(ad, depth);
162 Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL);
163 return -1;
165 else
166 #endif
167 #endif
169 Ipv4Address ad(intf, port);
170 if (ad.IsValid())
172 return Bind(ad, depth);
174 Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL);
175 return -1;
179 /** Bind and listen to specific interface.
180 \param intf Interface hostname
181 \param port Port (0 is random)
182 \param protocol Network protocol
183 \param depth Listen queue depth */
184 int Bind(const std::string& intf,port_t port,const std::string& protocol,int depth = 20) {
185 #ifdef ENABLE_IPV6
186 #ifdef IPPROTO_IPV6
187 if (IsIpv6())
189 Ipv6Address ad(intf, port);
190 if (ad.IsValid())
192 return Bind(ad, protocol, depth);
194 Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL);
195 return -1;
197 else
198 #endif
199 #endif
201 Ipv4Address ad(intf, port);
202 if (ad.IsValid())
204 return Bind(ad, protocol, depth);
206 Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL);
207 return -1;
211 /** Bind and listen to ipv4 interface.
212 \param a Ipv4 interface address
213 \param port Port (0 is random)
214 \param depth Listen queue depth */
215 int Bind(ipaddr_t a,port_t port,int depth = 20) {
216 Ipv4Address ad(a, port);
217 #ifdef USE_SCTP
218 if (dynamic_cast<SctpSocket *>(m_creator))
220 return Bind(ad, "sctp", depth);
222 #endif
223 return Bind(ad, "tcp", depth);
225 /** Bind and listen to ipv4 interface.
226 \param a Ipv4 interface address
227 \param port Port (0 is random)
228 \param protocol Network protocol
229 \param depth Listen queue depth */
230 int Bind(ipaddr_t a,port_t port,const std::string& protocol,int depth) {
231 Ipv4Address ad(a, port);
232 return Bind(ad, protocol, depth);
235 #ifdef ENABLE_IPV6
236 #ifdef IPPROTO_IPV6
237 /** Bind and listen to ipv6 interface.
238 \param a Ipv6 interface address
239 \param port Port (0 is random)
240 \param depth Listen queue depth */
241 int Bind(in6_addr a,port_t port,int depth = 20) {
242 Ipv6Address ad(a, port);
243 #ifdef USE_SCTP
244 if (dynamic_cast<SctpSocket *>(m_creator))
246 return Bind(ad, "sctp", depth);
248 #endif
249 return Bind(ad, "tcp", depth);
251 /** Bind and listen to ipv6 interface.
252 \param a Ipv6 interface address
253 \param port Port (0 is random)
254 \param protocol Network protocol
255 \param depth Listen queue depth */
256 int Bind(in6_addr a,port_t port,const std::string& protocol,int depth) {
257 Ipv6Address ad(a, port);
258 return Bind(ad, protocol, depth);
260 #endif
261 #endif
263 /** Bind and listen to network interface.
264 \param ad Interface address
265 \param protocol Network protocol
266 \param depth Listen queue depth */
267 int Bind(SocketAddress& ad,const std::string& protocol,int depth) {
268 SOCKET s;
269 if ( (s = CreateSocket(ad.GetFamily(), SOCK_STREAM, protocol)) == INVALID_SOCKET)
271 return -1;
273 if (bind(s, ad, ad) == -1)
275 Handler().LogError(this, "bind", Errno, StrError(Errno), LOG_LEVEL_FATAL);
276 closesocket(s);
277 #ifdef ENABLE_EXCEPTIONS
278 throw Exception("bind() failed for port " + Utility::l2string(ad.GetPort()) + ": " + StrError(Errno));
279 #endif
280 return -1;
282 if (listen(s, depth) == -1)
284 Handler().LogError(this, "listen", Errno, StrError(Errno), LOG_LEVEL_FATAL);
285 closesocket(s);
286 #ifdef ENABLE_EXCEPTIONS
287 throw Exception("listen() failed for port " + Utility::l2string(ad.GetPort()) + ": " + StrError(Errno));
288 #endif
289 return -1;
291 m_depth = depth;
292 Attach(s);
293 return 0;
296 /** Return assigned port number. */
297 port_t GetPort()
299 return GetSockPort();
302 /** Return listen queue depth. */
303 int GetDepth()
305 return m_depth;
308 /** OnRead on a ListenSocket receives an incoming connection. */
309 void OnRead()
311 struct sockaddr sa;
312 socklen_t sa_len = sizeof(struct sockaddr);
313 SOCKET a_s = accept(GetSocket(), &sa, &sa_len);
315 if (a_s == INVALID_SOCKET)
317 Handler().LogError(this, "accept", Errno, StrError(Errno), LOG_LEVEL_ERROR);
318 return;
320 if (!Handler().OkToAccept(this))
322 Handler().LogError(this, "accept", -1, "Not OK to accept", LOG_LEVEL_WARNING);
323 closesocket(a_s);
324 return;
326 if (Handler().GetCount() >= FD_SETSIZE)
328 Handler().LogError(this, "accept", (int)Handler().GetCount(), "ISocketHandler fd_set limit reached", LOG_LEVEL_FATAL);
329 closesocket(a_s);
330 return;
332 Socket *tmp = m_bHasCreate ? m_creator -> Create() : new X(Handler(),y_);
333 #ifdef ENABLE_IPV6
334 tmp -> SetIpv6( IsIpv6() );
335 #endif
336 tmp -> SetParent(this);
337 tmp -> Attach(a_s);
338 tmp -> SetNonblocking(true);
340 #ifdef ENABLE_IPV6
341 #ifdef IPPROTO_IPV6
342 if (sa_len == sizeof(struct sockaddr_in6))
344 struct sockaddr_in6 *p = (struct sockaddr_in6 *)&sa;
345 if (p -> sin6_family == AF_INET6)
347 Ipv6Address ad(p -> sin6_addr,ntohs(p -> sin6_port));
348 ad.SetFlowinfo(p -> sin6_flowinfo);
349 #ifndef _WIN32
350 ad.SetScopeId(p -> sin6_scope_id);
351 #endif
352 tmp -> SetRemoteAddress(ad);
355 #endif
356 #endif
357 if (sa_len == sizeof(struct sockaddr_in))
359 struct sockaddr_in *p = (struct sockaddr_in *)&sa;
360 if (p -> sin_family == AF_INET)
362 Ipv4Address ad(p -> sin_addr,ntohs(p -> sin_port));
363 tmp -> SetRemoteAddress(ad);
367 tmp -> SetConnected(true);
368 tmp -> Init();
369 tmp -> SetDeleteByHandler(true);
370 Handler().Add(tmp);
371 #ifdef HAVE_OPENSSL
372 if (tmp -> IsSSL()) // SSL Enabled socket
374 // %! OnSSLAccept calls SSLNegotiate that can finish in this one call.
375 // %! If that happens and negotiation fails, the 'tmp' instance is
376 // %! still added to the list of active sockets in the sockethandler.
377 // %! See bugfix for this in SocketHandler::Select - don't Set rwx
378 // %! flags if CloseAndDelete() flag is true.
379 // %! An even better fugbix (see TcpSocket::OnSSLAccept) now avoids
380 // %! the Add problem altogether, so ignore the above.
381 // %! (OnSSLAccept does no longer call SSLNegotiate().)
382 tmp -> OnSSLAccept();
384 else
385 #endif
387 tmp -> OnAccept();
391 /** Please don't use this method.
392 "accept()" is handled automatically in the OnRead() method. */
393 virtual SOCKET Accept(SOCKET socket, struct sockaddr *saptr, socklen_t *lenptr)
395 return accept(socket, saptr, lenptr);
398 bool HasCreator() { return m_bHasCreate; }
400 void OnOptions(int,int,int,SOCKET) {
401 SetSoReuseaddr(true);
404 protected:
405 SyncListenSocket(const SyncListenSocket& s) : Socket(s) {}
406 private:
407 SyncListenSocket& operator=(const SyncListenSocket& ) { return *this; }
408 int m_depth;
409 X *m_creator;
410 bool m_bHasCreate;
411 Y & y_;
416 #ifdef SOCKETS_NAMESPACE
418 #endif
420 #endif // _SOCKETS_SyncListenSocket_H