blocxx
ServerSocketImpl.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2 * Copyright (C) 2005, Vintela, Inc. All rights reserved.
3 * Copyright (C) 2006, Novell, Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of
14 * Vintela, Inc.,
15 * nor Novell, Inc.,
16 * nor the names of its contributors or employees may be used to
17 * endorse or promote products derived from this software without
18 * specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 *******************************************************************************/
32 
33 
39 #include "blocxx/BLOCXX_config.h"
41 #include "blocxx/Format.hpp"
42 #include "blocxx/ByteSwap.hpp"
43 #include "blocxx/FileSystem.hpp"
44 #include "blocxx/File.hpp"
45 #include "blocxx/Thread.hpp"
46 #include "blocxx/SocketUtils.hpp"
47 #include "blocxx/System.hpp"
48 #include "blocxx/TimeoutTimer.hpp"
49 
50 extern "C"
51 {
52 #if !defined(BLOCXX_WIN32)
53 #include <sys/types.h>
54 #include <sys/stat.h>
55 #include <sys/socket.h>
56 #include <sys/time.h>
57 #include <netinet/in.h>
58 #include <arpa/inet.h>
59 #include <netdb.h>
60 #include <unistd.h>
61 #include <fcntl.h>
62 
63 #define INVALID_SOCKET -1
64 #endif
65 }
66 
67 #include <cerrno>
68 
69 namespace BLOCXX_NAMESPACE
70 {
73  : m_sockfd(INVALID_SOCKET)
74  , m_localAddress(SocketAddress::allocEmptyAddress(SocketAddress::INET))
75  , m_isActive(false)
76  , m_sslCtx(sslCtx)
77 #if defined(BLOCXX_WIN32)
78  , m_event(NULL)
79  , m_shuttingDown(false)
80 {
81  m_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
82  BLOCXX_ASSERT(m_event != NULL);
83 }
84 #else
85  , m_udsFile()
86 {
87 }
88 #endif
89 
92  : m_sockfd(INVALID_SOCKET)
93  , m_localAddress(SocketAddress::allocEmptyAddress(SocketAddress::INET))
94  , m_isActive(false)
95  , m_isSSL(isSSL)
96 #if defined(BLOCXX_WIN32)
97  , m_event(NULL)
98  , m_shuttingDown(false)
99 {
100  m_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
101  BLOCXX_ASSERT(m_event != NULL);
102 }
103 #else
104  , m_udsFile()
105 {
106 }
107 #endif
108 
111 {
112  try
113  {
114  close();
115  }
116  catch (...)
117  {
118  // don't let exceptions escape
119  }
120 #if defined(BLOCXX_WIN32)
121  ::CloseHandle(m_event);
122 #endif
123 }
124 
126 Select_t
128 {
129 #if defined(BLOCXX_WIN32)
130  Select_t st;
131  st.event = m_event;
132  st.sockfd = m_sockfd;
133  st.isSocket = true;
134  st.networkevents = FD_ACCEPT;
135  return st;
136 #else
137  return m_sockfd;
138 #endif
139 }
140 
142 void
144  int queueSize, const String& listenAddr,
145  SocketFlags::EReuseAddrFlag reuseAddr)
146 {
147  m_isSSL = isSSL;
148  doListen(port, queueSize,listenAddr, reuseAddr);
149 }
150 
151 #if defined(BLOCXX_WIN32)
152 
153 void
154 ServerSocketImpl::doListen(UInt16 port,
155  int queueSize, const String& listenAddr,
156  SocketFlags::EReuseAddrFlag reuseAddr)
157 {
158  SocketHandle_t sock_ipv6 = INVALID_SOCKET;
160  close();
161 
162 #ifdef BLOCXX_HAVE_IPV6
163  // This will try to use IPv6 (AF_INET6). If it is not supported, it will
164  // fall back to the normal IPv4 (AF_INET).
165  sock_ipv6 = ::socket(AF_INET6, SOCK_STREAM, 0);
166  if (sock_ipv6 == INVALID_SOCKET)
167  {
168  switch(errno)
169  {
170  case EPROTONOSUPPORT:
171  case EAFNOSUPPORT:
172  case EPFNOSUPPORT:
173  case EINVAL:
174  m_sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
175  break;
176  default:
177  break;
178  }
179  }
180  else
181  {
182  m_sockfd = sock_ipv6;
183  }
184 #else
185  m_sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
186 #endif
187  if (m_sockfd == INVALID_SOCKET)
188  {
189  BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1",
190  System::lastErrorMsg(true)).c_str());
191  }
192  // Set listen socket to nonblocking
193  unsigned long cmdArg = 1;
194  if (::ioctlsocket(m_sockfd, FIONBIO, &cmdArg) == SOCKET_ERROR)
195  {
196  BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1",
197  System::lastErrorMsg(true)).c_str());
198  }
199 
200  if (reuseAddr)
201  {
202  DWORD reuse = 1;
203  ::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR,
204  (const char*)&reuse, sizeof(reuse));
205  }
206 
207  if ( sock_ipv6 == INVALID_SOCKET )
208  {
209  // IPv4
210  ServerSocketImpl::doListenIPv4( port, queueSize, listenAddr);
211  }
212 #ifdef BLOCXX_HAVE_IPV6
213  else
214  {
215  // IPv6
216  ServerSocketImpl::doListenIPv6( port, queueSize, listenAddr, reuseAddr);
217  }
218 #endif
219 }
221 void
222 ServerSocketImpl::doListenIPv4(UInt16 port, int queueSize, const String& listenAddr )
223 {
224  // use IPv4 protocol
225  InetSocketAddress_t inetAddr;
226  memset(&inetAddr, 0, sizeof(inetAddr));
227  reinterpret_cast<sockaddr_in*>(&inetAddr)->sin_family = AF_INET;
228  reinterpret_cast<sockaddr_in*>(&inetAddr)->sin_port = hton16(port);
229  if (listenAddr == SocketAddress::ALL_LOCAL_ADDRESSES)
230  {
231  reinterpret_cast<sockaddr_in*>(&inetAddr)->sin_addr.s_addr = hton32(INADDR_ANY);
232  }
233  else
234  {
235  SocketAddress addr = SocketAddress::getByName(listenAddr);
236  reinterpret_cast<sockaddr_in*>(&inetAddr)->sin_addr.s_addr =
237  reinterpret_cast<const sockaddr_in*>(addr.getInetAddress())->sin_addr.s_addr;
238  }
239  if (::bind(m_sockfd, reinterpret_cast<sockaddr*>(&inetAddr), sizeof(inetAddr)) == -1)
240  {
241  close();
242  BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1",
243  System::lastErrorMsg(true)).c_str());
244  }
245  if (::listen(m_sockfd, queueSize) == -1)
246  {
247  close();
248  BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1",
249  System::lastErrorMsg(true)).c_str());
250  }
251  fillAddrParms();
252  m_isActive = true;
253 }
255 #ifdef BLOCXX_HAVE_IPV6
256 void
257 ServerSocketImpl::doListenIPv6(UInt16 port, int queueSize, const String& listenAddr)
258 {
259  // use IPv6 protocol
260  InetSocketAddress_t inetAddr;
261  memset(&inetAddr, 0, sizeof(inetAddr));
262  reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_family = AF_INET6;
263  reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_port = hton16(port);
264  if (listenAddr == SocketAddress::ALL_LOCAL_ADDRESSES)
265  {
266  // copy IPv6 address any
267  memcpy(reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_addr.s6_addr, &in6addr_any, sizeof(struct in6_addr));
268  }
269  else
270  {
271  // create network address structure for IPv6 protocol
272  if(!inet_pton(AF_INET6, listenAddr.c_str(), (void*)&reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_addr))
273  {
274  addrinfo *addrinfos;
275  addrinfo hints;
276  memset(&hints, 0, sizeof(hints));
277  hints.ai_socktype = SOCK_STREAM;
278  hints.ai_family = AF_INET6;
279  if(getaddrinfo(listenAddr.c_str(), NULL, &hints, &addrinfos))
280  {
281  close();
282  BLOCXX_THROW(SocketException, Format("ServerSocketImpl:: doListen(): getaddrinfo() %1",
283  System::lastErrorMsg(true)).c_str());
284  }
285  memcpy(reinterpret_cast<sockaddr_in6*>(&inetAddr), addrinfos->ai_addr, addrinfos->ai_addrlen);
286  freeaddrinfo(addrinfos);
287  }
288  }
289  if (::bind(m_sockfd, reinterpret_cast<sockaddr*>(&inetAddr), sizeof(inetAddr)) == -1)
290  {
291  close();
292  BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1",
293  System::lastErrorMsg(true)).c_str());
294  }
295  if (::listen(m_sockfd, queueSize) == -1)
296  {
297  close();
298  BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1",
299  System::lastErrorMsg(true)).c_str());
300  }
301  fillAddrParms();
302  m_isActive = true;
303 }
304 #endif // BLOCXX_HAVE_IPV6
305 
306 namespace
307 {
308 
309 int
310 waitForAcceptIO(SocketHandle_t fd, HANDLE eventArg, const Timeout& timeOutSecs,
311  long networkEvents)
312 {
313  TimeoutTimer timer(timeOutSecs);
314 
315  if (networkEvents != -1L)
316  {
317  if(::WSAEventSelect(fd, eventArg, networkEvents) != 0)
318  {
319  BLOCXX_THROW(SocketException,
320  Format("WSAEventSelect failed in waitForAcceptIO: %1",
321  System::lastErrorMsg(true)).c_str());
322  }
323  }
324 
325  int cc;
326  switch(::WaitForSingleObject(eventArg, timer.asDWORDMs()))
327  {
328  case WAIT_OBJECT_0:
329  ::ResetEvent(eventArg);
330  cc = 0;
331  break;
332  case WAIT_TIMEOUT:
333  cc = ETIMEDOUT;
334  break;
335  default:
336  cc = -1;
337  break;
338  }
339 
340  return cc;
341 }
342 
343 }
344 
346 Socket
347 ServerSocketImpl::accept(const Timeout& timeoutSecs)
348 {
350 
351  if (!m_isActive)
352  {
353  BLOCXX_THROW(SocketException, "ServerSocketImpl::accept: NONE");
354  }
355 
356  // Register interest in FD_ACCEPT events
357  if(::WSAEventSelect(m_sockfd, m_event, FD_ACCEPT) != 0)
358  {
359  BLOCXX_THROW(SocketException,
360  Format("WSAEventSelect failed in accept: %1",
361  System::lastErrorMsg(true)).c_str());
362  }
363 
364  SOCKET clntfd;
365  socklen_t clntlen;
366  InetSocketAddress_t clntInetAddr;
367  HANDLE events[2];
368  int cc;
369 
370  while (true)
371  {
372  clntlen = sizeof(clntInetAddr);
373  clntfd = ::accept(m_sockfd,
374  reinterpret_cast<struct sockaddr*>(&clntInetAddr), &clntlen);
375  if (clntfd != INVALID_SOCKET)
376  {
377  // Got immediate connection
378  break;
379  }
380 
381  if (::WSAGetLastError() != WSAEWOULDBLOCK)
382  {
383  BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1",
384  System::lastErrorMsg(true)).c_str());
385  }
386 
387  //cc = SocketUtils::waitForIO(m_sockfd, m_event, INFINITE, FD_ACCEPT);
388  cc = waitForAcceptIO(m_sockfd, m_event, timeoutSecs, FD_ACCEPT);
389  if(m_shuttingDown)
390  {
391  cc = -2;
392  }
393 
394  switch (cc)
395  {
396  case -1:
397  BLOCXX_THROW(SocketException, "Error while waiting for network events");
398  case -2:
399  BLOCXX_THROW(SocketException, "Shutdown event was signaled");
400  case ETIMEDOUT:
401  BLOCXX_THROW(SocketTimeoutException,"Timed out waiting for a connection");
402  }
403  }
404 
405  // Unregister for any events. necessary to put us back in blocking mode.
406  if(::WSAEventSelect(clntfd, NULL, 0) != 0)
407  {
408  BLOCXX_THROW(SocketException,
409  Format("WSAEventSelect failed in accept: %1",
410  System::lastErrorMsg(true)).c_str());
411  }
412 
413  // set socket back to blocking; otherwise it'll inherit non-blocking from the listening socket
414  unsigned long cmdArg = 0;
415  if (::ioctlsocket(clntfd, FIONBIO, &cmdArg) == SOCKET_ERROR)
416  {
417  BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1",
418  System::lastErrorMsg(true)).c_str());
419  }
420 
422  {
423  return Socket(clntfd, m_localAddress.getType(), m_isSSL);
424  }
425 
426  return Socket(clntfd, m_localAddress.getType(), m_sslCtx);
427 }
428 #else
429 
430 void
432  int queueSize, const String& listenAddr,
433  SocketFlags::EReuseAddrFlag reuseAddr)
434 {
435  SocketHandle_t sock_ipv6 = INVALID_SOCKET;
437  close();
438 
439 #ifdef BLOCXX_HAVE_IPV6
440  // This will try to use IPv6 (AF_INET6). If it is not supported, it will
441  // fall back to the normal IPv4 (AF_INET).
442  sock_ipv6 = ::socket(AF_INET6, SOCK_STREAM, 0);
443  if (sock_ipv6 == INVALID_SOCKET)
444  {
445  switch(errno)
446  {
447  case EPROTONOSUPPORT:
448  case EAFNOSUPPORT:
449  case EPFNOSUPPORT:
450  case EINVAL:
451  // open socket for IPv4 protocol
452  m_sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
453  break;
454  default:
455  break;
456  }
457  }
458  else
459  {
460  m_sockfd = sock_ipv6;
461 #ifdef IPV6_V6ONLY
462  int ipv6_proto = IPPROTO_IPV6;
463 #ifdef SOL_IP
464  ipv6_proto = SOL_IP;
465 #endif
466  int ipv6_only=0;
467  ::setsockopt(m_sockfd, ipv6_proto, IPV6_V6ONLY, &ipv6_only, sizeof(ipv6_only));
468 #endif
469  }
470 #else
471  m_sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
472 #endif
473  if (m_sockfd == INVALID_SOCKET)
474  {
475  BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): socket()");
476  }
477  // set the close on exec flag so child process can't keep the socket.
478  if (::fcntl(m_sockfd, F_SETFD, FD_CLOEXEC) == -1)
479  {
480  close();
481  BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): fcntl() failed to set "
482  "close-on-exec flag on listen socket");
483  }
484  // set listen socket to nonblocking; see Unix Network Programming,
485  // pages 422-424.
486  int fdflags = ::fcntl(m_sockfd, F_GETFL, 0);
487  ::fcntl(m_sockfd, F_SETFL, fdflags | O_NONBLOCK);
488  // is this safe? Should be, but some OS kernels have problems with it.
489  // It's OK on current linux versions. Definitely not on
490  // OLD (kernel < 1.3.60) ones. Who knows about on other OS's like UnixWare or
491  // OpenServer?
492  // See http://monkey.org/openbsd/archive/misc/9601/msg00031.html
493  // or just google for "bind() Security Problems"
494  // Let the kernel reuse the port without waiting for it to time out.
495  // Without this line, you can't stop and immediately re-start the daemon.
496  if (reuseAddr)
497  {
498  int reuse = 1;
499 #if defined(BLOCXX_NCR)
500  ::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse));
501 #else
502  ::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
503 #endif
504  }
505  if ( sock_ipv6 == INVALID_SOCKET)
506  {
507  // IPv4
508  ServerSocketImpl::doListenIPv4( port, queueSize, listenAddr );
509  }
510 #ifdef BLOCXX_HAVE_IPV6
511  else
512  { // IPv6
513  ServerSocketImpl::doListenIPv6( port, queueSize, listenAddr );
514  }
515 #endif
516 }
517 
519 void
520 ServerSocketImpl::doListenIPv4(UInt16 port, int queueSize, const String& listenAddr )
521 {
522  // use IPv4 protocol
523  InetSocketAddress_t inetAddr;
524  memset(&inetAddr, 0, sizeof(inetAddr));
525  reinterpret_cast<sockaddr_in*>(&inetAddr)->sin_family = AF_INET;
526  reinterpret_cast<sockaddr_in*>(&inetAddr)->sin_port = hton16(port);
527  if (listenAddr == SocketAddress::ALL_LOCAL_ADDRESSES)
528  {
529  reinterpret_cast<sockaddr_in*>(&inetAddr)->sin_addr.s_addr = hton32(INADDR_ANY);
530  }
531  else
532  {
533  SocketAddress addr = SocketAddress::getByName(listenAddr);
534  reinterpret_cast<sockaddr_in*>(&inetAddr)->sin_addr.s_addr =
535  reinterpret_cast<const sockaddr_in*>(addr.getInetAddress())->sin_addr.s_addr;
536  }
537  if (::bind(m_sockfd, reinterpret_cast<sockaddr*>(&inetAddr), sizeof(inetAddr)) == -1)
538  {
539  close();
540  BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): bind");
541  }
542  if (::listen(m_sockfd, queueSize) == -1)
543  {
544  close();
545  BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): listen");
546  }
547  fillAddrParms();
548  m_isActive = true;
549 }
550 
551 #ifdef BLOCXX_HAVE_IPV6
552 
553 void
554 ServerSocketImpl::doListenIPv6(UInt16 port, int queueSize, const String& listenAddr)
555 {
556  // use IPv6 protocol
557  InetSocketAddress_t inetAddr;
558  memset(&inetAddr, 0, sizeof(inetAddr));
559  reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_family = AF_INET6;
560  reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_port = hton16(port);
561  if (listenAddr == SocketAddress::ALL_LOCAL_ADDRESSES)
562  {
563  // copy IPv6 address any
564  memcpy(reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_addr.s6_addr, &in6addr_any, sizeof(struct in6_addr));
565  }
566  else
567  {
568  // create network address structure for IPv6 protocol
569  if(!inet_pton(AF_INET6, listenAddr.c_str(), (void*)&reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_addr))
570  {
571  addrinfo *addrinfos;
572  addrinfo hints;
573  memset(&hints, 0, sizeof(hints));
574  hints.ai_socktype = SOCK_STREAM;
575  hints.ai_family = AF_INET6;
576  if(getaddrinfo(listenAddr.c_str(), NULL, &hints, &addrinfos))
577  {
578  close();
579  BLOCXX_THROW_ERRNO_MSG(SocketException,"ServerSocketImpl::doListen(): getaddrinfo()");
580  }
581  memcpy(reinterpret_cast<sockaddr_in6*>(&inetAddr), addrinfos->ai_addr, addrinfos->ai_addrlen);
582  freeaddrinfo(addrinfos);
583  }
584  }
585  if (::bind(m_sockfd, reinterpret_cast<sockaddr*>(&inetAddr), sizeof(inetAddr)) == -1)
586  {
587  close();
588  BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): bind");
589  }
590  if (::listen(m_sockfd, queueSize) == -1)
591  {
592  close();
593  BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): listen");
594  }
595  fillAddrParms();
596  m_isActive = true;
597 }
598 #endif
599 
600 void
601 ServerSocketImpl::doListenUDS(const String& filename, int queueSize, bool reuseAddr)
602 {
604  close();
605  m_sockfd = ::socket(PF_UNIX,SOCK_STREAM, 0);
606  if (m_sockfd == INVALID_SOCKET)
607  {
608  BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): socket()");
609  }
610  // set the close on exec flag so child process can't keep the socket.
611  if (::fcntl(m_sockfd, F_SETFD, FD_CLOEXEC) == -1)
612  {
613  close();
614  BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): fcntl() failed to set "
615  "close-on-exec flag on listen socket");
616  }
617 
618  // set listen socket to nonblocking; see Unix Network Programming,
619  // pages 422-424.
620  int fdflags = ::fcntl(m_sockfd, F_GETFL, 0);
621  ::fcntl(m_sockfd, F_SETFL, fdflags | O_NONBLOCK);
622 
623  if (reuseAddr)
624  {
625  // Let the kernel reuse the port without waiting for it to time out.
626  // Without this line, you can't stop and immediately re-start the daemon.
627  int reuse = 1;
628 #if defined(BLOCXX_NCR)
629  ::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));
630 #else
631  ::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
632 #endif
633  }
634  String lockfilename = filename + ".lock";
635  m_udsFile = FileSystem::openOrCreateFile(lockfilename);
636  if (!m_udsFile)
637  {
639  Format("ServerSocketImpl::doListen(): Unable to open or create Unix Domain Socket lock: %1",
640  lockfilename).c_str());
641  }
642  // if we can't get a lock, someone else has got it open.
643  if (m_udsFile.tryLock() == -1)
644  {
646  Format("ServerSocketImpl::doListen(): Unable to lock Unix Domain Socket: %1",
647  filename).c_str());
648  }
649  // We got the lock, so clobber the UDS if it's there so bind will succeed.
650  // If it's not gone, bind will fail.
651  if (FileSystem::exists(filename))
652  {
653  if (!FileSystem::removeFile(filename.c_str()))
654  {
656  Format("ServerSocketImpl::doListen(): Unable to unlink Unix Domain Socket: %1",
657  filename).c_str());
658  }
659  }
660 
661 #if defined(BLOCXX_NCR)
662  if (::bind(m_sockfd, const_cast<SocketAddress_t *>(m_localAddress.getNativeForm()), m_localAddress.getNativeFormSize()) == -1)
663 #else
665 #endif
666  {
667  close();
668  BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): bind()");
669  }
670  // give anybody access to the socket
671  // unfortunately, fchmod() doesn't work on a UDS
672  if (::chmod(filename.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) == -1)
673  {
674  close();
675  BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): chmod()");
676  }
677  if (::listen(m_sockfd, queueSize) == -1)
678  {
679  close();
680  BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): listen()");
681  }
682  fillAddrParms();
683  m_isActive = true;
684 }
686 /*
687 String
688 ServerSocketImpl::addrString()
689 {
690  return inetAddrToString(m_localAddress, m_localPort);
691 }
692 */
694 Socket
696 {
697  if (!m_isActive)
698  {
699  BLOCXX_THROW(SocketException, "ServerSocketImpl::accept(): m_isActive == false");
700  }
701  int rc = 0;
703  {
704  int clntfd;
705  socklen_t clntlen;
706  InetSocketAddress_t clntInetAddr;
707  struct sockaddr_un clntUnixAddr;
708  struct sockaddr* pSA(0);
710  {
711  pSA = reinterpret_cast<struct sockaddr*>(&clntInetAddr);
712  clntlen = sizeof(clntInetAddr);
713  }
715  {
716  pSA = reinterpret_cast<struct sockaddr*>(&clntUnixAddr);
717  clntlen = sizeof(clntUnixAddr);
718  }
719  else
720  {
721  BLOCXX_ASSERT(0);
722  }
723 
724  clntfd = ::accept(m_sockfd, pSA, &clntlen);
725  if (clntfd < 0)
726  {
727  // check to see if client aborts connection between select and accept.
728  // see Unix Network Programming pages 422-424.
729  if (errno == EWOULDBLOCK
730  || errno == ECONNABORTED
731 #ifdef EPROTO
732  || errno == EPROTO
733 #endif
734  )
735  {
736  BLOCXX_THROW(SocketException, "Client aborted TCP connection "
737  "between select() and accept()");
738  }
739 
740  if (errno == EINTR)
741  {
743  }
744  BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::accept(): accept()");
745  }
746  // set socket back to blocking; see Unix Network Programming,
747  // pages 422-424.
748  int fdflags = ::fcntl(clntfd, F_GETFL, 0);
749  // On most OSs non-blocking is inherited from the listen socket,
750  // but it's not on Openserver.
751  if ((fdflags & O_NONBLOCK) == O_NONBLOCK)
752  {
753  ::fcntl(clntfd, F_SETFL, fdflags ^ O_NONBLOCK);
754  }
755  // TODO, how to make this bw compatible?
756  //return Socket(clntfd, m_localAddress.getType(), m_isSSL);
758  {
759  return Socket(clntfd, m_localAddress.getType(), m_isSSL); // for bw compat.
760  }
761  return Socket(clntfd, m_localAddress.getType(), m_sslCtx);
762  }
763  else if (rc == ETIMEDOUT)
764  {
765  // The timeout expired.
766  BLOCXX_THROW(SocketTimeoutException,"Timed out waiting for a connection");
767  }
768  else
769  {
770  BLOCXX_THROW_ERRNO_MSG(SocketException,"Timed out waiting for a connection");
771  }
772 }
773 #endif
774 
776 void
778 {
779  if (m_isActive)
780  {
781 #if defined(BLOCXX_WIN32)
782  ::closesocket(m_sockfd);
784 #else
785  ::close(m_sockfd);
787  {
788  String filename = m_localAddress.toString();
789  if (!FileSystem::removeFile(filename.c_str()))
790  {
792  Format("ServerSocketImpl::close(): Unable to unlink Unix Domain Socket: %1",
793  filename).c_str());
794  }
795  if (m_udsFile)
796  {
797  String lockfilename = filename + ".lock";
798  if (m_udsFile.unlock() == -1)
799  {
801  Format("ServerSocketImpl::close(): Failed to unlock Unix Domain Socket: %1",
802  lockfilename).c_str());
803  }
804  m_udsFile.close();
805  if (!FileSystem::removeFile(lockfilename.c_str()))
806  {
808  Format("ServerSocketImpl::close(): Unable to unlink Unix Domain Socket lock: %1",
809  lockfilename).c_str());
810  }
811  }
812  }
813 #endif
814  m_isActive = false;
815  }
816 }
818 void
820 {
821  socklen_t len;
823  {
824  // get information of local address for IPv6 protocol
825  struct sockaddr *p_addr;
827  memset(&ss, 0, sizeof(ss));
828  len = sizeof(ss);
829  p_addr = reinterpret_cast<struct sockaddr*>(&ss);
830  if (getsockname(m_sockfd, p_addr, &len) == -1)
831  {
832  BLOCXX_THROW_ERRNO_MSG(SocketException, "SocketImpl::fillAddrParms(): getsockname");
833  }
835  }
836 #if !defined(BLOCXX_WIN32)
838  {
839  struct sockaddr_un addr;
840  memset(&addr, 0, sizeof(addr));
841  len = sizeof(addr);
842  if (getsockname(m_sockfd, reinterpret_cast<struct sockaddr*>(&addr), &len) == -1)
843  {
844  BLOCXX_THROW_ERRNO_MSG(SocketException, "SocketImpl::fillAddrParms(): getsockname");
845  }
847  }
848 #endif
849  else
850  {
851  BLOCXX_ASSERT(0);
852  }
853 }
854 
855 } // end namespace BLOCXX_NAMESPACE
856