39 #include "blocxx/BLOCXX_config.h"
52 #if !defined(BLOCXX_WIN32)
53 #include <sys/types.h>
55 #include <sys/socket.h>
57 #include <netinet/in.h>
58 #include <arpa/inet.h>
63 #define INVALID_SOCKET -1
69 namespace BLOCXX_NAMESPACE
77 #if defined(BLOCXX_WIN32)
79 , m_shuttingDown(false)
81 m_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
96 #if defined(BLOCXX_WIN32)
98 , m_shuttingDown(false)
100 m_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
120 #if defined(BLOCXX_WIN32)
121 ::CloseHandle(m_event);
129 #if defined(BLOCXX_WIN32)
134 st.networkevents = FD_ACCEPT;
144 int queueSize,
const String& listenAddr,
148 doListen(port, queueSize,listenAddr, reuseAddr);
151 #if defined(BLOCXX_WIN32)
155 int queueSize,
const String& listenAddr,
162 #ifdef BLOCXX_HAVE_IPV6
165 sock_ipv6 = ::socket(AF_INET6, SOCK_STREAM, 0);
170 case EPROTONOSUPPORT:
174 m_sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
185 m_sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
189 BLOCXX_THROW(SocketException, Format(
"ServerSocketImpl: %1",
193 unsigned long cmdArg = 1;
194 if (::ioctlsocket(
m_sockfd, FIONBIO, &cmdArg) == SOCKET_ERROR)
196 BLOCXX_THROW(SocketException, Format(
"ServerSocketImpl: %1",
203 ::setsockopt(
m_sockfd, SOL_SOCKET, SO_REUSEADDR,
204 (
const char*)&reuse,
sizeof(reuse));
212 #ifdef BLOCXX_HAVE_IPV6
216 ServerSocketImpl::doListenIPv6( port, queueSize, listenAddr, reuseAddr);
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);
231 reinterpret_cast<sockaddr_in*
>(&inetAddr)->sin_addr.s_addr =
hton32(INADDR_ANY);
236 reinterpret_cast<sockaddr_in*
>(&inetAddr)->sin_addr.s_addr =
237 reinterpret_cast<const sockaddr_in*>(addr.getInetAddress())->sin_addr.s_addr;
239 if (::bind(
m_sockfd, reinterpret_cast<sockaddr*>(&inetAddr),
sizeof(inetAddr)) == -1)
242 BLOCXX_THROW(SocketException, Format(
"ServerSocketImpl: %1",
245 if (::listen(
m_sockfd, queueSize) == -1)
248 BLOCXX_THROW(SocketException, Format(
"ServerSocketImpl: %1",
255 #ifdef BLOCXX_HAVE_IPV6
257 ServerSocketImpl::doListenIPv6(UInt16 port,
int queueSize,
const String& listenAddr)
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);
267 memcpy(reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_addr.s6_addr, &in6addr_any,
sizeof(
struct in6_addr));
272 if(!inet_pton(AF_INET6, listenAddr.c_str(), (
void*)&reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_addr))
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))
282 BLOCXX_THROW(SocketException, Format(
"ServerSocketImpl:: doListen(): getaddrinfo() %1",
285 memcpy(reinterpret_cast<sockaddr_in6*>(&inetAddr), addrinfos->ai_addr, addrinfos->ai_addrlen);
286 freeaddrinfo(addrinfos);
289 if (::bind(
m_sockfd, reinterpret_cast<sockaddr*>(&inetAddr),
sizeof(inetAddr)) == -1)
292 BLOCXX_THROW(SocketException, Format(
"ServerSocketImpl: %1",
295 if (::listen(
m_sockfd, queueSize) == -1)
298 BLOCXX_THROW(SocketException, Format(
"ServerSocketImpl: %1",
304 #endif // BLOCXX_HAVE_IPV6
310 waitForAcceptIO(
SocketHandle_t fd, HANDLE eventArg,
const Timeout& timeOutSecs,
313 TimeoutTimer timer(timeOutSecs);
315 if (networkEvents != -1L)
317 if(::WSAEventSelect(fd, eventArg, networkEvents) != 0)
320 Format(
"WSAEventSelect failed in waitForAcceptIO: %1",
326 switch(::WaitForSingleObject(eventArg, timer.asDWORDMs()))
329 ::ResetEvent(eventArg);
353 BLOCXX_THROW(SocketException,
"ServerSocketImpl::accept: NONE");
357 if(::WSAEventSelect(
m_sockfd, m_event, FD_ACCEPT) != 0)
360 Format(
"WSAEventSelect failed in accept: %1",
372 clntlen =
sizeof(clntInetAddr);
374 reinterpret_cast<struct sockaddr*>(&clntInetAddr), &clntlen);
381 if (::WSAGetLastError() != WSAEWOULDBLOCK)
383 BLOCXX_THROW(SocketException, Format(
"ServerSocketImpl: %1",
388 cc = waitForAcceptIO(
m_sockfd, m_event, timeoutSecs, FD_ACCEPT);
397 BLOCXX_THROW(SocketException,
"Error while waiting for network events");
399 BLOCXX_THROW(SocketException,
"Shutdown event was signaled");
401 BLOCXX_THROW(SocketTimeoutException,
"Timed out waiting for a connection");
406 if(::WSAEventSelect(clntfd, NULL, 0) != 0)
409 Format(
"WSAEventSelect failed in accept: %1",
414 unsigned long cmdArg = 0;
415 if (::ioctlsocket(clntfd, FIONBIO, &cmdArg) == SOCKET_ERROR)
417 BLOCXX_THROW(SocketException, Format(
"ServerSocketImpl: %1",
432 int queueSize,
const String& listenAddr,
439 #ifdef BLOCXX_HAVE_IPV6
442 sock_ipv6 = ::socket(AF_INET6, SOCK_STREAM, 0);
447 case EPROTONOSUPPORT:
452 m_sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
462 int ipv6_proto = IPPROTO_IPV6;
467 ::setsockopt(
m_sockfd, ipv6_proto, IPV6_V6ONLY, &ipv6_only,
sizeof(ipv6_only));
471 m_sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
478 if (::fcntl(
m_sockfd, F_SETFD, FD_CLOEXEC) == -1)
482 "close-on-exec flag on listen socket");
486 int fdflags = ::fcntl(
m_sockfd, F_GETFL, 0);
487 ::fcntl(
m_sockfd, F_SETFL, fdflags | O_NONBLOCK);
499 #if defined(BLOCXX_NCR)
500 ::setsockopt(
m_sockfd, SOL_SOCKET, SO_REUSEADDR, (
char*)&reuse,
sizeof(reuse));
502 ::setsockopt(
m_sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse,
sizeof(reuse));
510 #ifdef BLOCXX_HAVE_IPV6
513 ServerSocketImpl::doListenIPv6( port, queueSize, listenAddr );
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);
529 reinterpret_cast<sockaddr_in*
>(&inetAddr)->sin_addr.s_addr =
hton32(INADDR_ANY);
534 reinterpret_cast<sockaddr_in*
>(&inetAddr)->sin_addr.s_addr =
535 reinterpret_cast<const sockaddr_in*>(addr.
getInetAddress())->sin_addr.s_addr;
537 if (::bind(
m_sockfd, reinterpret_cast<sockaddr*>(&inetAddr),
sizeof(inetAddr)) == -1)
542 if (::listen(
m_sockfd, queueSize) == -1)
551 #ifdef BLOCXX_HAVE_IPV6
554 ServerSocketImpl::doListenIPv6(UInt16 port,
int queueSize,
const String& listenAddr)
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);
564 memcpy(reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_addr.s6_addr, &in6addr_any,
sizeof(
struct in6_addr));
569 if(!inet_pton(AF_INET6, listenAddr.
c_str(), (
void*)&reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_addr))
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))
581 memcpy(reinterpret_cast<sockaddr_in6*>(&inetAddr), addrinfos->ai_addr, addrinfos->ai_addrlen);
582 freeaddrinfo(addrinfos);
585 if (::bind(
m_sockfd, reinterpret_cast<sockaddr*>(&inetAddr),
sizeof(inetAddr)) == -1)
590 if (::listen(
m_sockfd, queueSize) == -1)
605 m_sockfd = ::socket(PF_UNIX,SOCK_STREAM, 0);
611 if (::fcntl(
m_sockfd, F_SETFD, FD_CLOEXEC) == -1)
615 "close-on-exec flag on listen socket");
620 int fdflags = ::fcntl(
m_sockfd, F_GETFL, 0);
621 ::fcntl(
m_sockfd, F_SETFL, fdflags | O_NONBLOCK);
628 #if defined(BLOCXX_NCR)
629 ::setsockopt(
m_sockfd, SOL_SOCKET, SO_REUSEADDR, (
char *)&reuse,
sizeof(reuse));
631 ::setsockopt(
m_sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse,
sizeof(reuse));
634 String lockfilename = filename +
".lock";
639 Format(
"ServerSocketImpl::doListen(): Unable to open or create Unix Domain Socket lock: %1",
640 lockfilename).c_str());
646 Format(
"ServerSocketImpl::doListen(): Unable to lock Unix Domain Socket: %1",
656 Format(
"ServerSocketImpl::doListen(): Unable to unlink Unix Domain Socket: %1",
661 #if defined(BLOCXX_NCR)
672 if (::chmod(filename.
c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) == -1)
677 if (::listen(
m_sockfd, queueSize) == -1)
707 struct sockaddr_un clntUnixAddr;
708 struct sockaddr* pSA(0);
711 pSA =
reinterpret_cast<struct sockaddr*
>(&clntInetAddr);
712 clntlen =
sizeof(clntInetAddr);
716 pSA =
reinterpret_cast<struct sockaddr*
>(&clntUnixAddr);
717 clntlen =
sizeof(clntUnixAddr);
729 if (errno == EWOULDBLOCK
730 || errno == ECONNABORTED
737 "between select() and accept()");
748 int fdflags = ::fcntl(clntfd, F_GETFL, 0);
751 if ((fdflags & O_NONBLOCK) == O_NONBLOCK)
753 ::fcntl(clntfd, F_SETFL, fdflags ^ O_NONBLOCK);
781 #if defined(BLOCXX_WIN32)
792 Format(
"ServerSocketImpl::close(): Unable to unlink Unix Domain Socket: %1",
797 String lockfilename = filename +
".lock";
801 Format(
"ServerSocketImpl::close(): Failed to unlock Unix Domain Socket: %1",
802 lockfilename).c_str());
808 Format(
"ServerSocketImpl::close(): Unable to unlink Unix Domain Socket lock: %1",
809 lockfilename).c_str());
825 struct sockaddr *p_addr;
827 memset(&ss, 0,
sizeof(ss));
829 p_addr =
reinterpret_cast<struct sockaddr*
>(&ss);
830 if (getsockname(
m_sockfd, p_addr, &len) == -1)
836 #if !defined(BLOCXX_WIN32)
839 struct sockaddr_un addr;
840 memset(&addr, 0,
sizeof(addr));
842 if (getsockname(
m_sockfd, reinterpret_cast<struct sockaddr*>(&addr), &len) == -1)
const String toString() const
Returns the IP address and the port with a colon in between.
static SocketAddress allocEmptyAddress(AddressType type)
Allocate an empty SocketAddress.
const SocketAddress_t * getNativeForm() const
Socket accept(const Timeout &timeout)
size_t getNativeFormSize() const
#define BLOCXX_ASSERT(CON)
BLOCXX_ASSERT works similar to the assert() macro, but instead of calling abort(), it throws an AssertionException.
BLOCXX_COMMON_API File openOrCreateFile(const String &path)
Opens or creates the file for the given name.
This String class is an abstract data type that represents as NULL terminated string of characters...
String lastErrorMsg(bool socketError)
static SocketAddress getUDS(const String &filename)
ServerSocketImpl(SSLServerCtxRef sslCtx)
BLOCXX_COMMON_API bool removeFile(const String &path)
Remove the given file.
AddressType getType() const
int close()
Close the underlying file object.
BLOCXX_COMMON_API bool exists(const String &path)
static SocketAddress getByName(const String &host, unsigned short port=0)
Do a DNS lookup on a hostname and return an SocketAddress for that host.
void assignFromNativeForm(const UnixSocketAddress_t *address, size_t len)
static const char *const ALL_LOCAL_ADDRESSES
A timeout can be absolute, which means that it will happen at the specified DateTime.
const char * c_str() const
const InetSocketAddress_t * getInetAddress() const
Get a pointer to the InetSocketAddress_t precondition: getType() == INET.
SocketAddress m_localAddress
Select_t getSelectObj() const
sockaddr_in InetSocketAddress_t
void doListenUDS(const String &filename, int queueSize=10, bool reuseAddr=true)
void doListenIPv4(UInt16 port, int queueSize, const String &listenAddr)
#define BLOCXX_THROW(exType, msg)
Throw an exception using FILE and LINE.
int tryLock(ELockType type=E_WRITE_LOCK)
Acquire a kernel lock on the file.
int waitForIO(SocketHandle_t fd, int timeOutSecs, SocketFlags::EWaitDirectionFlag waitFlag)
Wait for input or output on a socket.
static void testCancel()
Test if this thread has been cancelled.
#define BLOCXX_THROW_ERRNO_MSG(exType, msg)
Throw an exception using FILE, LINE, errno and strerror(errno)
void doListen(UInt16 port, SocketFlags::ESSLFlag isSSL, int queueSize=10, const String &listenAddr=SocketAddress::ALL_LOCAL_ADDRESSES, SocketFlags::EReuseAddrFlag reuseAddr=SocketFlags::E_REUSE_ADDR)
SocketFlags::ESSLFlag m_isSSL
int unlock()
Release a lock on the file.