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"
40 #include "ISocketHandler.h"
43 #include "SctpSocket.h"
44 #include "Ipv4Address.h"
45 #include "Ipv6Address.h"
47 #ifdef SOCKETS_NAMESPACE
48 namespace SOCKETS_NAMESPACE
{
52 /** Binds incoming port number to new Socket class X.
55 class ListenSocket
: public Socket
59 \param h ISocketHandler reference
60 \param use_creator Optional use of creator (default true) */
61 ListenSocket(ISocketHandler
& h
,bool use_creator
= true) : Socket(h
), m_port(0), m_depth(0), m_creator(NULL
)
67 Socket
*tmp
= m_creator
-> Create();
68 if (tmp
&& dynamic_cast<X
*>(tmp
))
85 /** Close file descriptor. */
87 if (GetSocket() != INVALID_SOCKET
)
89 closesocket(GetSocket());
94 /** Bind and listen to any interface.
95 \param port Port (0 is random)
96 \param depth Listen queue depth */
97 int Bind(port_t port
,int depth
= 20) {
102 Ipv6Address
ad(port
);
103 return Bind(ad
, depth
);
109 Ipv4Address
ad(port
);
110 return Bind(ad
, depth
);
114 int Bind(SocketAddress
& ad
,int depth
) {
116 if (dynamic_cast<SctpSocket
*>(m_creator
))
118 return Bind(ad
, "sctp", depth
);
121 return Bind(ad
, "tcp", depth
);
124 /** Bind and listen to any interface, with optional protocol.
125 \param port Port (0 is random)
126 \param protocol Network protocol
127 \param depth Listen queue depth */
128 int Bind(port_t port
,const std::string
& protocol
,int depth
= 20) {
133 Ipv6Address
ad(port
);
134 return Bind(ad
, protocol
, depth
);
140 Ipv4Address
ad(port
);
141 return Bind(ad
, protocol
, depth
);
145 /** Bind and listen to specific interface.
146 \param intf Interface hostname
147 \param port Port (0 is random)
148 \param depth Listen queue depth */
149 int Bind(const std::string
& intf
,port_t port
,int depth
= 20) {
154 Ipv6Address
ad(intf
, port
);
157 return Bind(ad
, depth
);
159 Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL
);
166 Ipv4Address
ad(intf
, port
);
169 return Bind(ad
, depth
);
171 Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL
);
176 /** Bind and listen to specific interface.
177 \param intf Interface hostname
178 \param port Port (0 is random)
179 \param protocol Network protocol
180 \param depth Listen queue depth */
181 int Bind(const std::string
& intf
,port_t port
,const std::string
& protocol
,int depth
= 20) {
186 Ipv6Address
ad(intf
, port
);
189 return Bind(ad
, protocol
, depth
);
191 Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL
);
198 Ipv4Address
ad(intf
, port
);
201 return Bind(ad
, protocol
, depth
);
203 Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL
);
208 /** Bind and listen to ipv4 interface.
209 \param a Ipv4 interface address
210 \param port Port (0 is random)
211 \param depth Listen queue depth */
212 int Bind(ipaddr_t a
,port_t port
,int depth
= 20) {
213 Ipv4Address
ad(a
, port
);
215 if (dynamic_cast<SctpSocket
*>(m_creator
))
217 return Bind(ad
, "sctp", depth
);
220 return Bind(ad
, "tcp", depth
);
222 /** Bind and listen to ipv4 interface.
223 \param a Ipv4 interface address
224 \param port Port (0 is random)
225 \param protocol Network protocol
226 \param depth Listen queue depth */
227 int Bind(ipaddr_t a
,port_t port
,const std::string
& protocol
,int depth
) {
228 Ipv4Address
ad(a
, port
);
229 return Bind(ad
, protocol
, depth
);
234 /** Bind and listen to ipv6 interface.
235 \param a Ipv6 interface address
236 \param port Port (0 is random)
237 \param depth Listen queue depth */
238 int Bind(in6_addr a
,port_t port
,int depth
= 20) {
239 Ipv6Address
ad(a
, port
);
241 if (dynamic_cast<SctpSocket
*>(m_creator
))
243 return Bind(ad
, "sctp", depth
);
246 return Bind(ad
, "tcp", depth
);
248 /** Bind and listen to ipv6 interface.
249 \param a Ipv6 interface address
250 \param port Port (0 is random)
251 \param protocol Network protocol
252 \param depth Listen queue depth */
253 int Bind(in6_addr a
,port_t port
,const std::string
& protocol
,int depth
) {
254 Ipv6Address
ad(a
, port
);
255 return Bind(ad
, protocol
, depth
);
260 /** Bind and listen to network interface.
261 \param ad Interface address
262 \param protocol Network protocol
263 \param depth Listen queue depth */
264 int Bind(SocketAddress
& ad
,const std::string
& protocol
,int depth
) {
266 if ( (s
= CreateSocket(ad
.GetFamily(), SOCK_STREAM
, protocol
)) == INVALID_SOCKET
)
270 if (bind(s
, ad
, ad
) == -1)
272 Handler().LogError(this, "bind", Errno
, StrError(Errno
), LOG_LEVEL_FATAL
);
276 if (listen(s
, depth
) == -1)
278 Handler().LogError(this, "listen", Errno
, StrError(Errno
), LOG_LEVEL_FATAL
);
282 // retrieve bound port
287 struct sockaddr_in6 sa
;
288 socklen_t sockaddr_length
= sizeof(struct sockaddr_in6
);
289 getsockname(s
, (struct sockaddr
*)&sa
, (socklen_t
*)&sockaddr_length
);
290 m_port
= ntohs(sa
.sin6_port
);
296 struct sockaddr_in sa
;
297 socklen_t sockaddr_length
= sizeof(struct sockaddr_in
);
298 getsockname(s
, (struct sockaddr
*)&sa
, (socklen_t
*)&sockaddr_length
);
299 m_port
= ntohs(sa
.sin_port
);
306 /** Return assigned port number. */
312 /** Return listen queue depth. */
318 /** OnRead on a ListenSocket receives an incoming connection. */
322 socklen_t sa_len
= sizeof(struct sockaddr
);
323 SOCKET a_s
= accept(GetSocket(), &sa
, &sa_len
);
325 if (a_s
== INVALID_SOCKET
)
327 Handler().LogError(this, "accept", Errno
, StrError(Errno
), LOG_LEVEL_ERROR
);
330 if (!Handler().OkToAccept(this))
332 Handler().LogError(this, "accept", -1, "Not OK to accept", LOG_LEVEL_WARNING
);
336 if (Handler().GetCount() >= FD_SETSIZE
)
338 Handler().LogError(this, "accept", (int)Handler().GetCount(), "ISocketHandler fd_set limit reached", LOG_LEVEL_FATAL
);
342 Socket
*tmp
= m_bHasCreate
? m_creator
-> Create() : new X(Handler());
344 tmp
-> SetIpv6( IsIpv6() );
346 tmp
-> SetParent(this);
348 tmp
-> SetNonblocking(true);
352 if (sa_len
== sizeof(struct sockaddr_in6
))
354 struct sockaddr_in6
*p
= (struct sockaddr_in6
*)&sa
;
355 if (p
-> sin6_family
== AF_INET6
)
357 Ipv6Address
ad(p
-> sin6_addr
,ntohs(p
-> sin6_port
));
358 ad
.SetFlowinfo(p
-> sin6_flowinfo
);
360 ad
.SetScopeId(p
-> sin6_scope_id
);
362 tmp
-> SetRemoteAddress(ad
);
367 if (sa_len
== sizeof(struct sockaddr_in
))
369 struct sockaddr_in
*p
= (struct sockaddr_in
*)&sa
;
370 if (p
-> sin_family
== AF_INET
)
372 Ipv4Address
ad(p
-> sin_addr
,ntohs(p
-> sin_port
));
373 tmp
-> SetRemoteAddress(ad
);
377 tmp
-> SetConnected(true);
379 tmp
-> SetDeleteByHandler(true);
382 if (tmp
-> IsSSL()) // SSL Enabled socket
384 // %! OnSSLAccept calls SSLNegotiate that can finish in this one call.
385 // %! If that happens and negotiation fails, the 'tmp' instance is
386 // %! still added to the list of active sockets in the sockethandler.
387 // %! See bugfix for this in SocketHandler::Select - don't Set rwx
388 // %! flags if CloseAndDelete() flag is true.
389 // %! An even better fugbix (see TcpSocket::OnSSLAccept) now avoids
390 // %! the Add problem altogether, so ignore the above.
391 // %! (OnSSLAccept does no longer call SSLNegotiate().)
392 tmp
-> OnSSLAccept();
401 /** Please don't use this method.
402 "accept()" is handled automatically in the OnRead() method. */
403 virtual SOCKET
Accept(SOCKET socket
, struct sockaddr
*saptr
, socklen_t
*lenptr
)
405 return accept(socket
, saptr
, lenptr
);
408 bool HasCreator() { return m_bHasCreate
; }
410 void OnOptions(int,int,int,SOCKET
) {
411 SetSoReuseaddr(true);
415 ListenSocket(const ListenSocket
& s
) : Socket(s
) {}
417 ListenSocket
& operator=(const ListenSocket
& ) { return *this; }
426 #ifdef SOCKETS_NAMESPACE
430 #endif // _SOCKETS_ListenSocket_H