Used a more uniform of logging and added a commandline parser.
[UnsignedByte.git] / src / Sockets / ListenSocket.h
blobdbd362e41f226a312123b3be5295b0b181b166bc
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 "ISocketHandler.h"
41 #include "Socket.h"
42 #include "Utility.h"
43 #include "SctpSocket.h"
44 #include "Ipv4Address.h"
45 #include "Ipv6Address.h"
47 #ifdef SOCKETS_NAMESPACE
48 namespace SOCKETS_NAMESPACE {
49 #endif
52 /** Binds incoming port number to new Socket class X.
53 \ingroup basic */
54 template <class X>
55 class ListenSocket : public Socket
57 public:
58 /** Constructor.
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)
62 ,m_bHasCreate(false)
64 if (use_creator)
66 m_creator = new X(h);
67 Socket *tmp = m_creator -> Create();
68 if (tmp && dynamic_cast<X *>(tmp))
70 m_bHasCreate = true;
72 if (tmp)
74 delete tmp;
78 ~ListenSocket() {
79 if (m_creator)
81 delete m_creator;
85 /** Close file descriptor. */
86 int Close() {
87 if (GetSocket() != INVALID_SOCKET)
89 closesocket(GetSocket());
91 return 0;
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) {
98 #ifdef ENABLE_IPV6
99 #ifdef IPPROTO_IPV6
100 if (IsIpv6())
102 Ipv6Address ad(port);
103 return Bind(ad, depth);
105 else
106 #endif
107 #endif
109 Ipv4Address ad(port);
110 return Bind(ad, depth);
114 int Bind(SocketAddress& ad,int depth) {
115 #ifdef USE_SCTP
116 if (dynamic_cast<SctpSocket *>(m_creator))
118 return Bind(ad, "sctp", depth);
120 #endif
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) {
129 #ifdef ENABLE_IPV6
130 #ifdef IPPROTO_IPV6
131 if (IsIpv6())
133 Ipv6Address ad(port);
134 return Bind(ad, protocol, depth);
136 else
137 #endif
138 #endif
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) {
150 #ifdef ENABLE_IPV6
151 #ifdef IPPROTO_IPV6
152 if (IsIpv6())
154 Ipv6Address ad(intf, port);
155 if (ad.IsValid())
157 return Bind(ad, depth);
159 Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL);
160 return -1;
162 else
163 #endif
164 #endif
166 Ipv4Address ad(intf, port);
167 if (ad.IsValid())
169 return Bind(ad, depth);
171 Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL);
172 return -1;
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) {
182 #ifdef ENABLE_IPV6
183 #ifdef IPPROTO_IPV6
184 if (IsIpv6())
186 Ipv6Address ad(intf, port);
187 if (ad.IsValid())
189 return Bind(ad, protocol, depth);
191 Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL);
192 return -1;
194 else
195 #endif
196 #endif
198 Ipv4Address ad(intf, port);
199 if (ad.IsValid())
201 return Bind(ad, protocol, depth);
203 Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL);
204 return -1;
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);
214 #ifdef USE_SCTP
215 if (dynamic_cast<SctpSocket *>(m_creator))
217 return Bind(ad, "sctp", depth);
219 #endif
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);
232 #ifdef ENABLE_IPV6
233 #ifdef IPPROTO_IPV6
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);
240 #ifdef USE_SCTP
241 if (dynamic_cast<SctpSocket *>(m_creator))
243 return Bind(ad, "sctp", depth);
245 #endif
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);
257 #endif
258 #endif
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) {
265 SOCKET s;
266 if ( (s = CreateSocket(ad.GetFamily(), SOCK_STREAM, protocol)) == INVALID_SOCKET)
268 return -1;
270 if (bind(s, ad, ad) == -1)
272 Handler().LogError(this, "bind", Errno, StrError(Errno), LOG_LEVEL_FATAL);
273 closesocket(s);
274 return -1;
276 if (listen(s, depth) == -1)
278 Handler().LogError(this, "listen", Errno, StrError(Errno), LOG_LEVEL_FATAL);
279 closesocket(s);
280 return -1;
282 // retrieve bound port
283 #ifdef ENABLE_IPV6
284 #ifdef IPPROTO_IPV6
285 if (IsIpv6())
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);
292 else
293 #endif
294 #endif
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);
301 m_depth = depth;
302 Attach(s);
303 return 0;
306 /** Return assigned port number. */
307 port_t GetPort()
309 return m_port;
312 /** Return listen queue depth. */
313 int GetDepth()
315 return m_depth;
318 /** OnRead on a ListenSocket receives an incoming connection. */
319 void OnRead()
321 struct sockaddr sa;
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);
328 return;
330 if (!Handler().OkToAccept(this))
332 Handler().LogError(this, "accept", -1, "Not OK to accept", LOG_LEVEL_WARNING);
333 closesocket(a_s);
334 return;
336 if (Handler().GetCount() >= FD_SETSIZE)
338 Handler().LogError(this, "accept", (int)Handler().GetCount(), "ISocketHandler fd_set limit reached", LOG_LEVEL_FATAL);
339 closesocket(a_s);
340 return;
342 Socket *tmp = m_bHasCreate ? m_creator -> Create() : new X(Handler());
343 #ifdef ENABLE_IPV6
344 tmp -> SetIpv6( IsIpv6() );
345 #endif
346 tmp -> SetParent(this);
347 tmp -> Attach(a_s);
348 tmp -> SetNonblocking(true);
350 #ifdef ENABLE_IPV6
351 #ifdef IPPROTO_IPV6
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);
359 #ifndef _WIN32
360 ad.SetScopeId(p -> sin6_scope_id);
361 #endif
362 tmp -> SetRemoteAddress(ad);
365 #endif
366 #endif
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);
378 tmp -> Init();
379 tmp -> SetDeleteByHandler(true);
380 Handler().Add(tmp);
381 #ifdef HAVE_OPENSSL
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();
394 else
395 #endif
397 tmp -> OnAccept();
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);
414 protected:
415 ListenSocket(const ListenSocket& s) : Socket(s) {}
416 private:
417 ListenSocket& operator=(const ListenSocket& ) { return *this; }
418 port_t m_port;
419 int m_depth;
420 X *m_creator;
421 bool m_bHasCreate;
426 #ifdef SOCKETS_NAMESPACE
428 #endif
430 #endif // _SOCKETS_ListenSocket_H