diff --git a/autotest/UnixSocket/UnixSocket.cpp b/autotest/UnixSocket/UnixSocket.cpp new file mode 100644 index 000000000..eedb320fe --- /dev/null +++ b/autotest/UnixSocket/UnixSocket.cpp @@ -0,0 +1,51 @@ +#include + +using namespace Upp; + +CONSOLE_APP_MAIN +{ +#ifdef PLATFORM_POSIX + + StdLogSetup(LOG_COUT|LOG_FILE); + + String path = Format("/tmp/upp-unixsocket-test-%d", getpid()); + + Socket server, client; + + // Test server listen + if(!server.ListenFileSystem(path)) { + LOG("Server listen failed: " << server.GetErrorDesc()); + Exit(1); + } + + // Test client connect + if(!client.ConnectFileSystem(path)) { + LOG("Client connect failed: " << client.GetErrorDesc()); + Exit(1); + } + + // Test data exchange + String test_data = "Hello, world!"; + client.Put(test_data + "\n"); + + Socket accepted; + if(!accepted.Accept(server)) { + LOG("Accept failed: " << accepted.GetErrorDesc()); + Exit(1); + } + + String received = accepted.GetLine(); + DUMP(received); + + ASSERT(received == test_data); + + // Test peer PID (on supported platforms) + int pid = accepted.GetPeerPid(); + DUMP(pid); + if(pid != -1) + ASSERT(pid == getpid()); // Should be our own process in this test + + LOG("=========== OK"); + +#endif +} \ No newline at end of file diff --git a/autotest/UnixSocket/UnixSocket.upp b/autotest/UnixSocket/UnixSocket.upp new file mode 100644 index 000000000..40be02c93 --- /dev/null +++ b/autotest/UnixSocket/UnixSocket.upp @@ -0,0 +1,9 @@ +uses + Core; + +file + UnixSocket.cpp; + +mainconfig + "" = ""; + diff --git a/reference/UnixSocketClient/UnixSocketClient.cpp b/reference/UnixSocketClient/UnixSocketClient.cpp new file mode 100644 index 000000000..2e7cd8b5e --- /dev/null +++ b/reference/UnixSocketClient/UnixSocketClient.cpp @@ -0,0 +1,28 @@ +#include + +using namespace Upp; + +// Start reference/UnixSocketServer before starting this program + +CONSOLE_APP_MAIN +{ +#ifdef PLATFORM_POSIX + auto Request = [](const String& r) + { + Socket s; + if(!s.ConnectFileSystem("/tmp/upp-unixsocket.sock")) { + Cout() << "Unable to connect to server!\n"; + SetExitCode(1); + return String(); + } + s.Put(r + '\n'); + return s.GetLine(); + }; + + Cout() << Request("time") << '\n'; + Cout() << Request("33") << '\n'; +#else + Cout() << "This example requires a POSIX compliant operating system...\r\n" + SetExitCode(1); +#endif +} diff --git a/reference/UnixSocketClient/UnixSocketClient.upp b/reference/UnixSocketClient/UnixSocketClient.upp new file mode 100644 index 000000000..d400e318f --- /dev/null +++ b/reference/UnixSocketClient/UnixSocketClient.upp @@ -0,0 +1,11 @@ +description "Example of using client UnixSocket - its counterpart is UnixSocketServer\377"; + +uses + Core; + +file + UnixSocketClient.cpp; + +mainconfig + "" = ""; + diff --git a/reference/UnixSocketServer/UnixSocketServer.cpp b/reference/UnixSocketServer/UnixSocketServer.cpp new file mode 100644 index 000000000..6c41ebe97 --- /dev/null +++ b/reference/UnixSocketServer/UnixSocketServer.cpp @@ -0,0 +1,33 @@ +#include + +using namespace Upp; + +CONSOLE_APP_MAIN +{ +#ifdef PLATFORM_POSIX + const String& path = "/tmp/upp-unixsocket.sock"; + + Socket server; + if(!server.ListenFileSystem(path, 5)) { + Cout() << "Unable to initialize server socket!\n"; + SetExitCode(1); + return; + } + Cout() << "Waiting for requests..\n"; + for(;;) { + Socket s; + if(s.Accept(server)) { + String w = s.GetLine(); + Cout() << "Request: " << w << " from: " << s.GetPeerPid() << '\n'; + if(w == "time") + s.Put(AsString(GetSysTime())); + else + s.Put(AsString(3 * atoi(~w))); + s.Put("\n"); + } + } +#else + Cout() << "This example requires a POSIX compliant operating system...\r\n" + SetExitCode(1); +#endif +} diff --git a/reference/UnixSocketServer/UnixSocketServer.upp b/reference/UnixSocketServer/UnixSocketServer.upp new file mode 100644 index 000000000..f97e7b19a --- /dev/null +++ b/reference/UnixSocketServer/UnixSocketServer.upp @@ -0,0 +1,11 @@ +description "Example of using server UnixSocket - its counterpart is UnixSocketClient\377"; + +uses + Core; + +file + UnixSocketServer.cpp; + +mainconfig + "" = ""; + diff --git a/uppsrc/Core/Core.h b/uppsrc/Core/Core.h index 8ed7866e4..b8c68ff09 100644 --- a/uppsrc/Core/Core.h +++ b/uppsrc/Core/Core.h @@ -221,6 +221,7 @@ #define W_P(w, p) p #include #include +#include #include #include //#include diff --git a/uppsrc/Core/Inet.h b/uppsrc/Core/Inet.h index 3e0e7f600..c4bd9442d 100644 --- a/uppsrc/Core/Inet.h +++ b/uppsrc/Core/Inet.h @@ -87,7 +87,7 @@ struct SSLInfo { enum { WAIT_READ = 1, WAIT_WRITE = 2, WAIT_IS_EXCEPTION = 4 }; -class TcpSocket : NoCopy { +class Socket : NoCopy { enum { BUFFERSIZE = 512 }; enum { NONE, CONNECT, ACCEPT, SSL_CONNECTED }; SOCKET socket; @@ -136,8 +136,8 @@ class TcpSocket : NoCopy { struct SSLImp; friend struct SSLImp; - static SSL *(*CreateSSL)(TcpSocket& socket); - static SSL *CreateSSLImp(TcpSocket& socket); + static SSL *(*CreateSSL)(Socket& socket); + static SSL *CreateSSLImp(Socket& socket); friend void InitCreateSSL(); friend class IpAddrInfo; @@ -172,7 +172,12 @@ class TcpSocket : NoCopy { static int GetErrorCode(); static void Init(); - TcpSocket(const TcpSocket&); +#ifdef PLATFORM_POSIX // Unix domain socket support + bool NixConnect(const String& path, bool abstract); + bool NixListen(const String& path, int n, bool reuse, bool abstract); +#endif + + Socket(const Socket&); public: Event<> WhenWait; @@ -208,10 +213,18 @@ public: bool WaitConnect(); bool Listen(int port, int listen_count = 5, bool ipv6 = false, bool reuse = true, void* addr = NULL); bool Listen(const IpAddrInfo& addr, int port, int listen_count = 5, bool ipv6 = false, bool reuse = true); - bool Accept(TcpSocket& listen_socket); + bool Accept(Socket& listen_socket); void Close(); void Shutdown(); +#ifdef PLATFORM_POSIX + int GetPeerPid() const; + bool ConnectFileSystem(const String& path); + bool ConnectAbstract(const String& path); + bool ListenFileSystem(const String& path, int listen_count = 5, bool reuse = true); + bool ListenAbstract(const String& path, int listen_count = 5, bool reuse = true); +#endif + void NoDelay(); void Linger(int msecs); void NoLinger() { Linger(Null); } @@ -247,19 +260,21 @@ public: void Clear(); - TcpSocket& Timeout(int ms) { timeout = ms; return *this; } + Socket& Timeout(int ms) { timeout = ms; return *this; } int GetTimeout() const { return timeout; } - TcpSocket& GlobalTimeout(int ms); - TcpSocket& NoGlobalTimeout() { return GlobalTimeout(Null); } - TcpSocket& Blocking() { return Timeout(Null); } + Socket& GlobalTimeout(int ms); + Socket& NoGlobalTimeout() { return GlobalTimeout(Null); } + Socket& Blocking() { return Timeout(Null); } bool IsBlocking() { return IsNull(GetTimeout()); } - TcpSocket& WaitStep(int ms) { waitstep = ms; return *this; } + Socket& WaitStep(int ms) { waitstep = ms; return *this; } int GetWaitStep() const { return waitstep; } - TcpSocket(); - ~TcpSocket() { Close(); } + Socket(); + virtual ~Socket() { Close(); } }; +using TcpSocket = Socket; // Backward compatibility + class SocketWaitEvent { Vector> socket; fd_set read[1], write[1], exception[1]; @@ -268,7 +283,7 @@ class SocketWaitEvent { public: void Clear() { socket.Clear(); } void Add(SOCKET s, dword events) { socket.Add(MakeTuple((int)s, events)); } - void Add(TcpSocket& s, dword events) { Add(s.GetSOCKET(), events); } + void Add(Socket& s, dword events) { Add(s.GetSOCKET(), events); } int Wait(int timeout); dword Get(int i) const; dword operator[](int i) const { return Get(i); } diff --git a/uppsrc/Core/SSL/InitExit.cpp b/uppsrc/Core/SSL/InitExit.cpp index 5f2c6cd6b..5d333aaaf 100644 --- a/uppsrc/Core/SSL/InitExit.cpp +++ b/uppsrc/Core/SSL/InitExit.cpp @@ -81,13 +81,13 @@ static void *SslRealloc(void *ptr, size_t size) #endif -void TcpSocketInit(); +void SocketInit(); INITIALIZER(SSL) { MemoryIgnoreLeaksBlock __; LLOG("SslInit"); - TcpSocketInit(); + SocketInit(); #ifdef UPP_HEAP #ifndef flagSSL_USEMALLOC // do not change OpenSSL memory functions to U++ heap #ifndef _DEBUG // temporary solution unless we find the source of all those harmless leaks diff --git a/uppsrc/Core/Socket.cpp b/uppsrc/Core/Socket.cpp index 32bd867be..252bbcaf5 100644 --- a/uppsrc/Core/Socket.cpp +++ b/uppsrc/Core/Socket.cpp @@ -161,7 +161,7 @@ void IpAddrInfo::Clear() IpAddrInfo::IpAddrInfo() { - TcpSocket::Init(); + Socket::Init(); entry = NULL; } @@ -169,12 +169,12 @@ IpAddrInfo::IpAddrInfo() #define SOCKERR(x) x -const char *TcpSocketErrorDesc(int code) +const char *SocketErrorDesc(int code) { return strerror(code); } -int TcpSocket::GetErrorCode() +int Socket::GetErrorCode() { return errno; } @@ -183,7 +183,7 @@ int TcpSocket::GetErrorCode() #define SOCKERR(x) WSA##x -const char *TcpSocketErrorDesc(int code) +const char *SocketErrorDesc(int code) { static Tuple err[] = { { WSAEINTR, "Interrupted function call." }, @@ -194,13 +194,13 @@ const char *TcpSocketErrorDesc(int code) { WSAEWOULDBLOCK, "Resource temporarily unavailable." }, { WSAEINPROGRESS, "Operation now in progress." }, { WSAEALREADY, "Operation already in progress." }, - { WSAENOTSOCK, "TcpSocket operation on nonsocket." }, + { WSAENOTSOCK, "Socket operation on nonsocket." }, { WSAEDESTADDRREQ, "Destination address required." }, { WSAEMSGSIZE, "Message too long." }, { WSAEPROTOTYPE, "Protocol wrong type for socket." }, { WSAENOPROTOOPT, "Bad protocol option." }, { WSAEPROTONOSUPPORT, "Protocol not supported." }, - { WSAESOCKTNOSUPPORT, "TcpSocket type not supported." }, + { WSAESOCKTNOSUPPORT, "Socket type not supported." }, { WSAEOPNOTSUPP, "Operation not supported." }, { WSAEPFNOSUPPORT, "Protocol family not supported." }, { WSAEAFNOSUPPORT, "Address family not supported by protocol family." }, @@ -212,8 +212,8 @@ const char *TcpSocketErrorDesc(int code) { WSAECONNABORTED, "Software caused connection abort." }, { WSAECONNRESET, "Connection reset by peer." }, { WSAENOBUFS, "No buffer space available." }, - { WSAEISCONN, "TcpSocket is already connected." }, - { WSAENOTCONN, "TcpSocket is not connected." }, + { WSAEISCONN, "Socket is already connected." }, + { WSAENOTCONN, "Socket is not connected." }, { WSAESHUTDOWN, "Cannot send after socket shutdown." }, { WSAETIMEDOUT, "Connection timed out." }, { WSAECONNREFUSED, "Connection refused." }, @@ -235,14 +235,14 @@ const char *TcpSocketErrorDesc(int code) return x ? x->b : "Unknown error code."; } -int TcpSocket::GetErrorCode() +int Socket::GetErrorCode() { return WSAGetLastError(); } #endif -void TcpSocketInit() +void SocketInit() { #ifdef PLATFORM_WIN32 ONCELOCK { @@ -255,12 +255,12 @@ void TcpSocketInit() #endif } -void TcpSocket::Init() +void Socket::Init() { - TcpSocketInit(); + SocketInit(); } -void TcpSocket::Reset() +void Socket::Reset() { LLOG("Reset"); is_eof = false; @@ -280,7 +280,7 @@ void TcpSocket::Reset() ssl_start = Null; } -TcpSocket::TcpSocket() +Socket::Socket() { ClearError(); Reset(); @@ -289,7 +289,7 @@ TcpSocket::TcpSocket() asn1 = false; } -bool TcpSocket::SetupSocket() +bool Socket::SetupSocket() { #ifdef PLATFORM_WIN32 connection_start = msecs(); @@ -310,7 +310,7 @@ bool TcpSocket::SetupSocket() return true; } -bool TcpSocket::Open(int family, int type, int protocol) +bool Socket::Open(int family, int type, int protocol) { Init(); Close(); @@ -319,11 +319,11 @@ bool TcpSocket::Open(int family, int type, int protocol) SetSockError("open"); return false; } - LLOG("TcpSocket::Data::Open() -> " << (int)socket); + LLOG("Socket::Data::Open() -> " << (int)socket); return SetupSocket(); } -bool TcpSocket::Listen(int port, int listen_count, bool ipv6_, bool reuse, void *addr) +bool Socket::Listen(int port, int listen_count, bool ipv6_, bool reuse, void *addr) { Close(); Init(); @@ -368,13 +368,13 @@ bool TcpSocket::Listen(int port, int listen_count, bool ipv6_, bool reuse, void return true; } -bool TcpSocket::Listen(const IpAddrInfo& addr, int port, int listen_count, bool ipv6, bool reuse) +bool Socket::Listen(const IpAddrInfo& addr, int port, int listen_count, bool ipv6, bool reuse) { addrinfo *a = addr.GetResult(); return Listen(port, listen_count, ipv6, reuse, &(((sockaddr_in*)a->ai_addr)->sin_addr.s_addr)); } -bool TcpSocket::Accept(TcpSocket& ls) +bool Socket::Accept(Socket& ls) { Close(); Init(); @@ -399,7 +399,7 @@ bool TcpSocket::Accept(TcpSocket& ls) return SetupSocket(); } -String TcpSocket::GetPeerAddr() const +String Socket::GetPeerAddr() const { if(!IsOpen()) return Null; @@ -417,7 +417,7 @@ String TcpSocket::GetPeerAddr() const #endif } -void TcpSocket::NoDelay() +void Socket::NoDelay() { ASSERT(IsOpen()); int __true = 1; @@ -426,7 +426,7 @@ void TcpSocket::NoDelay() SetSockError("setsockopt(TCP_NODELAY)"); } -void TcpSocket::Linger(int msecs) +void Socket::Linger(int msecs) { ASSERT(IsOpen()); linger ls; @@ -436,13 +436,13 @@ void TcpSocket::Linger(int msecs) SetSockError("setsockopt(SO_LINGER)"); } -void TcpSocket::Attach(SOCKET s) +void Socket::Attach(SOCKET s) { Close(); socket = s; } -bool TcpSocket::RawConnect(addrinfo *arp) +bool Socket::RawConnect(addrinfo *arp) { if(!arp) { SetSockError("connect", -1, "not found"); @@ -462,7 +462,7 @@ bool TcpSocket::RawConnect(addrinfo *arp) } if(err.GetCount()) err << '\n'; - err << TcpSocketErrorDesc(GetErrorCode()); + err << SocketErrorDesc(GetErrorCode()); Close(); } rp = rp->ai_next; @@ -473,7 +473,7 @@ bool TcpSocket::RawConnect(addrinfo *arp) } -bool TcpSocket::Connect(IpAddrInfo& info) +bool Socket::Connect(IpAddrInfo& info) { LLOG("Connect addrinfo"); Init(); @@ -482,7 +482,7 @@ bool TcpSocket::Connect(IpAddrInfo& info) return RawConnect(result); } -bool TcpSocket::Connect(const char *host, int port) +bool Socket::Connect(const char *host, int port) { LLOG("Connect(" << host << ':' << port << ')'); Close(); @@ -496,7 +496,7 @@ bool TcpSocket::Connect(const char *host, int port) return Connect(info); } -bool TcpSocket::WaitConnect() +bool Socket::WaitConnect() { if(WaitWrite()) { int optval = 0; @@ -505,7 +505,7 @@ bool TcpSocket::WaitConnect() if (optval == 0) return true; else { - SetSockError("wait connect", -1, Nvl(String(TcpSocketErrorDesc(optval)), "failed")); + SetSockError("wait connect", -1, Nvl(String(SocketErrorDesc(optval)), "failed")); return false; } } @@ -513,7 +513,7 @@ bool TcpSocket::WaitConnect() return false; } -void TcpSocket::RawClose() +void Socket::RawClose() { LLOG("close " << (int)socket); if(socket != INVALID_SOCKET) { @@ -531,7 +531,7 @@ void TcpSocket::RawClose() } } -void TcpSocket::Close() +void Socket::Close() { if(ssl) ssl->Close(); @@ -540,7 +540,7 @@ void TcpSocket::Close() ssl.Clear(); } -bool TcpSocket::WouldBlock() +bool Socket::WouldBlock() { int c = GetErrorCode(); #ifdef PLATFORM_POSIX @@ -559,7 +559,7 @@ bool TcpSocket::WouldBlock() #endif } -int TcpSocket::RawSend(const void *buf, int amount) +int Socket::RawSend(const void *buf, int amount) { #ifdef PLATFORM_LINUX int res = send(socket, (const char *)buf, amount, MSG_NOSIGNAL); @@ -574,21 +574,21 @@ int TcpSocket::RawSend(const void *buf, int amount) return res; } -int TcpSocket::Send(const void *buf, int amount) +int Socket::Send(const void *buf, int amount) { if(SSLHandshake()) return 0; return ssl ? ssl->Send(buf, amount) : RawSend(buf, amount); } -void TcpSocket::Shutdown() +void Socket::Shutdown() { ASSERT(IsOpen()); if(shutdown(socket, SD_SEND)) SetSockError("shutdown(SD_SEND)"); } -String TcpSocket::GetHostName() +String Socket::GetHostName() { Init(); char buffer[256]; @@ -596,7 +596,7 @@ String TcpSocket::GetHostName() return buffer; } -bool TcpSocket::IsGlobalTimeout() +bool Socket::IsGlobalTimeout() { if(!IsNull(global_timeout) && msecs() - start_time > global_timeout) { SetSockError("wait", ERROR_GLOBAL_TIMEOUT, "Timeout"); @@ -605,7 +605,7 @@ bool TcpSocket::IsGlobalTimeout() return false; } -bool TcpSocket::RawWait(dword flags, int end_time) +bool Socket::RawWait(dword flags, int end_time) { // wait till end_time LLOG("RawWait end_time: " << end_time << ", current time " << msecs() << ", to wait: " << end_time - msecs()); is_timeout = false; @@ -661,19 +661,19 @@ bool TcpSocket::RawWait(dword flags, int end_time) } } -TcpSocket& TcpSocket::GlobalTimeout(int ms) +Socket& Socket::GlobalTimeout(int ms) { start_time = msecs(); global_timeout = ms; return *this; } -bool TcpSocket::Wait(dword flags, int end_time) +bool Socket::Wait(dword flags, int end_time) { return ssl ? ssl->Wait(flags, end_time) : RawWait(flags, end_time); } -int TcpSocket::GetEndTime() const +int Socket::GetEndTime() const { // Compute time limit for operation, based on global timeout and per-operation timeout settings int o = min(IsNull(global_timeout) ? INT_MAX : start_time + global_timeout, IsNull(timeout) ? INT_MAX : msecs() + timeout); @@ -685,12 +685,12 @@ int TcpSocket::GetEndTime() const return o; } -bool TcpSocket::Wait(dword flags) +bool Socket::Wait(dword flags) { return Wait(flags, GetEndTime()); } -int TcpSocket::Put(const void *s_, int length) +int Socket::Put(const void *s_, int length) { LLOG("Put " << socket << ": " << length); ASSERT(IsOpen()); @@ -718,7 +718,7 @@ int TcpSocket::Put(const void *s_, int length) return done; } -bool TcpSocket::PutAll(const void *s, int len) +bool Socket::PutAll(const void *s, int len) { if(Put(s, len) != len) { if(!IsError()) @@ -728,7 +728,7 @@ bool TcpSocket::PutAll(const void *s, int len) return true; } -bool TcpSocket::PutAll(const String& s) +bool Socket::PutAll(const String& s) { if(Put(s) != s.GetCount()) { if(!IsError()) @@ -738,7 +738,7 @@ bool TcpSocket::PutAll(const String& s) return true; } -int TcpSocket::RawRecv(void *buf, int amount) +int Socket::RawRecv(void *buf, int amount) { int res = recv(socket, (char *)buf, amount, 0); if(res == 0) @@ -755,26 +755,26 @@ int TcpSocket::RawRecv(void *buf, int amount) return res; } -int TcpSocket::Recv(void *buffer, int maxlen) +int Socket::Recv(void *buffer, int maxlen) { if(SSLHandshake()) return 0; return ssl ? ssl->Recv(buffer, maxlen) : RawRecv(buffer, maxlen); } -void TcpSocket::ReadBuffer(int end_time) +void Socket::ReadBuffer(int end_time) { ptr = end = buffer; if(Wait(WAIT_READ, end_time)) end = buffer + Recv(buffer, BUFFERSIZE); } -bool TcpSocket::IsEof() const +bool Socket::IsEof() const { return is_eof && ptr == end || IsAbort() || !IsOpen() || IsError(); } -int TcpSocket::Get_() +int Socket::Get_() { if(!IsOpen() || IsError() || IsEof() || IsAbort()) return -1; @@ -782,7 +782,7 @@ int TcpSocket::Get_() return ptr < end ? (byte)*ptr++ : -1; } -int TcpSocket::Peek_(int end_time) +int Socket::Peek_(int end_time) { if(!IsOpen() || IsError() || IsEof() || IsAbort()) return -1; @@ -790,12 +790,12 @@ int TcpSocket::Peek_(int end_time) return ptr < end ? (byte)*ptr : -1; } -int TcpSocket::Peek_() +int Socket::Peek_() { return Peek_(GetEndTime()); } -int TcpSocket::Get(void *buffer, int count) +int Socket::Get(void *buffer, int count) { LLOG("Get " << count); @@ -829,7 +829,7 @@ int TcpSocket::Get(void *buffer, int count) return done; } -String TcpSocket::Get(int count) +String Socket::Get(int count) { if(count == 0) return Null; @@ -841,7 +841,7 @@ String TcpSocket::Get(int count) return String(out); } -bool TcpSocket::GetAll(void *buffer, int len) +bool Socket::GetAll(void *buffer, int len) { if(Get(buffer, len) == len) return true; @@ -850,7 +850,7 @@ bool TcpSocket::GetAll(void *buffer, int len) return false; } -String TcpSocket::GetAll(int len) +String Socket::GetAll(int len) { String s = Get(len); if(s.GetCount() != len) { @@ -861,7 +861,7 @@ String TcpSocket::GetAll(int len) return s; } -String TcpSocket::GetLine(int maxlen) +String Socket::GetLine(int maxlen) { LLOG("GetLine " << maxlen << ", iseof " << IsEof()); String ln; @@ -892,7 +892,7 @@ String TcpSocket::GetLine(int maxlen) } } -void TcpSocket::SetSockError(const char *context, int code, const char *errdesc) +void Socket::SetSockError(const char *context, int code, const char *errdesc) { errorcode = code; errordesc.Clear(); @@ -903,19 +903,19 @@ void TcpSocket::SetSockError(const char *context, int code, const char *errdesc) LLOG("ERROR " << errordesc); } -void TcpSocket::SetSockError(const char *context, const char *errdesc) +void Socket::SetSockError(const char *context, const char *errdesc) { SetSockError(context, GetErrorCode(), errdesc); } -void TcpSocket::SetSockError(const char *context) +void Socket::SetSockError(const char *context) { - SetSockError(context, TcpSocketErrorDesc(GetErrorCode())); + SetSockError(context, SocketErrorDesc(GetErrorCode())); } -TcpSocket::SSL *(*TcpSocket::CreateSSL)(TcpSocket& socket); +Socket::SSL *(*Socket::CreateSSL)(Socket& socket); -bool TcpSocket::StartSSL() +bool Socket::StartSSL() { ASSERT(IsOpen()); if(!CreateSSL) { @@ -940,7 +940,7 @@ bool TcpSocket::StartSSL() return true; } -dword TcpSocket::SSLHandshake() +dword Socket::SSLHandshake() { if(ssl && (mode == CONNECT || mode == ACCEPT)) { dword w = ssl->Handshake(); @@ -958,25 +958,25 @@ dword TcpSocket::SSLHandshake() return 0; } -void TcpSocket::SSLCertificate(const String& cert_, const String& pkey_, bool asn1_) +void Socket::SSLCertificate(const String& cert_, const String& pkey_, bool asn1_) { cert = cert_; pkey = pkey_; asn1 = asn1_; } -void TcpSocket::SSLServerNameIndication(const String& name) +void Socket::SSLServerNameIndication(const String& name) { sni = name; } -void TcpSocket::SSLCAcert(const String& cert, bool asn1_) +void Socket::SSLCAcert(const String& cert, bool asn1_) { ca_cert = cert; asn1 = asn1_; } -void TcpSocket::Clear() +void Socket::Clear() { ClearError(); if(IsOpen()) @@ -984,6 +984,142 @@ void TcpSocket::Clear() Reset(); } +#ifdef PLATFORM_POSIX + +static bool sSetUnixSockType(Socket& s, const String& path, sockaddr_un& addr, bool abstract) +{ + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + +#ifndef PLATFORM_LINUX + if(abstract) { + s.SetSockError("SetUnixSockType", + -1, "Abstract socket is not supported on this platform"); + return false; + } +#endif + + if(abstract) { + addr.sun_path[0] = '\0'; + if(path.GetLength() > 0) { + ASSERT(path.GetLength() < sizeof(addr.sun_path) - 1); + strncpy(addr.sun_path + 1, ~path, sizeof(addr.sun_path) - 2); + return true; + } + } + else { + if(path.GetLength() > 0) { + ASSERT(path.GetLength() < sizeof(addr.sun_path)); + strncpy(addr.sun_path, ~path, sizeof(addr.sun_path) - 1); + addr.sun_path[sizeof(addr.sun_path) - 1] = '\0'; + return true; + } + } + s.SetSockError("SetUnixSockType", + -1, "Failed to set unix domain socket type"); + return false; +} + +int Socket::GetPeerPid() const +{ + if(!IsOpen()) + return -1; + +#if defined(PLATFORM_LINUX) + struct ucred ucred; + socklen_t len = sizeof(ucred); + if(getsockopt(socket, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == 0) + return ucred.pid; + +#elif (defined(PLATFORM_MACOS) || defined(PLATFORM_FREEBSD)) && defined(LOCAL_PEERPID) + pid_t pid; + socklen_t len = sizeof(pid); + if(getsockopt(socket, SOL_LOCAL, LOCAL_PEERPID, &pid, &len) == 0) + return pid; + +#endif + + return -1; // Not supported. +} + +bool Socket::NixConnect(const String& path, bool abstract) +{ + Close(); + Init(); + Reset(); + + if(!Open(AF_UNIX, SOCK_STREAM, 0)) + return false; + + struct sockaddr_un addr; + if(!sSetUnixSockType(*this, path, addr, abstract)) + return false; + + if(connect(socket, (sockaddr *) &addr, sizeof(addr)) == 0 || + GetErrorCode() == EINPROGRESS || GetErrorCode() == EWOULDBLOCK) { + mode = Socket::CONNECT; + return true; + } + + SetSockError("connect", -1, strerror(GetErrorCode())); + Close(); + return false; +} + +bool Socket::ConnectFileSystem(const String& path) +{ + return NixConnect(path, false); +} + +bool Socket::ConnectAbstract(const String& path) +{ + return NixConnect(path, true); +} + +bool Socket::NixListen(const String& path, int n, bool reuse, bool abstract) +{ + Close(); + Init(); + Reset(); + + if(!Open(AF_UNIX, SOCK_STREAM, 0)) + return false; + + struct sockaddr_un addr; + if(!sSetUnixSockType(*this, path, addr, abstract)) + return false; + + if(reuse) { + int optval = 1; + setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (const char *) &optval, sizeof(optval)); + } + + if(bind(socket, (const sockaddr *) &addr, sizeof(addr))) { + SetSockError(Format("bind(path=%s)", path)); + return false; + } + + if(listen(socket, n)) { + SetSockError(Format("listen(path=%s, count=%d)", path, n)); + return false; + } + + return true; +} + +bool Socket::ListenFileSystem(const String& path, int listen_count, bool reuse) +{ + return NixListen(path, listen_count, reuse, false); +} + +bool Socket::ListenAbstract(const String& path, int listen_count, bool reuse) +{ + return NixListen(path, listen_count, reuse, true); +} + +#endif + + int SocketWaitEvent::Wait(int timeout) { FD_ZERO(read); diff --git a/uppsrc/Core/src.tpp/SocketWaitEvent_en-us.tpp b/uppsrc/Core/src.tpp/SocketWaitEvent_en-us.tpp index 5f08e9a9c..b641a2f31 100644 --- a/uppsrc/Core/src.tpp/SocketWaitEvent_en-us.tpp +++ b/uppsrc/Core/src.tpp/SocketWaitEvent_en-us.tpp @@ -1,5 +1,4 @@ topic "SocketWaitEvent"; -[2 $$0,0#00000000000000000000000000000000:Default] [i448;a25;kKO9;2 $$1,0#37138531426314131252341829483380:class] [l288;2 $$2,2#27521748481378242620020725143825:desc] [0 $$3,0#96390100711032703541132217272105:end] @@ -9,6 +8,7 @@ topic "SocketWaitEvent"; [l288;i1121;b17;O9;~~~.1408;2 $$7,0#10431211400427159095818037425705:param] [i448;b42;O9;2 $$8,8#61672508125594000341940100500538:tparam] [b42;2 $$9,9#13035079074754324216151401829390:normal] +[2 $$0,0#00000000000000000000000000000000:Default] [{_} [ {{10000@(113.42.0) [s0;%% [*@7;4 SocketWaitEvent]]}}&] [s3; &] @@ -28,9 +28,9 @@ sockets for specified events.&] Note that SocketWaitEvent always waits for exceptions.&] [s3;%% &] [s4; &] -[s5;:SocketWaitEvent`:`:Add`(TcpSocket`&`,dword`): [@(0.0.255) void]_[* Add]([_^TcpSocket^ T -cpSocket][@(0.0.255) `&]_[*@3 s], [_^dword^ dword]_[*@3 events]_`=_WAIT`_ALL)&] -[s2;%% Adds TcpSocket [%-*@3 s] to the list to be waited on specified +[s5;:SocketWaitEvent`:`:Add`(Socket`&`,dword`): [@(0.0.255) void]_[* Add]([_^topic`:`/`/Core`/src`/Socket`_en`-us`#Socket`:`:class^ S +ocket][@(0.0.255) `&]_[*@3 s], [_^dword^ dword]_[*@3 events]_`=_WAIT`_ALL)&] +[s2;%% Adds Socket [%-*@3 s] to the list to be waited on specified [%-*@3 events]. If [%-*@3 s] is not open, it is not used but its index is reserved anyway (see Get).&] [s3;%% &] diff --git a/uppsrc/Core/src.tpp/TcpSocket_en-us.tpp b/uppsrc/Core/src.tpp/Socket_en-us.tpp similarity index 51% rename from uppsrc/Core/src.tpp/TcpSocket_en-us.tpp rename to uppsrc/Core/src.tpp/Socket_en-us.tpp index 979b4981d..fbe5cd5bf 100644 --- a/uppsrc/Core/src.tpp/TcpSocket_en-us.tpp +++ b/uppsrc/Core/src.tpp/Socket_en-us.tpp @@ -1,4 +1,4 @@ -topic "TcpSocket"; +topic "Socket"; [i448;a25;kKO9;2 $$1,0#37138531426314131252341829483380:class] [l288;2 $$2,2#27521748481378242620020725143825:desc] [0 $$3,0#96390100711032703541132217272105:end] @@ -10,16 +10,16 @@ topic "TcpSocket"; [b42;2 $$9,9#13035079074754324216151401829390:normal] [2 $$0,0#00000000000000000000000000000000:Default] [{_} -[ {{10000@(113.42.0) [s0;%% [*@7;4 TcpSocket]]}}&] +[ {{10000@(113.42.0) [s0;%% [*@7;4 Socket]]}}&] [s3; &] -[s1;:TcpSocket`:`:class: [@(0.0.255)3 class][3 _][*3 TcpSocket]&] -[s2;%% This class represents an TCP/IP socket. It extends the basic -semantics of sockets to allow non`-blocking or time constrained -operations.&] +[s1;:Socket`:`:class: [@(0.0.255)3 class][3 _][*3 Socket]&] +[s2;%% This class represents a TCP/IP socket or [^https`:`/`/en`.wikipedia`.org`/wiki`/Unix`_domain`_socket`?oldformat`=true^ U +nix domain socket]. It extends the basic semantics of sockets +to allow non`-blocking or time constrained operations.&] [s3; &] [ {{10000F(128)G(128)@1 [s0;%% [* Public Method List]]}}&] [s3; &] -[s5;:TcpSocket`:`:WhenWait: [_^topic`:`/`/Core`/src`/Callbacks`$en`-us`#Callback`:`:class^ C +[s5;:Socket`:`:WhenWait: [_^topic`:`/`/Core`/src`/Callbacks`$en`-us`#Callback`:`:class^ C allback]_[* WhenWait]&] [s2;%% If this callback is defined, it is invoked periodically while TcpSocket performs any operations, with the period set by WaitStep @@ -27,101 +27,133 @@ TcpSocket performs any operations, with the period set by WaitStep in interactive applications.&] [s3; &] [s4; &] -[s5;:TcpSocket`:`:GetHostName`(`): [@(0.0.255) static] [_^topic`:`/`/Core`/src`/String`$en`-us`#String`:`:class^ S +[s5;:Socket`:`:GetHostName`(`): [@(0.0.255) static] [_^topic`:`/`/Core`/src`/String`$en`-us`#String`:`:class^ S tring]_[* GetHostName]()&] [s2;%% Returns the name of computer.&] [s3; &] [s4; &] -[s5;:TcpSocket`:`:GetDone`(`)const: [@(0.0.255) int]_[* GetDone]()_[@(0.0.255) const]&] +[s5;:Socket`:`:GetPeerPid`(`)const: [@(0.0.255) int] [* GetPeerPid]() +[@(0.0.255) const]&] +[s6; POSIX only&] +[s2;%% Returns the process ID (pid) of the peer on success, `-1 on +failure. On non`-blocking mode, make sure that socket is actually +connected or accepted. This is only available on unix domain +(local) sockets.&] +[s3; &] +[s4; &] +[s5;:Socket`:`:GetDone`(`)const: [@(0.0.255) int]_[* GetDone]()_[@(0.0.255) const]&] [s2;%% Returns number of bytes processed during current operation; intended to be called from WhenWait routine&] [s3; &] [s4; &] -[s5;:TcpSocket`:`:IsOpen`(`)const: [@(0.0.255) bool]_[* IsOpen]()_[@(0.0.255) const]&] +[s5;:Socket`:`:IsOpen`(`)const: [@(0.0.255) bool]_[* IsOpen]()_[@(0.0.255) const]&] [s2;%% Returns true if socket is open.&] [s3; &] [s4; &] -[s5;:TcpSocket`:`:IsEof`(`)const: [@(0.0.255) bool]_[* IsEof]()_[@(0.0.255) const]&] +[s5;:Socket`:`:IsEof`(`)const: [@(0.0.255) bool]_[* IsEof]()_[@(0.0.255) const]&] [s2;%% Returns true if there are no more input data to process. Also returns true if socket is not open, if there was an error or if socket was aborted.&] [s3; &] [s4; &] -[s5;:TcpSocket`:`:IsError`(`)const: [@(0.0.255) bool]_[* IsError]()_[@(0.0.255) const]&] +[s5;:Socket`:`:IsError`(`)const: [@(0.0.255) bool]_[* IsError]()_[@(0.0.255) const]&] [s2;%% Returns true if some previous operations reported error. In that case, all subsequent request are ignored.&] [s3; &] [s4; &] -[s5;:TcpSocket`:`:ClearError`(`): [@(0.0.255) void]_[* ClearError]()&] +[s5;:Socket`:`:ClearError`(`): [@(0.0.255) void]_[* ClearError]()&] [s2;%% Clears the error state.&] [s3; &] [s4; &] -[s5;:TcpSocket`:`:GetError`(`)const: [@(0.0.255) int]_[* GetError]()_[@(0.0.255) const]&] +[s5;:Socket`:`:GetError`(`)const: [@(0.0.255) int]_[* GetError]()_[@(0.0.255) const]&] [s2;%% Returns errorcode. Errorcodes are either defined by SOCKET API or it can be `-1 for other errors.&] [s3; &] [s4; &] -[s5;:TcpSocket`:`:GetErrorDesc`(`)const: [_^topic`:`/`/Core`/src`/String`$en`-us`#String`:`:class^ S +[s5;:Socket`:`:GetErrorDesc`(`)const: [_^topic`:`/`/Core`/src`/String`$en`-us`#String`:`:class^ S tring]_[* GetErrorDesc]()_[@(0.0.255) const]&] [s2;%% Returns description of error.&] [s3; &] [s4; &] -[s5;:TcpSocket`:`:Abort`(`): [@(0.0.255) void]_[* Abort]()&] -[s2;%% Sets TcpSocket to aborted state. In aborted state, all subsequent +[s5;:Socket`:`:Abort`(`): [@(0.0.255) void]_[* Abort]()&] +[s2;%% Sets Socket to aborted state. In aborted state, all subsequent request are ignored. Intended to be called from WhenWait routine.&] [s3; &] [s4; &] -[s5;:TcpSocket`:`:IsAbort`(`)const: [@(0.0.255) bool]_[* IsAbort]()_[@(0.0.255) const]&] -[s2;%% Returns true is TcpSocket is in aborted state.&] +[s5;:Socket`:`:IsAbort`(`)const: [@(0.0.255) bool]_[* IsAbort]()_[@(0.0.255) const]&] +[s2;%% Returns true is Socket is in aborted state.&] [s3; &] [s4; &] -[s5;:TcpSocket`:`:ClearAbort`(`): [@(0.0.255) void]_[* ClearAbort]()&] +[s5;:Socket`:`:ClearAbort`(`): [@(0.0.255) void]_[* ClearAbort]()&] [s2;%% Clears the aborted state.&] [s3; &] [s4; &] -[s5;:TcpSocket`:`:IsTimeout`(`)const: [@(0.0.255) bool]_[* IsTimeout]()_[@(0.0.255) const]&] +[s5;:Socket`:`:IsTimeout`(`)const: [@(0.0.255) bool]_[* IsTimeout]()_[@(0.0.255) const]&] [s2;%% Returns true if the last operation time`-outed.&] [s3; &] [s4; &] -[s5;:TcpSocket`:`:GetSOCKET`(`)const: SOCKET_[* GetSOCKET]()_[@(0.0.255) const]&] -[s2;%% Returns socket handle. Note that all TcpSocket sockets are -non`-blocking from host OS perspective.&] +[s5;:Socket`:`:GetSOCKET`(`)const: SOCKET_[* GetSOCKET]()_[@(0.0.255) const]&] +[s2;%% Returns socket handle. Note that all Socket sockets are non`-blocking +from host OS perspective.&] [s3; &] [s4; &] -[s5;:TcpSocket`:`:GetPeerAddr`(`)const: [_^topic`:`/`/Core`/src`/String`$en`-us`#String`:`:class^ S +[s5;:Socket`:`:GetPeerAddr`(`)const: [_^topic`:`/`/Core`/src`/String`$en`-us`#String`:`:class^ S tring]_[* GetPeerAddr]()_[@(0.0.255) const]&] [s2;%% Returns the peer address.&] [s3; &] [s4; &] -[s5;:TcpSocket`:`:Attach`(SOCKET`): [@(0.0.255) void]_[* Attach](SOCKET_[*@3 socket])&] -[s2;%% Attaches [%-*@3 socket] to TcpSocket. [%-*@3 socket] must be in -non`-blocking state.&] +[s5;:Socket`:`:Attach`(SOCKET`): [@(0.0.255) void]_[* Attach](SOCKET_[*@3 socket])&] +[s2;%% Attaches [%-*@3 socket] to Socket. [%-*@3 socket] must be in non`-blocking +state.&] [s3;%% &] [s4;%% &] -[s5;:TcpSocket`:`:Connect`(const char`*`,int`): [@(0.0.255) bool]_[* Connect]([@(0.0.255) c -onst]_[@(0.0.255) char]_`*[*@3 host], [@(0.0.255) int]_[*@3 port])&] +[s5;:Socket`:`:Connect`(const char`*`,int`): [@(0.0.255) bool]_[* Connect]([@(0.0.255) cons +t]_[@(0.0.255) char]_`*[*@3 host], [@(0.0.255) int]_[*@3 port])&] [s2;%% Connects socket to server at [%-*@3 host]:[%-*@3 port]. This operation is blocking with respect to resolving host name. Returns true when connection process is successfully started.&] [s3; &] [s4;%% &] -[s5;:TcpSocket`:`:Connect`(IpAddrInfo`&`): [@(0.0.255) bool]_[* Connect]([_^topic`:`/`/Core`/src`/IpAddrInfo`$en`-us`#IpAddrInfo`:`:class^ I +[s5;:Socket`:`:Connect`(IpAddrInfo`&`): [@(0.0.255) bool]_[* Connect]([_^topic`:`/`/Core`/src`/IpAddrInfo`$en`-us`#IpAddrInfo`:`:class^ I pAddrInfo][@(0.0.255) `&]_[*@3 info])&] [s2;%% Connects socket to server found at [%-*@3 info]. Non`-blocking.&] [s3;%% &] [s4; &] -[s5;:TcpSocket`:`:WaitConnect`(`): [@(0.0.255) bool]_[* WaitConnect]()&] +[s5;:Upp`:`:Socket`:`:ConnectFileSystem`(const String`&`): [@(0.0.255) bool] +[* ConnectFileSystem]([@(0.0.255) const] String[@(0.0.255) `&] [*@3 path])&] +[s6;%% POSIX only&] +[s2;%% Connects socket to a Unix domain server bound at the given +file system [%-*@3 path]. The path must exist on the file system. +Returns true if connection is successful (blocking mode) or connection +is in progress (non blocking mode). File system sockets are visible +in the file system and require proper permissions. &] +[s3; &] +[s4; &] +[s5;:Upp`:`:Socket`:`:ConnectAbstract`(const String`&`): [@(0.0.255) bool] +[* ConnectAbstract]([@(0.0.255) const] String[@(0.0.255) `&] [*@3 path])&] +[s6;%% Linux only&] +[s2;%% Connects socket to a Unix domain server in the Linux abstract +namespace. The [%-*@3 path ]is the name in the abstract namespace +and does not correspond to a file system path. Returns true if +connection is successful (blocking mode) or connection is in +progress (non blocking mode). Abstract sockets exist only in +kernel memory and disappear when processes exit. On non`-Linux +POSIX systems, this function will fail and set the socket into +error state. &] +[s3; &] +[s4; &] +[s5;:Socket`:`:WaitConnect`(`): [@(0.0.255) bool]_[* WaitConnect]()&] [s2;%% After Connect returns true, WaitConnect waits for connection to be established. Note that it is only necessary to use WaitConnect if you want to intercept errors before sending/recieving data.&] [s3;%% &] [s4; &] -[s5;:TcpSocket`:`:Listen`(int`,int`,bool`,bool`,void`*`): [@(0.0.255) bool]_[* Listen]([@(0.0.255) i +[s5;:Socket`:`:Listen`(int`,int`,bool`,bool`,void`*`): [@(0.0.255) bool]_[* Listen]([@(0.0.255) i nt]_[*@3 port], [@(0.0.255) int]_[*@3 listen`_count]_`=_[@3 5], [@(0.0.255) bool]_[*@3 ipv6]_ `=_[@(0.0.255) false], [@(0.0.255) bool]_[*@3 reuse]_`=_[@(0.0.255) true], [@(0.0.255) void`*]_[*@3 addr]_`=_NULL)&] -[s5;:TcpSocket`:`:Listen`(const IpAddrInfo`&`,int`,int`,bool`,bool`): [@(0.0.255) bool]_ -[* Listen]([@(0.0.255) const]_[_^topic`:`/`/Core`/src`/IpAddrInfo`$en`-us`#IpAddrInfo`:`:class^ I +[s5;:Socket`:`:Listen`(const IpAddrInfo`&`,int`,int`,bool`,bool`): [@(0.0.255) bool]_[* L +isten]([@(0.0.255) const]_[_^topic`:`/`/Core`/src`/IpAddrInfo`$en`-us`#IpAddrInfo`:`:class^ I pAddrInfo][@(0.0.255) `&]_[*@3 addr], [@(0.0.255) int]_[*@3 port], [@(0.0.255) int]_[*@3 list en`_count]_`=_[@3 5], [@(0.0.255) bool]_[*@3 ipv6]_`=_[@(0.0.255) false], [@(0.0.255) bool]_[*@3 reuse]_`=_[@(0.0.255) true])&] @@ -135,34 +167,62 @@ to sockaddr`_in`::sin`_addr.s`_addr for ipv6`=`=true and/or in6`_addr to be dereferenced and assigned to sockaddr`_in6`::sin6`_addr for ipv6`=`=true.&] [s3;%% &] +[s4; &] +[s5;:Upp`:`:Socket`:`:ListenFileSystem`(const String`&`,int`,bool`): [@(0.0.255) bool] +[* ListenFileSystem]([@(0.0.255) const ]String[@(0.0.255) `&] [*@3 path], +[@(0.0.255) int] [*@3 listen`_count] [@(0.0.255) `=] [@3 5], [@(0.0.255) bool] +[*@3 reuse] [@(0.0.255) `=] [@(0.0.255) true])&] +[s6; POSIX only&] +[s2;%% Creates a Unix domain server socket bound to the given file +system [%-*@3 path]. [%-*@3 listen`_count] specifies the maximum +number of pending connections in the queue. [%-*@3 reuse] indicates +whether the socket should allow reuse of the address if it already +exists. returns true if the listen is successful.&] +[s3; &] +[s4; &] +[s5;:Upp`:`:Socket`:`:ListenAbstract`(const String`&`,int`,bool`): [@(0.0.255) bool] +[* ListenAbstract]([@(0.0.255) const] String[@(0.0.255) `&] [*@3 path], +[@(0.0.255) int] [*@3 listen`_count] [@(0.0.255) `=] [@3 5], [@(0.0.255) bool] +[*@3 reuse] [@(0.0.255) `=] [@(0.0.255) true])&] +[s6; Linux only&] +[s2;%% Creates a Unix domain server socket in the Linux abstract +namespace. [%-*@3 path] is the name in the abstract namespace (does +not correspond to a file system path). [%-*@3 listen`_count] specifies +the maximum number of pending connections. [%-*@3 reuse] indicates +whether the abstract socket name can be reused. Abstract sockets +exist only in kernel memory and disappear when processes exit. +On non`-Linux POSIX systems, this method will fail and set the +socket into error state.&] +[s3; &] [s4;%% &] -[s5;:TcpSocket`:`:Accept`(TcpSocket`&`): [@(0.0.255) bool]_[* Accept]([_^topic`:`/`/Core`/src`/TcpSocket`$en`-us`#TcpSocket`:`:class^ T -cpSocket][@(0.0.255) `&]_[*@3 listen`_socket])&] +[s5;:Socket`:`:Accept`(Socket`&`): [@(0.0.255) bool]_[* Accept]([_^topic`:`/`/Core`/src`/TcpSocket`$en`-us`#TcpSocket`:`:class^ S +ocket][@(0.0.255) `&]_[*@3 listen`_socket])&] [s2;%% Accepts a connection from [%-*@3 listen`_socket].&] [s3;%% &] [s4;%% &] -[s5;:TcpSocket`:`:Close`(`): [@(0.0.255) void]_[* Close]()&] +[s5;:Socket`:`:Close`(`): [@(0.0.255) void]_[* Close]()&] [s2;%% Closes the socket.&] [s3;%% &] [s4;%% &] -[s5;:TcpSocket`:`:Shutdown`(`): [@(0.0.255) void]_[* Shutdown]()&] +[s5;:Socket`:`:Shutdown`(`): [@(0.0.255) void]_[* Shutdown]()&] [s2;%% Performs shutdown for write operations. Normally not needed.&] [s3;%% &] [s4;%% &] -[s5;:TcpSocket`:`:NoDelay`(`): [@(0.0.255) void]_[* NoDelay]()&] -[s2;%% Sets TCP`_NODELAY option.&] +[s5;:Socket`:`:NoDelay`(`): [@(0.0.255) void]_[* NoDelay]()&] +[s2;%% Sets TCP`_NODELAY option. Note that this option is not available +for unix domain sockets.&] [s3;%% &] [s4;%% &] -[s5;:TcpSocket`:`:Linger`(int`): [@(0.0.255) void]_[* Linger]([@(0.0.255) int]_[*@3 msecs])&] +[s5;:Socket`:`:Linger`(int`): [@(0.0.255) void]_[* Linger]([@(0.0.255) int]_[*@3 msecs])&] [s2;%% Sets SO`_LINGER option to [%-*@3 msecs]. If [%-*@3 msecs] is Null, switches SO`_LINGER off.&] [s3;%% &] [s4;%% &] -[s5;:TcpSocket`:`:NoLinger`(`): [@(0.0.255) void]_[* NoLinger]()&] +[s5;:Socket`:`:NoLinger`(`): [@(0.0.255) void]_[* NoLinger]()&] [s2;%% Same as Linger(Null).&] [s3;%% &] [s4;%% &] -[s5;:TcpSocket`:`:Wait`(dword`): [@(0.0.255) bool]_[* Wait]([_^topic`:`/`/Core`/src`/PrimitiveDataTypes`$en`-us`#Upp`:`:dword`:`:typedef^ d +[s5;:Socket`:`:Wait`(dword`): [@(0.0.255) bool]_[* Wait]([_^topic`:`/`/Core`/src`/PrimitiveDataTypes`$en`-us`#Upp`:`:dword`:`:typedef^ d word]_[*@3 events])&] [s2;%% Waits for at most timeout for [%-*@3 events], which can be a combination of WAIT`_READ (wait for more input bytes available), @@ -172,100 +232,99 @@ true if wait was successful (data can be written/read after the wait), false on timeout.&] [s3;%% &] [s4;%% &] -[s5;:TcpSocket`:`:WaitRead`(`): [@(0.0.255) bool]_[* WaitRead]()&] +[s5;:Socket`:`:WaitRead`(`): [@(0.0.255) bool]_[* WaitRead]()&] [s2;%% Same as Wait(WAIT`_READ).&] [s3;%% &] [s4;%% &] -[s5;:TcpSocket`:`:WaitWrite`(`): [@(0.0.255) bool]_[* WaitWrite]()&] +[s5;:Socket`:`:WaitWrite`(`): [@(0.0.255) bool]_[* WaitWrite]()&] [s2;%% Same as Wait(WAIT`_WRITE).&] [s3;%% &] [s4;%% &] -[s5;:TcpSocket`:`:Peek`(`): [@(0.0.255) int]_[* Peek]()&] -[s5;:TcpSocket`:`:Term`(`): [@(0.0.255) int]_[* Term]()&] +[s5;:Socket`:`:Peek`(`): [@(0.0.255) int]_[* Peek]()&] +[s5;:Socket`:`:Term`(`): [@(0.0.255) int]_[* Term]()&] [s2;%% Returns the next input byte without actually removing it from input queue. It at most waits for specified timeout for it, if there is still none, returns `-1.&] [s3;%% &] [s4;%% &] -[s5;:TcpSocket`:`:Get`(`): [@(0.0.255) int]_[* Get]()&] +[s5;:Socket`:`:Get`(`): [@(0.0.255) int]_[* Get]()&] [s2;%% Reads the next input byte. It at most waits for specified timeout for it, if there is still none, returns `-1.&] [s3;%% &] [s4;%% &] -[s5;:TcpSocket`:`:Get`(void`*`,int`): [@(0.0.255) int]_[* Get]([@(0.0.255) void]_`*[*@3 buffe -r], [@(0.0.255) int]_[*@3 len])&] +[s5;:Socket`:`:Get`(void`*`,int`): [@(0.0.255) int]_[* Get]([@(0.0.255) void]_`*[*@3 buffer], + [@(0.0.255) int]_[*@3 len])&] [s2;%% Reads at most [%-*@3 len] bytes into [%-*@3 buffer], trying to do so at most for specified timeout. Returns the number of bytes actually read.&] [s3;%% &] [s4;%% &] -[s5;:TcpSocket`:`:Get`(int`): [_^topic`:`/`/Core`/src`/String`$en`-us`#String`:`:class^ S -tring]_[* Get]([@(0.0.255) int]_[*@3 len])&] +[s5;:Socket`:`:Get`(int`): [_^topic`:`/`/Core`/src`/String`$en`-us`#String`:`:class^ St +ring]_[* Get]([@(0.0.255) int]_[*@3 len])&] [s2;%% Reads at most [%-*@3 len] bytes, trying to do so at most for specified timeout. Returns a String with read data.&] [s3;%% &] [s4; &] -[s5;:TcpSocket`:`:Put`(const void`*`,int`): [@(0.0.255) int]_[* Put]([@(0.0.255) const]_[@(0.0.255) v +[s5;:Socket`:`:Put`(const void`*`,int`): [@(0.0.255) int]_[* Put]([@(0.0.255) const]_[@(0.0.255) v oid]_`*[*@3 s], [@(0.0.255) int]_[*@3 len])&] [s2;%% Writes at most [%-*@3 len] bytes from [%-*@3 buffer], trying to do so at most for specified timeout. Returns the number of bytes actually written.&] [s3;%% &] [s4;%% &] -[s5;:TcpSocket`:`:Put`(const String`&`): [@(0.0.255) int]_[* Put]([@(0.0.255) const]_[_^topic`:`/`/Core`/src`/String`$en`-us`#String`:`:class^ S +[s5;:Socket`:`:Put`(const String`&`): [@(0.0.255) int]_[* Put]([@(0.0.255) const]_[_^topic`:`/`/Core`/src`/String`$en`-us`#String`:`:class^ S tring][@(0.0.255) `&]_[*@3 s])&] [s2;%% Writes [%-*@3 s], trying to do so at most for specified timeout. Returns the number of bytes actually written.&] [s3;%% &] [s4;%% &] -[s5;:TcpSocket`:`:GetAll`(void`*`,int`): [@(0.0.255) bool]_[* GetAll]([@(0.0.255) void]_`*[*@3 b +[s5;:Socket`:`:GetAll`(void`*`,int`): [@(0.0.255) bool]_[* GetAll]([@(0.0.255) void]_`*[*@3 b uffer], [@(0.0.255) int]_[*@3 len])&] [s2;%% Reads exactly [%-*@3 len] bytes into [%-*@3 buffer]. If such number of bytes cannot be read until timeout, returns false and sets -timeout error for TcpSocket.&] +timeout error for Socket.&] [s3;%% &] [s4;%% &] -[s5;:TcpSocket`:`:GetAll`(int`): [_^topic`:`/`/Core`/src`/String`$en`-us`#String`:`:class^ S +[s5;:Socket`:`:GetAll`(int`): [_^topic`:`/`/Core`/src`/String`$en`-us`#String`:`:class^ S tring]_[* GetAll]([@(0.0.255) int]_[*@3 len])&] [s2;%% Reads exactly [%-*@3 len] bytes. If such number of bytes cannot be read until timeout, returns String`::GetVoid() and sets timeout -error for TcpSocket.&] +error for Socket.&] [s3;%% &] [s4;%% &] -[s5;:TcpSocket`:`:GetLine`(int`): [_^topic`:`/`/Core`/src`/String`$en`-us`#String`:`:class^ S +[s5;:Socket`:`:GetLine`(int`): [_^topic`:`/`/Core`/src`/String`$en`-us`#String`:`:class^ S tring]_[* GetLine]([@(0.0.255) int]_[*@3 maxlen]_`=_[@3 65536])&] [s2;%% Reads single line (ended with `'`\n`', `'`\r`' is ignored). If the whole line cannot be read within timeout or line length is longer than [%-*@3 maxlen] sets error and returns String`::GetVoid().&] [s3;%% &] [s4; &] -[s5;:TcpSocket`:`:PutAll`(const void`*`,int`): [@(0.0.255) bool]_[* PutAll]([@(0.0.255) con -st]_[@(0.0.255) void]_`*[*@3 s], [@(0.0.255) int]_[*@3 len])&] +[s5;:Socket`:`:PutAll`(const void`*`,int`): [@(0.0.255) bool]_[* PutAll]([@(0.0.255) const]_ +[@(0.0.255) void]_`*[*@3 s], [@(0.0.255) int]_[*@3 len])&] [s2;%% Outputs exactly [%-*@3 len] bytes. If such number of bytes cannot be written in time specified by timeout, sets error and returns false.&] [s3;%% &] [s4;%% &] -[s5;:TcpSocket`:`:PutAll`(const String`&`): [@(0.0.255) bool]_[* PutAll]([@(0.0.255) const]_ -[_^topic`:`/`/Core`/src`/String`$en`-us`#String`:`:class^ String][@(0.0.255) `&]_[*@3 s -])&] +[s5;:Socket`:`:PutAll`(const String`&`): [@(0.0.255) bool]_[* PutAll]([@(0.0.255) const]_[_^topic`:`/`/Core`/src`/String`$en`-us`#String`:`:class^ S +tring][@(0.0.255) `&]_[*@3 s])&] [s2;%% Outputs the whole String. If such number of bytes cannot be written in time specified by timeout, sets error and returns false.&] [s3;%% &] [s4;%% &] -[s5;:TcpSocket`:`:StartSSL`(`): [@(0.0.255) bool]_[* StartSSL]()&] -[s2;%% Sets TcpSocket to SSL mode and starts SSL handshake. Core/SSL +[s5;:Socket`:`:StartSSL`(`): [@(0.0.255) bool]_[* StartSSL]()&] +[s2;%% Sets Socket to SSL mode and starts SSL handshake. Core/SSL must be present in project. Returns true if SSL could have been started. Handshake is not finished until SSLHandshake returns false.&] [s3;%% &] [s4;%% &] -[s5;:TcpSocket`:`:IsSSL`(`)const: [@(0.0.255) bool]_[* IsSSL]()_[@(0.0.255) const]&] -[s2;%% Returns true if TcpSocket is in SSL mode.&] +[s5;:Socket`:`:IsSSL`(`)const: [@(0.0.255) bool]_[* IsSSL]()_[@(0.0.255) const]&] +[s2;%% Returns true if Socket is in SSL mode.&] [s3;%% &] [s4;%% &] -[s5;:TcpSocket`:`:SSLHandshake`(`): [@(0.0.255) dword]_[* SSLHandshake]()&] +[s5;:Socket`:`:SSLHandshake`(`): [@(0.0.255) dword]_[* SSLHandshake]()&] [s2;%% Attempts the progress on SSL handshake for at most timeout period. Returns a combination of WAIT`_READ and WAIT`_WRITE if SSL handshake is (still) in progress, indicating whether the @@ -273,8 +332,8 @@ process needs to read or write more bytes from the socket. Returns 0 if handshake is finished.&] [s3;%% &] [s4;%% &] -[s5;:TcpSocket`:`:SSLCertificate`(const String`&`,const String`&`,bool`): [@(0.0.255) v -oid]_[* SSLCertificate]([@(0.0.255) const]_[_^topic`:`/`/Core`/src`/String`$en`-us`#String`:`:class^ S +[s5;:Socket`:`:SSLCertificate`(const String`&`,const String`&`,bool`): [@(0.0.255) void +]_[* SSLCertificate]([@(0.0.255) const]_[_^topic`:`/`/Core`/src`/String`$en`-us`#String`:`:class^ S tring][@(0.0.255) `&]_[*@3 cert], [@(0.0.255) const]_[_^topic`:`/`/Core`/src`/String`$en`-us`#String`:`:class^ S tring][@(0.0.255) `&]_[*@3 pkey], [@(0.0.255) bool]_[*@3 asn1])&] [s2;%% Sets the SSL certificate. Must be called before StartSSL. @@ -282,37 +341,37 @@ tring][@(0.0.255) `&]_[*@3 pkey], [@(0.0.255) bool]_[*@3 asn1])&] usually used on accepting sockets.)&] [s3;%% &] [s4; &] -[s5;:Upp`:`:TcpSocket`:`:SSLServerNameIndication`(const Upp`:`:String`&`): [@(0.0.255) v -oid]_[* SSLServerNameIndication]([@(0.0.255) const]_[_^Upp`:`:String^ String][@(0.0.255) `& -]_[*@3 name])&] +[s5;:Socket`:`:SSLServerNameIndication`(const Upp`:`:String`&`): [@(0.0.255) void]_[* SSL +ServerNameIndication]([@(0.0.255) const]_[_^Upp`:`:String^ String][@(0.0.255) `&]_[*@3 na +me])&] [s2;%% Sets [^https`:`/`/cs`.wikipedia`.org`/wiki`/Server`_Name`_Indication^ SNI] for SSL connection.&] [s3;%% &] [s4;%% &] -[s5;:TcpSocket`:`:GetSSLInfo`(`)const: [@(0.0.255) const]_[_^topic`:`/`/Core`/src`/TcpSocket`$en`-us`#SSLInfo`:`:struct^ S +[s5;:Socket`:`:GetSSLInfo`(`)const: [@(0.0.255) const]_[_^topic`:`/`/Core`/src`/TcpSocket`$en`-us`#SSLInfo`:`:struct^ S SLInfo]_`*[* GetSSLInfo]()_[@(0.0.255) const]&] [s2;%% Returns information about established (after handshake) SSL connection or NULL if such information is not available.&] [s3;%% &] [s4;%% &] -[s5;:TcpSocket`:`:Timeout`(int`): [_^topic`:`/`/Core`/src`/TcpSocket`$en`-us`#TcpSocket`:`:class^ T -cpSocket][@(0.0.255) `&]_[* Timeout]([@(0.0.255) int]_[*@3 ms])&] +[s5;:Socket`:`:Timeout`(int`): [_^topic`:`/`/Core`/src`/TcpSocket`$en`-us`#TcpSocket`:`:class^ S +ocket][@(0.0.255) `&]_[* Timeout]([@(0.0.255) int]_[*@3 ms])&] [s2;%% Sets timeout for all operations. Zero means that all operations return immediately (in that case it is usually a good idea to perform some sort of external blocking on socket or socket group using e.g. SocketWaitEvent). Null means operations are blocking (but they still can invoke WhenProgress periodically if defined). Other values specify a number of milliseconds. Note: It is possible -to adjust timeout before any single TcpSocket operation. Returns -`*this. Default value is Null, which means TcpSocket is blocking.&] +to adjust timeout before any single Socket operation. Returns +`*this. Default value is Null, which means Socket is blocking.&] [s3;%% &] [s4;%% &] -[s5;:TcpSocket`:`:GetTimeout`(`)const: [@(0.0.255) int]_[* GetTimeout]()_[@(0.0.255) const]&] +[s5;:Socket`:`:GetTimeout`(`)const: [@(0.0.255) int]_[* GetTimeout]()_[@(0.0.255) const]&] [s2;%% Returns current timeout.&] [s3;%% &] [s4; &] -[s5;:TcpSocket`:`:GlobalTimeout`(int`): [_^topic`:`/`/Core`/src`/TcpSocket`$en`-us`#TcpSocket`:`:class^ T -cpSocket][@(0.0.255) `&]_[* GlobalTimeout]([@(0.0.255) int]_[*@3 ms])&] +[s5;:Socket`:`:GlobalTimeout`(int`): [_^topic`:`/`/Core`/src`/TcpSocket`$en`-us`#TcpSocket`:`:class^ S +ocket][@(0.0.255) `&]_[* GlobalTimeout]([@(0.0.255) int]_[*@3 ms])&] [s2;%% Sets the `"global timeout`". This timeout is in effect over a whole range of operations, until it is canceled by calling this method with Null parameter or by setting a new global timeout. @@ -320,34 +379,33 @@ If global timeout is exceeded, operation during which it happened fails and socket error code is set to ERROR`_GLOBAL`_TIMEOUT.&] [s3;%% &] [s4; &] -[s5;:TcpSocket`:`:NoGlobalTimeout`(`): [_^topic`:`/`/Core`/src`/TcpSocket`$en`-us`#TcpSocket`:`:class^ T -cpSocket][@(0.0.255) `&]_[* NoGlobalTimeout]()&] +[s5;:Socket`:`:NoGlobalTimeout`(`): [_^topic`:`/`/Core`/src`/TcpSocket`$en`-us`#TcpSocket`:`:class^ S +ocket][@(0.0.255) `&]_[* NoGlobalTimeout]()&] [s2;%% Same as GlobalTimeout(Null).&] [s3; &] [s4;%% &] -[s5;:TcpSocket`:`:Blocking`(`): [_^topic`:`/`/Core`/src`/TcpSocket`$en`-us`#TcpSocket`:`:class^ T -cpSocket][@(0.0.255) `&]_[* Blocking]()&] +[s5;:Socket`:`:Blocking`(`): [_^topic`:`/`/Core`/src`/TcpSocket`$en`-us`#TcpSocket`:`:class^ S +ocket][@(0.0.255) `&]_[* Blocking]()&] [s2;%% Same as Timeout(Null). Returns `*this. This is the default value.&] [s3;%% &] [s4; &] -[s5;:Upp`:`:TcpSocket`:`:IsBlocking`(`): [@(0.0.255) bool]_[* IsBlocking]()&] +[s5;:Socket`:`:IsBlocking`(`): [@(0.0.255) bool]_[* IsBlocking]()&] [s2;%% Same is IsNull(GetTimeout()).&] [s3; &] [s4; &] -[s5;:TcpSocket`:`:WaitStep`(int`): [_^topic`:`/`/Core`/src`/TcpSocket`$en`-us`#TcpSocket`:`:class^ T -cpSocket][@(0.0.255) `&]_[* WaitStep]([@(0.0.255) int]_[*@3 ms])&] +[s5;:Socket`:`:WaitStep`(int`): [_^topic`:`/`/Core`/src`/TcpSocket`$en`-us`#TcpSocket`:`:class^ S +ocket][@(0.0.255) `&]_[* WaitStep]([@(0.0.255) int]_[*@3 ms])&] [s2;%% Sets the periodicity of calling WhenWait in millisecond between calls. Default is 10ms (100hz).&] [s3;%% &] [s4; &] -[s5;:TcpSocket`:`:GetWaitStep`(`)const: [@(0.0.255) int]_[* GetWaitStep]()_[@(0.0.255) cons -t]&] -[s2;%% Retruns current periodicity of calling WhenWait.&] +[s5;:Socket`:`:GetWaitStep`(`)const: [@(0.0.255) int]_[* GetWaitStep]()_[@(0.0.255) const]&] +[s2;%% Returns current periodicity of calling WhenWait.&] [s3; &] [s4;%% &] -[s5;:TcpSocket`:`:TcpSocket`(`): [* TcpSocket]()&] -[s5;:TcpSocket`:`:`~TcpSocket`(`): [@(0.0.255) `~][* TcpSocket]()&] +[s5;:Socket`:`:Socket`(`): [* Socket]()&] +[s5;:Socket`:`:`~Socket`(`): [@(0.0.255) `~][* Socket]()&] [s2;%% Constructor, destructor.&] [s3;%% &] [s0; &] @@ -394,4 +452,4 @@ ate]_[* cert`_notafter]&] [s5;:SSLInfo`:`:cert`_serial: [_^topic`:`/`/Core`/src`/String`$en`-us`#String`:`:class^ S tring]_[* cert`_serial]&] [s2;%% Serial number of certificate.&] -[s3; ]] \ No newline at end of file +[s0;%% ]] \ No newline at end of file