1 /** \file ListenSocket.h
3 ** \author grymse@alhem.net
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"
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"
50 #ifdef SOCKETS_NAMESPACE
51 namespace SOCKETS_NAMESPACE
{
55 /** Binds incoming port number to new Socket class X.
57 template <class X
,class Y
>
58 class SyncListenSocket
: public Socket
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
)
69 m_creator
= new X(h
,y
);
70 Socket
*tmp
= m_creator
-> Create();
71 if (tmp
&& dynamic_cast<X
*>(tmp
))
88 /** Close file descriptor. */
90 if (GetSocket() != INVALID_SOCKET
)
92 closesocket(GetSocket());
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) {
105 Ipv6Address
ad(port
);
106 return Bind(ad
, depth
);
112 Ipv4Address
ad(port
);
113 return Bind(ad
, depth
);
117 int Bind(SocketAddress
& ad
,int depth
) {
119 if (dynamic_cast<SctpSocket
*>(m_creator
))
121 return Bind(ad
, "sctp", depth
);
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) {
136 Ipv6Address
ad(port
);
137 return Bind(ad
, protocol
, depth
);
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) {
157 Ipv6Address
ad(intf
, port
);
160 return Bind(ad
, depth
);
162 Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL
);
169 Ipv4Address
ad(intf
, port
);
172 return Bind(ad
, depth
);
174 Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL
);
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) {
189 Ipv6Address
ad(intf
, port
);
192 return Bind(ad
, protocol
, depth
);
194 Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL
);
201 Ipv4Address
ad(intf
, port
);
204 return Bind(ad
, protocol
, depth
);
206 Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL
);
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
);
218 if (dynamic_cast<SctpSocket
*>(m_creator
))
220 return Bind(ad
, "sctp", depth
);
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
);
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
);
244 if (dynamic_cast<SctpSocket
*>(m_creator
))
246 return Bind(ad
, "sctp", depth
);
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
);
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
) {
269 if ( (s
= CreateSocket(ad
.GetFamily(), SOCK_STREAM
, protocol
)) == INVALID_SOCKET
)
273 if (bind(s
, ad
, ad
) == -1)
275 Handler().LogError(this, "bind", Errno
, StrError(Errno
), LOG_LEVEL_FATAL
);
277 #ifdef ENABLE_EXCEPTIONS
278 throw Exception("bind() failed for port " + Utility::l2string(ad
.GetPort()) + ": " + StrError(Errno
));
282 if (listen(s
, depth
) == -1)
284 Handler().LogError(this, "listen", Errno
, StrError(Errno
), LOG_LEVEL_FATAL
);
286 #ifdef ENABLE_EXCEPTIONS
287 throw Exception("listen() failed for port " + Utility::l2string(ad
.GetPort()) + ": " + StrError(Errno
));
296 /** Return assigned port number. */
299 return GetSockPort();
302 /** Return listen queue depth. */
308 /** OnRead on a ListenSocket receives an incoming connection. */
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
);
320 if (!Handler().OkToAccept(this))
322 Handler().LogError(this, "accept", -1, "Not OK to accept", LOG_LEVEL_WARNING
);
326 if (Handler().GetCount() >= FD_SETSIZE
)
328 Handler().LogError(this, "accept", (int)Handler().GetCount(), "ISocketHandler fd_set limit reached", LOG_LEVEL_FATAL
);
332 Socket
*tmp
= m_bHasCreate
? m_creator
-> Create() : new X(Handler(),y_
);
334 tmp
-> SetIpv6( IsIpv6() );
336 tmp
-> SetParent(this);
338 tmp
-> SetNonblocking(true);
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
);
350 ad
.SetScopeId(p
-> sin6_scope_id
);
352 tmp
-> SetRemoteAddress(ad
);
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);
369 tmp
-> SetDeleteByHandler(true);
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();
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);
405 SyncListenSocket(const SyncListenSocket
& s
) : Socket(s
) {}
407 SyncListenSocket
& operator=(const SyncListenSocket
& ) { return *this; }
416 #ifdef SOCKETS_NAMESPACE
420 #endif // _SOCKETS_SyncListenSocket_H