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_ListenSocket_H
31 #define _SOCKETS_ListenSocket_H
32 #include "sockets-config.h"
41 #include "ISocketHandler.h"
44 #include "SctpSocket.h"
45 #include "Ipv4Address.h"
46 #include "Ipv6Address.h"
47 #ifdef ENABLE_EXCEPTIONS
48 #include "Exception.h"
51 #ifdef SOCKETS_NAMESPACE
52 namespace SOCKETS_NAMESPACE
{
56 /** Binds incoming port number to new Socket class X.
59 class ListenSocket
: public Socket
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
)
71 Socket
*tmp
= m_creator
-> Create();
72 if (tmp
&& dynamic_cast<X
*>(tmp
))
89 /** Close file descriptor. */
91 if (GetSocket() != INVALID_SOCKET
)
93 closesocket(GetSocket());
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) {
106 Ipv6Address
ad(port
);
107 return Bind(ad
, depth
);
113 Ipv4Address
ad(port
);
114 return Bind(ad
, depth
);
118 int Bind(SocketAddress
& ad
,int depth
) {
120 if (dynamic_cast<SctpSocket
*>(m_creator
))
122 return Bind(ad
, "sctp", depth
);
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) {
137 Ipv6Address
ad(port
);
138 return Bind(ad
, protocol
, depth
);
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) {
158 Ipv6Address
ad(intf
, port
);
161 return Bind(ad
, depth
);
163 Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL
);
170 Ipv4Address
ad(intf
, port
);
173 return Bind(ad
, depth
);
175 Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL
);
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) {
190 Ipv6Address
ad(intf
, port
);
193 return Bind(ad
, protocol
, depth
);
195 Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL
);
202 Ipv4Address
ad(intf
, port
);
205 return Bind(ad
, protocol
, depth
);
207 Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL
);
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
);
219 if (dynamic_cast<SctpSocket
*>(m_creator
))
221 return Bind(ad
, "sctp", depth
);
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
);
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
);
245 if (dynamic_cast<SctpSocket
*>(m_creator
))
247 return Bind(ad
, "sctp", depth
);
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
);
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
) {
270 if ( (s
= CreateSocket(ad
.GetFamily(), SOCK_STREAM
, protocol
)) == INVALID_SOCKET
)
274 if (bind(s
, ad
, ad
) == -1)
276 Handler().LogError(this, "bind", Errno
, StrError(Errno
), LOG_LEVEL_FATAL
);
278 #ifdef ENABLE_EXCEPTIONS
279 throw Exception("bind() failed for port " + Utility::l2string(ad
.GetPort()) + ": " + StrError(Errno
));
283 if (listen(s
, depth
) == -1)
285 Handler().LogError(this, "listen", Errno
, StrError(Errno
), LOG_LEVEL_FATAL
);
287 #ifdef ENABLE_EXCEPTIONS
288 throw Exception("listen() failed for port " + Utility::l2string(ad
.GetPort()) + ": " + StrError(Errno
));
297 /** Return assigned port number. */
300 return GetSockPort();
303 /** Return listen queue depth. */
309 /** OnRead on a ListenSocket receives an incoming connection. */
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
);
321 if (!Handler().OkToAccept(this))
323 Handler().LogError(this, "accept", -1, "Not OK to accept", LOG_LEVEL_WARNING
);
327 if (Handler().GetCount() >= FD_SETSIZE
)
329 Handler().LogError(this, "accept", (int)Handler().GetCount(), "ISocketHandler fd_set limit reached", LOG_LEVEL_FATAL
);
333 Socket
*tmp
= m_bHasCreate
? m_creator
-> Create() : new X(Handler());
335 tmp
-> SetIpv6( IsIpv6() );
337 tmp
-> SetParent(this);
339 tmp
-> SetNonblocking(true);
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
);
351 ad
.SetScopeId(p
-> sin6_scope_id
);
353 tmp
-> SetRemoteAddress(ad
);
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);
370 tmp
-> SetDeleteByHandler(true);
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();
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);
406 ListenSocket(const ListenSocket
& s
) : Socket(s
) {}
408 ListenSocket
& operator=(const ListenSocket
& ) { return *this; }
416 #ifdef SOCKETS_NAMESPACE
420 #endif // _SOCKETS_ListenSocket_H