=> 84928fcaab4aedc3cfc1fd8e79b9ef422ae362d4
[1mdiff --git a/src/platform/win32/service.c b/src/platform/win32/service.c[m [1mindex b66e442..878a0f9 100644[m [1m--- a/src/platform/win32/service.c[m [1m+++ b/src/platform/win32/service.c[m [36m@@ -29,7 +29,6 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.[m #include "the_Foundation/socket.h"[m #include "the_Foundation/string.h"[m #include "the_Foundation/thread.h"[m [31m-#include "pipe.h"[m #include "wide.h"[m [m #define WIN32_LEAN_AND_MEAN[m [36m@@ -40,7 +39,8 @@[m [mstruct Impl_Service {[m iObject object;[m uint16_t port;[m SOCKET fd;[m [31m- iPipe stop;[m [32m+[m[32m HANDLE fdEvent;[m [32m+[m[32m HANDLE stopEvent;[m iThread *listening;[m iAudience *incomingAccepted;[m };[m [36m@@ -50,55 +50,69 @@[m [miDefineAudienceGetter(Service, incomingAccepted)[m iDefineObjectConstructionArgs(Service, (uint16_t port), port)[m [m static iThreadResult listen_Service_(iThread *thd) {[m [31m- iService *d = userData_Thread(thd);[m [31m- while (d->fd >= 0) {[m [32m+[m[32m iService *d = userData_Thread(thd);[m[41m [m [32m+[m[32m while (d->fd != INVALID_SOCKET) {[m /* Wait for activity. */[m [31m- fd_set fds;[m [31m- FD_ZERO(&fds);[m [31m- FD_SET(d->fd, &fds);[m [31m- FD_SET(output_Pipe(&d->stop), &fds);[m [31m- if (select(0, &fds, NULL, NULL, NULL) == -1) {[m [32m+[m[32m HANDLE events[2] = { d->fdEvent, d->stopEvent };[m [32m+[m[32m DWORD rc = WaitForMultipleObjects(2, events, FALSE, INFINITE);[m [32m+[m[32m if (rc == WAIT_FAILED) {[m [32m+[m[32m iDebug("[Service] %s\n", errorMessage_Windows_(GetLastError()));[m break;[m }[m [31m- if (FD_ISSET(output_Pipe(&d->stop), &fds)) {[m [32m+[m[32m else if (rc == WAIT_OBJECT_0 + 1) {[m [32m+[m[32m iDebug("[Service] stop signal received\n");[m break;[m }[m [31m- if (FD_ISSET(d->fd, &fds)) {[m [31m- struct sockaddr_storage addr;[m [31m- int size = sizeof(addr);[m [31m- int incoming = accept(d->fd, (struct sockaddr *) &addr, &size);[m [31m- if (incoming < 0) {[m [31m- iWarning("[Service] error on accept: %s\n",[m [31m- errorMessage_Windows_(WSAGetLastError()));[m [32m+[m[32m else if (rc == WAIT_OBJECT_0) {[m [32m+[m[32m WSANETWORKEVENTS ev;[m [32m+[m[32m iZap(ev);[m [32m+[m[32m WSAEnumNetworkEvents(d->fd, d->fdEvent, &ev);[m [32m+[m[32m if (ev.lNetworkEvents & FD_ACCEPT) {[m [32m+[m[32m struct sockaddr_storage addr;[m [32m+[m[32m int size = sizeof(addr);[m [32m+[m[32m int incoming = accept(d->fd, (struct sockaddr *) &addr, &size);[m [32m+[m[32m if (incoming < 0) {[m [32m+[m[32m iWarning("[Service] error on accept: %s\n",[m [32m+[m[32m errorMessage_Windows_(WSAGetLastError()));[m [32m+[m[32m break;[m [32m+[m[32m }[m [32m+[m[32m iSocket *socket = newExisting_Socket(incoming, &addr, size);[m [32m+[m[32m iNotifyAudienceArgs(d, incomingAccepted, ServiceIncomingAccepted, socket);[m [32m+[m[32m iRelease(socket);[m [32m+[m[32m }[m [32m+[m[32m else if (ev.lNetworkEvents & FD_CLOSE) {[m [32m+[m[32m iDebug("[Service] socket closed\n");[m break;[m }[m [31m- iSocket *socket = newExisting_Socket(incoming, &addr, size);[m [31m- iNotifyAudienceArgs(d, incomingAccepted, ServiceIncomingAccepted, socket);[m [31m- iRelease(socket);[m }[m }[m iReleasePtr(&d->listening);[m [32m+[m[32m iDebug("[Service] listen thread exited\n");[m return 0;[m }[m [m void init_Service(iService *d, uint16_t port) {[m d->port = port;[m [31m- d->fd = NULL;[m [32m+[m[32m d->fd = INVALID_SOCKET;[m d->listening = NULL;[m [31m- init_Pipe(&d->stop);[m [32m+[m[32m //init_Pipe(&d->stop);[m [32m+[m[32m d->fdEvent = CreateEvent(NULL, FALSE, FALSE, NULL);[m [32m+[m[32m d->stopEvent = CreateEvent(NULL, FALSE, FALSE, NULL);[m d->incomingAccepted = new_Audience();[m }[m [m void deinit_Service(iService *d) {[m close_Service(d);[m [31m- deinit_Pipe(&d->stop);[m [32m+[m[32m //deinit_Pipe(&d->stop);[m [32m+[m[32m CloseHandle(d->stopEvent);[m [32m+[m[32m CloseHandle(d->fdEvent);[m iAssert(d->listening == NULL);[m [31m- iAssert(!d->fd);[m [32m+[m[32m iAssert(d->fd == INVALID_SOCKET);[m delete_Audience(d->incomingAccepted);[m }[m [m iBool isOpen_Service(const iService *d) {[m [31m- return d->fd >= 0;[m [32m+[m[32m return d->fd != INVALID_SOCKET;[m }[m [m iBool open_Service(iService *d) {[m [36m@@ -118,25 +132,26 @@[m [miBool open_Service(iService *d) {[m return iFalse;[m }[m d->fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);[m [31m- if (d->fd < 0) {[m [32m+[m[32m if (d->fd == INVALID_SOCKET) {[m iWarning("[Service] failed to open socket: %s\n", errorMessage_Windows_(WSAGetLastError()));[m return iFalse;[m }[m rc = bind(d->fd, info->ai_addr, info->ai_addrlen);[m if (rc < 0) {[m closesocket(d->fd);[m [31m- d->fd = NULL;[m [32m+[m[32m d->fd = INVALID_SOCKET;[m iWarning("[Service] failed to bind address: %s\n", errorMessage_Windows_(WSAGetLastError()));[m return iFalse;[m }[m rc = listen(d->fd, 10);[m if (rc < 0) {[m closesocket(d->fd);[m [31m- d->fd = NULL;[m [32m+[m[32m d->fd = INVALID_SOCKET;[m iWarning("[Service] failed to listen: %s\n", errorMessage_Windows_(WSAGetLastError()));[m return iFalse;[m }[m }[m [32m+[m[32m WSAEventSelect(d->fd, d->fdEvent, FD_ACCEPT | FD_CLOSE);[m d->listening = new_Thread(listen_Service_);[m setUserData_Thread(d->listening, d);[m start_Thread(d->listening);[m [36m@@ -146,12 +161,17 @@[m [miBool open_Service(iService *d) {[m void close_Service(iService *d) {[m if (d->listening) {[m /* Signal the listening thread to stop. */[m [31m- writeByte_Pipe(&d->stop, 1);[m [32m+[m[32m //writeByte_Pipe(&d->stop, 1);[m [32m+[m[32m SetEvent(d->stopEvent);[m closesocket(d->fd);[m [31m- d->fd = NULL;[m [32m+[m[32m d->fd = INVALID_SOCKET;[m join_Thread(d->listening);[m iAssert(d->listening == NULL);[m }[m [32m+[m[32m if (d->fd != INVALID_SOCKET) {[m [32m+[m[32m closesocket(d->fd);[m [32m+[m[32m d->fd = INVALID_SOCKET;[m [32m+[m[32m }[m }[m [m iDefineClass(Service)[m [1mdiff --git a/src/platform/win32/socket.c b/src/platform/win32/socket.c[m [1mindex 86ca92e..2ebf680 100644[m [1m--- a/src/platform/win32/socket.c[m [1m+++ b/src/platform/win32/socket.c[m [36m@@ -30,7 +30,6 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.[m #include "the_Foundation/mutex.h"[m #include "the_Foundation/thread.h"[m #include "the_Foundation/atomic.h"[m [31m-#include "pipe.h"[m #include "wide.h"[m [m #define WIN32_LEAN_AND_MEAN[m [36m@@ -56,7 +55,8 @@[m [mstruct Impl_Socket {[m enum iSocketStatus status;[m iAddress *address;[m SOCKET fd;[m [31m- iPipe *stopConnect;[m [32m+[m[32m HANDLE fdEvent;[m [32m+[m[32m HANDLE stopConnectEvent;[m iThread *connecting;[m iSocketThread *thread;[m iCondition allSent;[m [36m@@ -92,7 +92,7 @@[m [miDeclareClass(SocketThread)[m struct Impl_SocketThread {[m iThread thread;[m iSocket *socket;[m [31m- iPipe wakeup;[m [32m+[m[32m HANDLE wakeupEvent;[m iAtomicInt mode; /* enum iSocketThreadMode */[m };[m [m [36m@@ -107,33 +107,26 @@[m [mstatic iThreadResult run_SocketThread_(iThread *thread) {[m iBlock *inbuf = collect_Block(new_Block(0x20000));[m iGuardMutex(smx, {[m /* Connection has been formed. */[m [31m- delete_Pipe(d->socket->stopConnect);[m [31m- d->socket->stopConnect = NULL;[m [32m+[m[32m CloseHandle(d->socket->stopConnectEvent);[m [32m+[m[32m d->socket->stopConnectEvent = INVALID_HANDLE_VALUE;[m });[m while (value_Atomic(&d->mode) == run_SocketThreadMode) {[m if (bytesToSend_Socket(d->socket) > 0) {[m /* Make sure we won't block on select() when there's still data to send. */[m [31m- writeByte_Pipe(&d->wakeup, 0);[m [32m+[m[32m SetEvent(d->wakeupEvent);[m }[m /* Wait for activity. */[m [31m- fd_set reads, errors; {[m [31m- FD_ZERO(&reads);[m [31m- FD_ZERO(&errors);[m [31m- FD_SET(output_Pipe(&d->wakeup), &reads);[m [31m- FD_SET(d->socket->fd, &reads);[m [31m- FD_SET(d->socket->fd, &errors);[m [31m- int ready = select(0, &reads, NULL, &errors, NULL);[m [31m- if (ready == -1) {[m [31m- const DWORD err = WSAGetLastError();[m [31m- iWarning("[Socket] error from select(): %s\n", errorMessage_Windows_(err));[m [31m- return errno_Windows_(err);[m [31m- }[m [31m- }[m [31m- if (FD_ISSET(output_Pipe(&d->wakeup), &reads)) {[m [31m- readByte_Pipe(&d->wakeup);[m [32m+[m[32m HANDLE events[2] = { d->socket->fdEvent, d->wakeupEvent };[m [32m+[m[32m DWORD waitResult = WaitForMultipleObjects(2, events, FALSE, INFINITE);[m [32m+[m[32m if (waitResult == WAIT_FAILED) {[m [32m+[m[32m const DWORD err = GetLastError();[m [32m+[m[32m iWarning("[Socket] %s\n", errorMessage_Windows_(err));[m [32m+[m[32m return errno_Windows_(err);[m }[m /* Check for incoming data. */[m [31m- if (FD_ISSET(d->socket->fd, &reads)) {[m [32m+[m[32m WSANETWORKEVENTS netEvents;[m [32m+[m[32m WSAEnumNetworkEvents(d->socket->fd, d->socket->fdEvent, &netEvents);[m [32m+[m[32m if (netEvents.lNetworkEvents & FD_READ) {[m ssize_t readSize = recv(d->socket->fd, data_Block(inbuf), size_Block(inbuf), 0);[m if (readSize == 0) {[m iWarning("[Socket] peer closed the connection while we were receiving\n");[m [36m@@ -156,12 +149,11 @@[m [mstatic iThreadResult run_SocketThread_(iThread *thread) {[m iNotifyAudience(d->socket, readyRead, SocketReadyRead);[m }[m /* Problem with the socket? */[m [31m- if (FD_ISSET(d->socket->fd, &errors)) {[m [32m+[m[32m if (netEvents.lNetworkEvents & FD_CLOSE) {[m if (status_Socket(d->socket) == connected_SocketStatus) {[m [31m- const DWORD err = WSAGetLastError();[m [31m- iWarning("[Socket] error while receiving: %s\n", errorMessage_Windows_(err));[m [32m+[m[32m iDebug("[Socket] socket was closed\n");[m shutdown_Socket_(d->socket);[m [31m- return errno_Windows_(err);[m [32m+[m[32m return ENOTCONN;[m }[m return 0;[m }[m [36m@@ -220,18 +212,18 @@[m [mstatic void init_SocketThread(iSocketThread *d, iSocket *socket,[m setName_Thread(&d->thread, cstr_String(&name));[m deinit_String(&name);[m }[m [31m- init_Pipe(&d->wakeup);[m [32m+[m[32m d->wakeupEvent = CreateEvent(NULL, FALSE, FALSE, NULL);[m d->socket = socket;[m set_Atomic(&d->mode, mode);[m }[m [m static void deinit_SocketThread(iSocketThread *d) {[m [31m- deinit_Pipe(&d->wakeup);[m [32m+[m[32m CloseHandle(d->wakeupEvent);[m }[m [m static void exit_SocketThread_(iSocketThread *d) {[m set_Atomic(&d->mode, stop_SocketThreadMode);[m [31m- writeByte_Pipe(&d->wakeup, 1); // select() will exit[m [32m+[m[32m SetEvent(d->wakeupEvent);[m join_Thread(&d->thread);[m }[m [m [36m@@ -264,9 +256,10 @@[m [mstatic void init_Socket_(iSocket *d) {[m d->input = new_Buffer();[m openEmpty_Buffer(d->output);[m openEmpty_Buffer(d->input);[m [31m- d->fd = NULL;[m [32m+[m[32m d->fd = INVALID_SOCKET;[m [32m+[m[32m d->fdEvent = CreateEvent(NULL, FALSE, FALSE, NULL);[m d->address = NULL;[m [31m- d->stopConnect = new_Pipe(); /* used for aborting select() on user action */[m [32m+[m[32m d->stopConnectEvent = CreateEvent(NULL, FALSE, FALSE, NULL);[m d->connecting = NULL;[m d->thread = NULL;[m init_Condition(&d->allSent);[m [36m@@ -289,7 +282,10 @@[m [mvoid deinit_Socket(iSocket *d) {[m waitForFinished_Address(d->address);[m iReleasePtr(&d->address);[m deinit_Mutex(&d->mutex);[m [31m- delete_Pipe(d->stopConnect);[m [32m+[m[32m if (d->stopConnectEvent != INVALID_HANDLE_VALUE) {[m [32m+[m[32m CloseHandle(d->stopConnectEvent);[m [32m+[m[32m }[m [32m+[m[32m CloseHandle(d->fdEvent);[m deinit_Condition(&d->allSent);[m delete_Audience(d->connected);[m delete_Audience(d->disconnected);[m [36m@@ -322,15 +318,15 @@[m [mstatic iBool setNonBlocking_Socket_(iSocket *d, iBool set) {[m static void shutdown_Socket_(iSocket *d) {[m iGuardMutex(&d->mutex, {[m setStatus_Socket_(d, disconnecting_SocketStatus);[m [31m- if (d->fd) {[m [32m+[m[32m if (d->fd != INVALID_SOCKET) {[m shutdown(d->fd, SD_RECEIVE);[m }[m });[m iBool notify = iFalse;[m iGuardMutex(&d->mutex, {[m [31m- if (d->fd) {[m [32m+[m[32m if (d->fd != INVALID_SOCKET) {[m closesocket(d->fd);[m [31m- d->fd = NULL;[m [32m+[m[32m d->fd = INVALID_SOCKET;[m }[m notify = setStatus_Socket_(d, disconnected_SocketStatus);[m });[m [36m@@ -369,12 +365,13 @@[m [mstatic iThreadResult connectAsync_Socket_(iThread *thd) {[m cstrCollect_String(toString_SockAddr(addr)),[m addrSize, indexInFamily);[m const iSocketParameters sp = socketParametersIndex_Address(d->address, addrIndex);[m [31m- if (d->fd) {[m [32m+[m[32m if (d->fd != INVALID_SOCKET) {[m closesocket(d->fd);[m [31m- d->fd = NULL;[m [32m+[m[32m d->fd = INVALID_SOCKET;[m }[m iDebug("[Socket] family:%d type:%d protocol:%d\n", sp.family, sp.type, sp.protocol);[m d->fd = socket(sp.family, sp.type, sp.protocol);[m [32m+[m[32m WSAEventSelect(d->fd, d->fdEvent, FD_CONNECT | FD_READ | FD_CLOSE);[m if (!setNonBlocking_Socket_(d, iTrue)) {[m /* Wait indefinitely. */[m rc = connect(d->fd, addr, addrSize);[m [36m@@ -382,46 +379,36 @@[m [mstatic iThreadResult connectAsync_Socket_(iThread *thd) {[m else {[m /* Give up after a timeout. */[m rc = connect(d->fd, addr, addrSize);[m [31m- if (rc && WSAGetLastError() != WSAEINPROGRESS) {[m [32m+[m[32m if (rc && WSAGetLastError() != WSAEWOULDBLOCK) {[m iDebug("[Socket] result from connect: rc=%d (%s)\n",[m rc,[m errorMessage_Windows_(WSAGetLastError()));[m continue;[m }[m [31m- iAssert(d->stopConnect != NULL);[m [31m- const HANDLE stopFd = output_Pipe(d->stopConnect);[m [31m- fd_set stopSet;[m [31m- fd_set connSet;[m [31m- fd_set errSet;[m [31m- FD_ZERO(&stopSet);[m [31m- FD_ZERO(&connSet);[m [31m- FD_ZERO(&errSet);[m [31m- FD_SET(stopFd, &stopSet);[m [31m- FD_SET(d->fd, &connSet);[m [31m- FD_SET(d->fd, &errSet);[m [31m- struct timeval timeout = { .tv_sec = connectionTimeoutSeconds_Socket_ };[m [31m- rc = select(0, &stopSet, &connSet, &errSet, &timeout);[m [31m- if (rc > 0) {[m [31m- if (FD_ISSET(stopFd, &stopSet)) {[m [31m- setError_Socket_(d, ECONNABORTED, "Connection aborted");[m [31m- return ECONNABORTED;[m [31m- }[m [31m- socklen_t argLen = sizeof(int);[m [31m- int sockError = 0;[m [31m- getsockopt(d->fd, SOL_SOCKET, SO_ERROR, (char *) &sockError, &argLen);[m [31m- if (sockError) {[m [31m- errno = sockError;[m [31m- iDebug("[Socket] socket error: errno=%d (%s)\n",[m [31m- errno,[m [31m- strerror(errno));[m [31m- continue;[m [32m+[m[32m HANDLE events[2] = { d->stopConnectEvent, d->fdEvent };[m [32m+[m[32m DWORD waitResult = WaitForMultipleObjects([m [32m+[m[32m 2, events, FALSE, connectionTimeoutSeconds_Socket_ * 1000);[m [32m+[m[32m if (waitResult == WAIT_OBJECT_0 /* stop connect */) {[m [32m+[m[32m setError_Socket_(d, ECONNABORTED, "Connection aborted");[m [32m+[m[32m return ECONNABORTED;[m [32m+[m[32m }[m [32m+[m[32m else if (waitResult == WAIT_OBJECT_0 + 1) {[m [32m+[m[32m WSANETWORKEVENTS netEvents;[m [32m+[m[32m WSAEnumNetworkEvents(d->fd, d->fdEvent, &netEvents);[m [32m+[m[32m if (netEvents.lNetworkEvents & FD_CONNECT) {[m [32m+[m[32m const int err = netEvents.iErrorCode[FD_CONNECT_BIT];[m [32m+[m[32m if (err) {[m [32m+[m[32m errno = WSAECONNREFUSED;[m [32m+[m[32m iDebug("[Socket] socket error: %s\n", errorMessage_Windows_(err));[m [32m+[m[32m continue;[m [32m+[m[32m }[m [32m+[m[32m rc = 0; /* Success. */[m [32m+[m[32m setNonBlocking_Socket_(d, iFalse);[m }[m [31m- rc = 0; /* Success. */[m [31m- setNonBlocking_Socket_(d, iFalse);[m }[m else {[m rc = -1;[m [31m- errno = ETIMEDOUT;[m [32m+[m[32m errno = WSAETIMEDOUT;[m }[m }[m lock_Mutex(&d->mutex);[m [36m@@ -441,10 +428,10 @@[m [mstatic iThreadResult connectAsync_Socket_(iThread *thd) {[m }[m if (rc) {[m int errNum;[m [31m- char *msg;[m [32m+[m[32m const char *msg;[m if (isHostFound_Address(d->address)) {[m errNum = errno;[m [31m- msg = strerror(errNum);[m [32m+[m[32m msg = errorMessage_Windows_(errNum);[m }[m else {[m errNum = -1;[m [36m@@ -468,7 +455,7 @@[m [mstatic iBool open_Socket_(iSocket *d) {[m return iFalse;[m }[m else if (!d->connecting) {[m [31m- iAssert(!d->fd);[m [32m+[m[32m iAssert(d->fd == INVALID_SOCKET);[m setStatus_Socket_(d, connecting_SocketStatus);[m d->connecting = new_Thread(connectAsync_Socket_);[m setUserData_Thread(d->connecting, d);[m [36m@@ -504,6 +491,7 @@[m [miSocket *newExisting_Socket(int fd, const void *sockAddr, size_t sockAddrSize) {[m iSocket *d = iNew(Socket);[m init_Socket_(d);[m d->fd = fd;[m [32m+[m[32m WSAEventSelect(d->fd, d->fdEvent, FD_READ | FD_CLOSE);[m d->address = newSockAddr_Address(sockAddr, sockAddrSize, tcp_SocketType);[m setStatus_Socket_(d, connected_SocketStatus);[m startThread_Socket_(d);[m [36m@@ -551,8 +539,8 @@[m [mvoid close_Socket(iSocket *d) {[m return;[m }[m if (d->status == connecting_SocketStatus) {[m [31m- if (d->stopConnect) {[m [31m- write_Pipe(d->stopConnect, "0", 1);[m [32m+[m[32m if (d->stopConnectEvent != INVALID_HANDLE_VALUE) {[m [32m+[m[32m SetEvent(d->stopConnectEvent);[m }[m shutdown(d->fd, SD_SEND);[m }[m [36m@@ -612,7 +600,7 @@[m [mstatic size_t write_Socket_(iSocket *d, const void *data, size_t size) {[m iGuardMutex(&d->mutex, {[m writeData_Stream(stream_Buffer(d->output), data, size);[m if (d->thread) {[m [31m- writeByte_Pipe(&d->thread->wakeup, 0); // wake up the I/O thread[m [32m+[m[32m SetEvent(d->thread->wakeupEvent); /* wake up the I/O thread */[m }[m });[m return size;[m [1mdiff --git a/tests/t_network.c b/tests/t_network.c[m [1mindex 5b7c429..c4239e4 100644[m [1m--- a/tests/t_network.c[m [1m+++ b/tests/t_network.c[m [36m@@ -122,12 +122,12 @@[m [mstatic void communicate_(iAny *d, iService *sv, iSocket *sock) {[m start_Thread(receiver);[m }[m [m [31m-static bool connectTo_(const char *address) {[m [32m+[m[32mstatic iBool connectTo_(const char *address) {[m iSocket *sock = iClob(new_Socket(address, 14666));[m observeSocket_(sock);[m if (!open_Socket(sock)) {[m puts("Failed to connect");[m [31m- return false;[m [32m+[m[32m return iFalse;[m }[m puts("Type to send a message (empty to quit):");[m for (;;) {[m [36m@@ -139,7 +139,7 @@[m [mstatic bool connectTo_(const char *address) {[m writeData_Socket(sock, buf, strlen(buf));[m }[m puts("Good day!");[m [31m- return true;[m [32m+[m[32m return iTrue;[m }[m [m #if defined (iHaveTlsRequest)[m [36m@@ -197,6 +197,7 @@[m [mint main(int argc, char *argv[]) {[m else {[m printf("Failure! CURL says: %s\n", cstr_String(errorMessage_WebRequest(web)));[m }[m [32m+[m[32m deinit_Foundation();[m return 0;[m }[m #endif[m [36m@@ -236,6 +237,7 @@[m [mint main(int argc, char *argv[]) {[m hexEncode_Block(collect_Block(fingerprint_TlsCertificate(cert)))));[m printf("Recreated private key:\n%s", cstrCollect_String(privateKeyPem_TlsCertificate(cert)));[m delete_TlsCertificate(cert);[m [32m+[m[32m deinit_Foundation();[m return 0;[m }[m iCommandLineArg *tlsArgs = iClob(checkArgumentValues_CommandLine(cmdline, "t;tls", 2));[m [36m@@ -252,6 +254,7 @@[m [mint main(int argc, char *argv[]) {[m submit_TlsRequest(tls);[m waitForFinished_TlsRequest(tls);[m printf("We are done.\n");[m [32m+[m[32m deinit_Foundation();[m return 0;[m }[m }[m [36m@@ -261,6 +264,7 @@[m [mint main(int argc, char *argv[]) {[m iConnect(Service, sv, incomingAccepted, sv, communicate_);[m if (!open_Service(sv)) {[m puts("Failed to start service");[m [32m+[m[32m deinit_Foundation();[m return 1;[m }[m puts("Press Enter to quit..."); {[m [36m@@ -269,6 +273,7 @@[m [mint main(int argc, char *argv[]) {[m iWarning("fgets failed\n");[m }[m }[m [32m+[m[32m close_Service(sv);[m }[m else if (contains_CommandLine(cmdline, "c;client")) {[m connectTo_("localhost");[m
text/gemini; charset=utf-8
This content has been proxied by September (ba2dc).