diff --git a/CMakeLists.txt b/CMakeLists.txt index 5fcf2d7..86e8a5b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.8.12...3.5) project(asl) -set(ASL_VERSION 1.11.10) +set(ASL_VERSION 1.11.11) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) @@ -38,7 +38,7 @@ option(ASL_BUILD_SHARED "Build shared library" ${ASL_BUILD_SHARED_HINT}) option(ASL_IPV6 "Expect also IPv6 when looking up DNS names") option(ASL_SAMPLES "Build samples") option(ASL_TESTS "Build tests") - +option(ASL_SOCKET_LOCAL "Support Unix sockets on Windows") if(ASL_TLS) if(TARGET MbedTLS::mbedtls) diff --git a/doc/doc.h b/doc/doc.h index 5ab4c79..cfb16e9 100644 --- a/doc/doc.h +++ b/doc/doc.h @@ -288,12 +288,10 @@ socket.connect(host, 80); socket << String(0, "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n", *path, *host); String response; char buffer[1001]; -while(true) +while(socket.connected()) { - if(!socket.waitInput()) + if(!socket.waitData()) continue; - if(socket.disconnected()) - break; int n = socket.read(buffer, min(socket.available(), 1000)); if(n <= 0) break; diff --git a/doc/doxy.ini b/doc/doxy.ini index 6122af6..1c6fb8d 100644 --- a/doc/doxy.ini +++ b/doc/doxy.ini @@ -235,7 +235,7 @@ EXPAND_ONLY_PREDEF = YES SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = -PREDEFINED = _WIN32 ASL_EXP_THREADING ASL_TLS ASL_API ASL_HAVE_INITLIST ASL_HAVE_INITLIST2 DOXYGEN_SHOULD_SKIP_THIS _MSC_VER=1800 ASL_EXPLICIT=explicit ASL_DEPRECATED= ASL_PRINTF_W1= +PREDEFINED = _WIN32 ASL_EXP_THREADING ASL_TLS ASL_API ASL_HAVE_INITLIST ASL_HAVE_INITLIST2 DOXYGEN_SHOULD_SKIP_THIS _MSC_VER=1800 ASL_EXPLICIT=explicit ASL_DEPRECATED= ASL_PRINTF_W1= ASL_SOCKET_LOCAL EXPAND_AS_DEFINED = YES SKIP_FUNCTION_MACROS = NO diff --git a/include/asl/Socket.h b/include/asl/Socket.h index 499df77..fbd3134 100644 --- a/include/asl/Socket.h +++ b/include/asl/Socket.h @@ -138,7 +138,7 @@ ASL_SMART_CLASS(Socket, SmartObject) }; /** -A Socket is a communication socket for TCP protocol. +A communication socket for the TCP/IP protocol. \ingroup Sockets */ class ASL_API Socket : public SmartObject @@ -174,6 +174,11 @@ class ASL_API Socket : public SmartObject */ bool disconnected() { return _()->disconnected(); } + /** + Checks if the connection is open. + */ + bool connected() { return !disconnected(); } + /** Binds this socket to the given IP address and port number. */ @@ -369,7 +374,7 @@ ASL_SMART_CLASS(PacketSocket, Socket) }; /** -A PacketSocket is a communication socket for UDP protocol. +A communication socket for UDP/IP protocol. \ingroup Sockets A listening side binds to a port and receives packets. The readFrom() functions also @@ -434,7 +439,7 @@ class ASL_API PacketSocket : public Socket } }; -#if !defined(_WIN32) || defined(ASL_SOCKETLOCAL) +#if !defined(_WIN32) || defined(ASL_SOCKET_LOCAL) ASL_SMART_CLASS(LocalSocket, Socket) { @@ -442,10 +447,31 @@ ASL_SMART_CLASS(LocalSocket, Socket) LocalSocket_(); LocalSocket_(int fd); ~LocalSocket_(); - String _pathname; bool bind(const String& name); + Socket_* accept(); }; +/** +A Local or Unix socket for inter-process communication within a machine. + +Works similar to a TCP socket but it is bound to a local path in the file system. + +Used to be Unix/Linux-only but is also supported on recent Windows 10+ versions (need to +enable CMAKE_SOCKET_LOCAL on Windows) + +``` +LocalSocket server; +server.bind("/dir/comm.sock"); +server.listen(); +LocalSocket client = server.accept(); +... + +LocalSocket client; +client.connect("/dir/comm.sock"); +client << "Hello\n"; +``` +\ingroup Sockets +*/ class ASL_API LocalSocket : public Socket { public: @@ -465,7 +491,7 @@ ASL_SMART_CLASS(MulticastSocket, PacketSocket) }; /** -A MulticastSocket is a communication socket for multicast UDP protocol. +A communication socket for multicast UDP/IP protocol. A socket can send packets to a multicast group and port, and another socket can join the group so it receives packets sent to it. diff --git a/include/asl/SocketServer.h b/include/asl/SocketServer.h index 55ebc13..c4e1b4b 100644 --- a/include/asl/SocketServer.h +++ b/include/asl/SocketServer.h @@ -12,7 +12,7 @@ struct SockServerThread; struct SockClientThread; /** -This is a reusable TCP socket server that listens to incoming connections and answers them concurrently (default) or sequentially. +This is a reusable TCP or Unix socket server that listens to incoming connections and answers them concurrently (default) or sequentially. To make an actual server, derive a class from it and implement the virtual function `serve()`. That function will be called whenever a new connection arrives. @@ -46,7 +46,7 @@ For long-running connections, the recommended way of dealing with possible disco ~~~ void serve(Socket client) { - while (!client.disconnected()) + while (client.connected()) { if (!client.waitData()) continue; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 583932e..0dcff5a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -92,6 +92,10 @@ if( ASL_USE_LOCAL8BIT ) list(APPEND ASL_DEFS ASL_ANSI) endif() +if(ASL_SOCKET_LOCAL) + list(APPEND ASL_DEFS ASL_SOCKET_LOCAL) +endif() + if(POLICY CMP0022) cmake_policy(SET CMP0022 NEW) endif() diff --git a/src/Socket.cpp b/src/Socket.cpp index 8959120..dd0670f 100644 --- a/src/Socket.cpp +++ b/src/Socket.cpp @@ -5,7 +5,7 @@ struct IUnknown; // Workaround for "combaseapi.h(229): error C2187: syntax error: 'identifier' was unexpected here" with /permissive- #include #include -#ifdef ASL_SOCKETLOCAL +#ifdef ASL_SOCKET_LOCAL #include #endif #include @@ -20,6 +20,9 @@ struct IUnknown; // Workaround for "combaseapi.h(229): error C2187: syntax error #include #include #include +#ifndef ASL_SOCKET_LOCAL +#define ASL_SOCKET_LOCAL +#endif #endif #include @@ -139,7 +142,7 @@ inline int sockfamily(InetAddress::Type t) { case InetAddress::IPv4: return AF_INET; case InetAddress::IPv6: return AF_INET6; -#if !defined(_WIN32) || defined(ASL_SOCKETLOCAL) +#ifdef ASL_SOCKET_LOCAL case InetAddress::LOCAL: return AF_UNIX; #endif default:; @@ -155,7 +158,7 @@ InetAddress::InetAddress(InetAddress::Type t) { case IPv4: n = sizeof(sockaddr_in); break; case IPv6: n = sizeof(sockaddr_in6); break; -#if !defined(_WIN32) || defined(ASL_SOCKETLOCAL) +#ifdef ASL_SOCKET_LOCAL case LOCAL: n = sizeof(sockaddr_un); break; #endif default: ; @@ -210,7 +213,7 @@ String InetAddress::host() const byte* ip = (byte*)&addr->sin_addr; return String::f("%i.%i.%i.%i", ip[0], ip[1], ip[2], ip[3]); } -#if !defined(_WIN32) || defined(ASL_SOCKETLOCAL) +#ifdef ASL_SOCKET_LOCAL else if (_type == LOCAL) { sockaddr_un* addr = (sockaddr_un*)ptr(); @@ -347,7 +350,7 @@ HostPort parseHostPort(const String& u) } else { int i = u.lastIndexOf(':'); - if (i > 0) { + if (i > 1) { hostend = i; portstart = i + 1; } @@ -366,13 +369,14 @@ bool InetAddress::set(const String& host) thehost = '[' + host + ']'; HostPort hp = parseHostPort(thehost); - if(!hp.port.ok() && hp.host.contains('/')) + if (!hp.port.ok() && (hp.host.contains('/') || hp.host.contains('\\'))) { -#ifndef _WIN32 +#ifdef ASL_SOCKET_LOCAL resize(sizeof(sockaddr_un)); sockaddr_un* a=(sockaddr_un*)ptr(); a->sun_family=AF_UNIX; - strcpy(a->sun_path, host.substring(0, min(107, host.length()))); + memcpy(a->sun_path, *host, min((int)sizeof(a->sun_path), host.length() + 1)); + a->sun_path[sizeof(a->sun_path) - 1] = '\0'; _type = LOCAL; return true; #endif @@ -382,7 +386,6 @@ bool InetAddress::set(const String& host) // Socket - Socket_::Socket_() { #ifdef _WIN32 @@ -398,6 +401,10 @@ Socket_::Socket_() Socket_::Socket_(int fd) { +#ifdef _WIN32 + if (!g_wsaStarted) + startWSA(); +#endif _handle = fd; _family = InetAddress::IPv4; _error = 0; @@ -640,7 +647,7 @@ void Socket_::skip(int n) bool Socket_::disconnected() { - return _error != 0 || (waitInput(0) && available() <= 0); + return _handle < 0 || _error != 0 || (waitInput(0) && available() <= 0); } bool Socket_::waitInput(double t) @@ -719,7 +726,7 @@ void PacketSocket_::sendTo(const InetAddress& to, const void* data, int n) sendto(_handle, (const char*)data, n, 0, (sockaddr*)to.ptr(), to.length()); } -#if !defined(_WIN32) || defined(ASL_SOCKETLOCAL) +#ifdef ASL_SOCKET_LOCAL // LocalSocket (UNIX) @@ -737,21 +744,28 @@ LocalSocket_::LocalSocket_(int fd) : Socket_(fd) LocalSocket_::~LocalSocket_() { - if(_pathname) + String path = localAddress().toString(); + if (path) { close(); - unlink(_pathname); +#ifdef _WIN32 + DeleteFileW(path); +#else + unlink(path); +#endif } } bool LocalSocket_::bind(const String& name) { - _pathname=name; +#ifdef _WIN32 + DeleteFileW(name); +#else unlink(name); +#endif init(); - setOption(SOL_SOCKET, SO_REUSEADDR, 1); InetAddress here(name); - if(::bind(_handle, (sockaddr*)here.ptr(), here.length())) + if (::bind(_handle, (sockaddr*)here.ptr(), sizeof(sockaddr_un))) { verbose_print("Can't bind to %s\n", *name); return false; @@ -759,6 +773,11 @@ bool LocalSocket_::bind(const String& name) return true; } +Socket_* LocalSocket_::accept() +{ + return new LocalSocket_((int)::accept(_handle, (sockaddr*)0, (socklen_t*)0)); +} + #endif }