=> 881829672d543bbbd3862fa55d6bcb0c422770ae
[1mdiff --git a/src/platform/win32/datagram.c b/src/platform/win32/datagram.c[m [1mindex ef548ea..b7aaba3 100644[m [1m--- a/src/platform/win32/datagram.c[m [1m+++ b/src/platform/win32/datagram.c[m [36m@@ -1,6 +1,6 @@[m /** @file win32/datagram.c UDP socket.[m [m [31m-@authors Copyright (c) 2018 Jaakko Keränen[m [32m+[m[32m@authors Copyright (c) 2018-2023 Jaakko Keränen [m[41m [m [m @par License[m [m [36m@@ -26,36 +26,236 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.[m */[m [m #include "the_Foundation/datagram.h"[m [32m+[m[32m#include "the_Foundation/mutex.h"[m[41m [m [32m+[m[32m#include "the_Foundation/address.h"[m[41m [m #include "the_Foundation/queue.h"[m [32m+[m[32m#include "the_Foundation/thread.h"[m[41m [m [32m+[m[32m#include "the_Foundation/ptrset.h"[m[41m [m [32m+[m[32m#include "wide.h"[m[41m [m [32m+[m[41m [m [32m+[m[32m#define WIN32_LEAN_AND_MEAN[m[41m [m [32m+[m[32m#include [m[41m [m [32m+[m[32m#include [m[41m [m [32m+[m[32m#include [m[41m [m [32m+[m[41m [m [32m+[m[32m/* address.c */[m[41m [m [32m+[m[32mint getSockAddr_Address(const iAddress * d,[m[41m [m [32m+[m[32m struct sockaddr **addr_out,[m[41m [m [32m+[m[32m socklen_t * addrSize_out,[m[41m [m [32m+[m[32m int family,[m[41m [m [32m+[m[32m int indexInFamily);[m[41m [m [32m+[m[41m [m [32m+[m[32miDeclareClass(Message)[m[41m [m [32m+[m[41m [m [32m+[m[32mstruct Impl_Message {[m[41m [m [32m+[m[32m iObject object;[m[41m [m [32m+[m[32m iAddress *address;[m[41m [m [32m+[m[32m iBlock data;[m[41m [m [32m+[m[32m};[m[41m [m [32m+[m[41m [m [32m+[m[32mstatic void init_Message(iMessage *d) {[m[41m [m [32m+[m[32m d->address = NULL;[m[41m [m [32m+[m[32m init_Block(&d->data, 0);[m[41m [m [32m+[m[32m}[m[41m [m [32m+[m[41m [m [32m+[m[32mstatic void deinit_Message(iMessage *d) {[m[41m [m [32m+[m[32m iRelease(d->address);[m[41m [m [32m+[m[32m deinit_Block(&d->data);[m[41m [m [32m+[m[32m}[m[41m [m [32m+[m[41m [m [32m+[m[32miDefineObjectConstruction(Message)[m[41m [m [32m+[m[32miDefineClass(Message)[m[41m [m [32m+[m[41m [m [32m+[m[32m/*-------------------------------------------------------------------------------------*/[m[41m [m [m struct Impl_Datagram {[m iObject object;[m iMutex mutex;[m uint16_t port;[m [31m- // int fd;[m [32m+[m[32m SOCKET fd;[m[41m [m [32m+[m[32m HANDLE fdEvent;[m[41m [m iAddress *address;[m iAddress *destination;[m iCondition allSent;[m iCondition messageReceived;[m iQueue *output;[m iQueue *input;[m [31m- // Audiences:[m [32m+[m[32m /* Audiences: */[m[41m [m iAudience *error;[m iAudience *message;[m iAudience *writeFinished;[m };[m [m [31m-//---------------------------------------------------------------------------------------[m [32m+[m[32miDeclareClass(DatagramThread)[m[41m [m [m [31m-void init_DatagramThreads_(void) {[m [32m+[m[32menum iDatagramThreadMode {[m[41m [m [32m+[m[32m run_DatagramThreadMode,[m[41m [m [32m+[m[32m stop_DatagramThreadMode,[m[41m [m [32m+[m[32m};[m[41m [m [m [32m+[m[32mstruct Impl_DatagramThread {[m[41m [m [32m+[m[32m iThread thread;[m[41m [m [32m+[m[32m HANDLE wakeupEvent;[m[41m [m [32m+[m[32m iMutex mutex;[m[41m [m [32m+[m[32m iPtrSet datagrams;[m[41m [m [32m+[m[32m iAtomicInt mode;[m[41m [m [32m+[m[32m};[m[41m [m [32m+[m[41m [m [32m+[m[32m#define iMessageMaxDataSize 4096[m[41m [m [32m+[m[41m [m [32m+[m[32mstatic iThreadResult run_DatagramThread_(iThread *thread) {[m[41m [m [32m+[m[32m iDatagramThread *d = (iAny *) thread;[m[41m [m [32m+[m[32m iMutex *mtx = &d->mutex;[m[41m [m [32m+[m[32m iArray events;[m[41m [m [32m+[m[32m init_Array(&events, sizeof(HANDLE));[m[41m [m [32m+[m[32m while (d->mode == run_DatagramThreadMode) {[m[41m [m [32m+[m[32m /* Wait for activity. */[m[41m [m [32m+[m[32m clear_Array(&events);[m[41m [m [32m+[m[32m pushBack_Array(&events, &d->wakeupEvent);[m[41m [m [32m+[m[32m iGuardMutex(mtx, {[m[41m [m [32m+[m[32m iConstForEach(PtrSet, i, &d->datagrams) {[m[41m [m [32m+[m[32m const iDatagram *dgm = *i.value;[m[41m [m [32m+[m[32m pushBack_Array(&events, &dgm->fdEvent);[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m });[m[41m [m [32m+[m[32m const DWORD waitResult =[m[41m [m [32m+[m[32m WaitForMultipleObjects(size_Array(&events), data_Array(&events), FALSE, INFINITE);[m[41m [m [32m+[m[32m if (waitResult == WAIT_FAILED) {[m[41m [m [32m+[m[32m return GetLastError();[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m /* Clear the wakeup. */[m[41m [m [32m+[m[32m lock_Mutex(mtx);[m[41m [m [32m+[m[32m if (waitResult > WAIT_OBJECT_0) { /* thread locked during datagram iteration */[m[41m [m [32m+[m[32m int eventIndex = 1;[m[41m [m [32m+[m[32m iForEach(PtrSet, i, &d->datagrams) {[m[41m [m [32m+[m[32m iDatagram *dgm = *i.value;[m[41m [m [32m+[m[32m if (waitResult != WAIT_OBJECT_0 + eventIndex) {[m[41m [m [32m+[m[32m continue;[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m WSANETWORKEVENTS netEvents;[m[41m [m [32m+[m[32m WSAEnumNetworkEvents(dgm->fd, dgm->fdEvent, &netEvents);[m[41m [m [32m+[m[32m /* Problem with the socket? */[m[41m [m [32m+[m[32m if (netEvents.lNetworkEvents & FD_CLOSE) {[m[41m [m [32m+[m[32m iWarning("[Datagram] socket %i is closed\n", dgm->fd);[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m /* Check for incoming data. */[m[41m [m [32m+[m[32m else if (netEvents.lNetworkEvents & FD_READ) {[m[41m [m [32m+[m[32m char buf[iMessageMaxDataSize];[m[41m [m [32m+[m[32m struct sockaddr_storage addr;[m[41m [m [32m+[m[32m socklen_t addrSize = sizeof(addr);[m[41m [m [32m+[m[32m ssize_t dataSize = recvfrom([m[41m [m [32m+[m[32m dgm->fd, buf, iMessageMaxDataSize - 1, 0, (struct sockaddr *) &addr, &addrSize);[m[41m [m [32m+[m[32m if (dataSize == -1) {[m[41m [m [32m+[m[32m const DWORD err = WSAGetLastError();[m[41m [m [32m+[m[32m iWarning("[Datagram] socket %i: error while receiving: %s\n",[m[41m [m [32m+[m[32m dgm->fd, errorMessage_Windows_(err));[m[41m [m [32m+[m[32m iNotifyAudienceArgs(dgm, error, DatagramError, err, errorMessage_Windows_(err));[m[41m [m [32m+[m[32m /* Maybe remove the datagram from the set? */[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m /* Keep the data as a message. */ {[m[41m [m [32m+[m[32m iMessage *msg = new_Message();[m[41m [m [32m+[m[32m msg->address = newSockAddr_Address(&addr, addrSize, udp_SocketType);[m[41m [m [32m+[m[32m setData_Block(&msg->data, buf, dataSize);[m[41m [m [32m+[m[32m put_Queue(dgm->input, msg);[m[41m [m [32m+[m[32m iRelease(msg);[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m iGuardMutex(&dgm->mutex, signal_Condition(&dgm->messageReceived));[m[41m [m [32m+[m[32m if (dgm->message) {[m[41m [m [32m+[m[32m iNotifyAudience(dgm, message, DatagramMessage);[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m eventIndex++;[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m unlock_Mutex(mtx);[m[41m [m [32m+[m[32m /* Now that received messages have been handled, check for outgoing messages. */[m[41m [m [32m+[m[32m lock_Mutex(mtx); { // thread locked during datagram iteration[m[41m [m [32m+[m[32m iForEach(PtrSet, i, &d->datagrams) {[m[41m [m [32m+[m[32m iDatagram *dgm = *i.value;[m[41m [m [32m+[m[32m iMessage *msg = NULL;[m[41m [m [32m+[m[32m iBool didSend = iFalse;[m[41m [m [32m+[m[32m while ((msg = tryTake_Queue(dgm->output)) != NULL) {[m[41m [m [32m+[m[32m socklen_t destLen;[m[41m [m [32m+[m[32m struct sockaddr *destAddr;[m[41m [m [32m+[m[32m getSockAddr_Address(msg->address, &destAddr, &destLen, AF_INET, 0);[m[41m [m [32m+[m[32m ssize_t rc = sendto(dgm->fd,[m[41m [m [32m+[m[32m data_Block(&msg->data),[m[41m [m [32m+[m[32m size_Block(&msg->data),[m[41m [m [32m+[m[32m 0,[m[41m [m [32m+[m[32m destAddr,[m[41m [m [32m+[m[32m destLen);[m[41m [m [32m+[m[32m if (rc != (ssize_t) size_Block(&msg->data)) {[m[41m [m [32m+[m[32m const DWORD err = WSAGetLastError();[m[41m [m [32m+[m[32m iWarning("[Datagram] socket %i: error while sending %zu bytes: %s\n",[m[41m [m [32m+[m[32m dgm->fd,[m[41m [m [32m+[m[32m size_Block(&msg->data),[m[41m [m [32m+[m[32m errorMessage_Windows_(err));[m[41m [m [32m+[m[32m iNotifyAudienceArgs(dgm, error, DatagramError, err, errorMessage_Windows_(err));[m[41m [m [32m+[m[32m /* Maybe remove the datagram from the set? */[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m iRelease(msg);[m[41m [m [32m+[m[32m didSend = iTrue;[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m if (didSend) {[m[41m [m [32m+[m[32m iGuardMutex(&dgm->mutex, signal_Condition(&dgm->allSent));[m[41m [m [32m+[m[32m if (dgm->writeFinished) {[m[41m [m [32m+[m[32m iNotifyAudience(dgm, writeFinished, DatagramWriteFinished);[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m unlock_Mutex(mtx);[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m deinit_Array(&events);[m[41m [m [32m+[m[32m return 0;[m[41m [m }[m [m [31m-void deinit_DatagramThreads_(void) {[m [32m+[m[32mstatic void init_DatagramThread(iDatagramThread *d) {[m[41m [m [32m+[m[32m init_Thread(&d->thread, run_DatagramThread_);[m[41m [m [32m+[m[32m setName_Thread(&d->thread, "DatagramThread");[m[41m [m [32m+[m[32m d->wakeupEvent = CreateEvent(NULL, FALSE, FALSE, NULL);[m[41m [m [32m+[m[32m init_Mutex(&d->mutex);[m[41m [m [32m+[m[32m init_PtrSet(&d->datagrams);[m[41m [m [32m+[m[32m d->mode = run_DatagramThreadMode;[m[41m [m [32m+[m[32m}[m[41m [m [m [32m+[m[32mstatic void deinit_DatagramThread(iDatagramThread *d) {[m[41m [m [32m+[m[32m iGuardMutex(&d->mutex, {[m[41m [m [32m+[m[32m deinit_PtrSet(&d->datagrams);[m[41m [m [32m+[m[32m deinit_Mutex(&d->mutex);[m[41m [m [32m+[m[32m CloseHandle(d->wakeupEvent);[m[41m [m [32m+[m[32m });[m[41m [m }[m [m [31m-//---------------------------------------------------------------------------------------[m [32m+[m[32miDefineObjectConstruction(DatagramThread)[m[41m [m [32m+[m[41m [m [32m+[m[32miLocalDef void start_DatagramThread_(iDatagramThread *d) { start_Thread(&d->thread); }[m[41m [m [32m+[m[41m [m [32m+[m[32mstatic void exit_DatagramThread_(iDatagramThread *d) {[m[41m [m [32m+[m[32m d->mode = stop_DatagramThreadMode;[m[41m [m [32m+[m[32m SetEvent(d->wakeupEvent);[m[41m [m [32m+[m[32m join_Thread(&d->thread);[m[41m [m [32m+[m[32m}[m[41m [m [32m+[m[41m [m [32m+[m[32mstatic iDatagramThread *datagramIO_ = NULL;[m[41m [m [32m+[m[41m [m [32m+[m[32mvoid init_DatagramThreads_(void) {[m[41m [m [32m+[m[32m iAssert(datagramIO_ == NULL);[m[41m [m [32m+[m[32m datagramIO_ = new_DatagramThread();[m[41m [m [32m+[m[32m start_DatagramThread_(datagramIO_);[m[41m [m [32m+[m[32m}[m[41m [m [32m+[m[41m [m [32m+[m[32mvoid deinit_DatagramThreads_(void) { /* called from deinit_Foundation */[m[41m [m [32m+[m[32m if (datagramIO_) {[m[41m [m [32m+[m[32m exit_DatagramThread_(datagramIO_);[m[41m [m [32m+[m[32m iRelease(datagramIO_);[m[41m [m [32m+[m[32m datagramIO_ = NULL;[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m}[m[41m [m [32m+[m[41m [m [32m+[m[32miDefineSubclass(DatagramThread, Thread)[m[41m [m [32m+[m[41m [m [32m+[m[32m/*-------------------------------------------------------------------------------------*/[m[41m [m [m iDefineObjectConstruction(Datagram)[m iDefineClass(Datagram)[m [36m@@ -64,61 +264,165 @@[m [miDefineAudienceGetter(Datagram, message)[m iDefineAudienceGetter(Datagram, writeFinished)[m [m void init_Datagram(iDatagram *d) {[m [31m- iUnused(d);[m [32m+[m[32m init_Mutex(&d->mutex);[m[41m [m [32m+[m[32m d->port = 0;[m[41m [m [32m+[m[32m d->fd = INVALID_SOCKET;[m[41m [m [32m+[m[32m d->fdEvent = CreateEvent(NULL, FALSE, FALSE, NULL);[m[41m [m [32m+[m[32m d->address = NULL;[m[41m [m [32m+[m[32m d->destination = NULL;[m[41m [m [32m+[m[32m init_Condition(&d->allSent);[m[41m [m [32m+[m[32m init_Condition(&d->messageReceived);[m[41m [m [32m+[m[32m d->output = new_Queue();[m[41m [m [32m+[m[32m d->input = new_Queue();[m[41m [m [32m+[m[32m d->error = NULL;[m[41m [m [32m+[m[32m d->message = NULL;[m[41m [m [32m+[m[32m d->writeFinished = NULL;[m[41m [m }[m [m [31m-void deinit_Datagram(iDatagram *d) {[m [31m- iUnused(d);[m [32m+[m[32miBool isOpen_Datagram(const iDatagram *d) {[m[41m [m [32m+[m[32m return d->fd != INVALID_SOCKET;[m[41m [m }[m [m [31m-iBool open_Datagram(iDatagram *d, uint16_t port) {[m [31m- iUnused(d, port);[m [31m- return iFalse;[m [32m+[m[32muint16_t port_Datagram(const iDatagram *d) {[m[41m [m [32m+[m[32m return d->port;[m[41m [m }[m [m [31m-void close_Datagram(iDatagram *d) {[m [31m- iUnused(d);[m [32m+[m[32miBool open_Datagram(iDatagram *d, uint16_t port) {[m[41m [m [32m+[m[32m if (isOpen_Datagram(d)) {[m[41m [m [32m+[m[32m return iFalse;[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m iAssert(port);[m[41m [m [32m+[m[32m if (d->address) iRelease(d->address);[m[41m [m [32m+[m[32m d->address = new_Address();[m[41m [m [32m+[m[32m d->port = port;[m[41m [m [32m+[m[32m lookupCStr_Address(d->address, NULL, port, udp_SocketType);[m[41m [m [32m+[m[32m waitForFinished_Address(d->address);[m[41m [m [32m+[m[32m /* Create and bind a socket for listening to incoming messages. */ {[m[41m [m [32m+[m[32m socklen_t sockLen;[m[41m [m [32m+[m[32m struct sockaddr *sockAddr;[m[41m [m [32m+[m[32m iSocketParameters sp = socketParametersFamily_Address(d->address, AF_INET);[m[41m [m [32m+[m[32m d->fd = socket(sp.family, sp.type, sp.protocol);[m[41m [m [32m+[m[32m if (d->fd == INVALID_SOCKET) {[m[41m [m [32m+[m[32m iWarning("[Datagram] error creating socket: %s\n", errorMessage_Windows_(WSAGetLastError()));[m[41m [m [32m+[m[32m iReleasePtr(&d->address);[m[41m [m [32m+[m[32m return iFalse;[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m WSAEventSelect(d->fd, d->fdEvent, FD_READ | FD_CLOSE);[m[41m [m [32m+[m[32m /* Enable broadcasting. */ {[m[41m [m [32m+[m[32m const int broadcast = 1;[m[41m [m [32m+[m[32m setsockopt(d->fd, SOL_SOCKET, SO_BROADCAST, (char *) &broadcast, sizeof(broadcast));[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m getSockAddr_Address(d->address, &sockAddr, &sockLen, AF_INET, 0 /* first one */);[m[41m [m [32m+[m[32m if (bind(d->fd, sockAddr, sockLen) == -1) {[m[41m [m [32m+[m[32m iReleasePtr(&d->address);[m[41m [m [32m+[m[32m closesocket(d->fd);[m[41m [m [32m+[m[32m d->fd = INVALID_SOCKET;[m[41m [m [32m+[m[32m iWarning("[Datagram] error binding socket (port %u): %s\n", port,[m[41m [m [32m+[m[32m errorMessage_Windows_(WSAGetLastError()));[m[41m [m [32m+[m[32m return iFalse;[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m /* All open datagrams share the I/O thread. */ {[m[41m [m [32m+[m[32m if (!datagramIO_) {[m[41m [m [32m+[m[32m init_DatagramThreads_();[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m iGuardMutex(&datagramIO_->mutex, insert_PtrSet(&datagramIO_->datagrams, d));[m[41m [m [32m+[m[32m SetEvent(datagramIO_->wakeupEvent); /* update the set of waiting datagrams */[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m return iTrue;[m[41m [m }[m [m [31m-iBool isOpen_Datagram(const iDatagram *d) {[m [31m- iUnused(d);[m [31m- return iFalse;[m [32m+[m[32mvoid close_Datagram(iDatagram *d) {[m[41m [m [32m+[m[32m flush_Datagram(d);[m[41m [m [32m+[m[32m /* Remove from the I/O thread. */[m[41m [m [32m+[m[32m if (datagramIO_) {[m[41m [m [32m+[m[32m iGuardMutex(&datagramIO_->mutex, remove_PtrSet(&datagramIO_->datagrams, d));[m[41m [m [32m+[m[32m SetEvent(datagramIO_->wakeupEvent); /* update the set of waiting datagrams */[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m iGuardMutex(&d->mutex, {[m[41m [m [32m+[m[32m if (isOpen_Datagram(d)) {[m[41m [m [32m+[m[32m closesocket(d->fd);[m[41m [m [32m+[m[32m d->fd = INVALID_SOCKET;[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m });[m[41m [m }[m [m [31m-uint16_t port_Datagram(const iDatagram *d) {[m [31m- iUnused(d);[m [31m- return 0;[m [32m+[m[32mvoid deinit_Datagram(iDatagram *d) {[m[41m [m [32m+[m[32m close_Datagram(d);[m[41m [m [32m+[m[32m iGuardMutex(&d->mutex, {[m[41m [m [32m+[m[32m iRelease(d->address);[m[41m [m [32m+[m[32m iRelease(d->destination);[m[41m [m [32m+[m[32m iRelease(d->output);[m[41m [m [32m+[m[32m iRelease(d->input);[m[41m [m [32m+[m[32m deinit_Condition(&d->allSent);[m[41m [m [32m+[m[32m deinit_Condition(&d->messageReceived);[m[41m [m [32m+[m[32m delete_Audience(d->error);[m[41m [m [32m+[m[32m delete_Audience(d->message);[m[41m [m [32m+[m[32m delete_Audience(d->writeFinished);[m[41m [m [32m+[m[32m CloseHandle(d->fdEvent);[m[41m [m [32m+[m[32m });[m[41m [m [32m+[m[32m deinit_Mutex(&d->mutex);[m[41m [m }[m [m void send_Datagram(iDatagram *d, const iBlock *data, const iAddress *to) {[m [31m- iUnused(d, data, to);[m [32m+[m[32m iAssert(to != NULL);[m[41m [m [32m+[m[32m iMessage *msg = new_Message();[m[41m [m [32m+[m[32m /* Block here until the address is resolved. We cannot block the datagram I/O thread because */[m[41m [m [32m+[m[32m /* it handles multiple sockets at once. */[m[41m [m [32m+[m[32m waitForFinished_Address(to);[m[41m [m [32m+[m[32m msg->address = ref_Object(to);[m[41m [m [32m+[m[32m set_Block(&msg->data, data);[m[41m [m [32m+[m[32m put_Queue(d->output, msg);[m[41m [m [32m+[m[32m iRelease(msg);[m[41m [m [32m+[m[32m SetEvent(datagramIO_->wakeupEvent);[m[41m [m }[m [m void sendData_Datagram(iDatagram *d, const void *data, size_t size, const iAddress *to) {[m [31m- iUnused(d, data, size, to);[m [32m+[m[32m iBlock buf;[m[41m [m [32m+[m[32m initData_Block(&buf, data, size);[m[41m [m [32m+[m[32m send_Datagram(d, &buf, to);[m[41m [m [32m+[m[32m deinit_Block(&buf);[m[41m [m }[m [m iBlock *receive_Datagram(iDatagram *d, iAddress **from_out) {[m [31m- iUnused(d, from_out);[m [31m- return NULL;[m [32m+[m[32m iMessage *msg = tryTake_Queue(d->input);[m[41m [m [32m+[m[32m iBlock *data = NULL;[m[41m [m [32m+[m[32m if (msg) {[m[41m [m [32m+[m[32m data = copy_Block(&msg->data);[m[41m [m [32m+[m[32m if (from_out) *from_out = ref_Object(msg->address);[m[41m [m [32m+[m[32m iRelease(msg);[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m else {[m[41m [m [32m+[m[32m if (from_out) *from_out = NULL;[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m return data;[m[41m [m }[m [m void connect_Datagram(iDatagram *d, const iAddress *address) {[m [31m- iUnused(d, address);[m [32m+[m[32m iRelease(d->destination);[m[41m [m [32m+[m[32m d->destination = ref_Object(address);[m[41m [m }[m [m void write_Datagram(iDatagram *d, const iBlock *data) {[m [31m- iUnused(d, data);[m [32m+[m[32m send_Datagram(d, data, d->destination);[m[41m [m }[m [m void writeData_Datagram(iDatagram *d, const void *data, size_t size) {[m [31m- iUnused(d, data, size);[m [32m+[m[32m iBlock buf;[m[41m [m [32m+[m[32m initData_Block(&buf, data, size);[m[41m [m [32m+[m[32m write_Datagram(d, &buf);[m[41m [m [32m+[m[32m deinit_Block(&buf);[m[41m [m }[m [m [31m-void disconnect_Datagram (iDatagram *d) {[m [31m- iUnused(d);[m [32m+[m[32mvoid disconnect_Datagram(iDatagram *d) {[m[41m [m [32m+[m[32m iRelease(d->destination);[m[41m [m [32m+[m[32m d->destination = NULL;[m[41m [m }[m [m void flush_Datagram(iDatagram *d) {[m [31m- iUnused(d);[m [32m+[m[32m iGuardMutex(&d->mutex, {[m[41m [m [32m+[m[32m if (isOpen_Datagram(d) && !isEmpty_Queue(d->output)) {[m[41m [m [32m+[m[32m wait_Condition(&d->allSent, &d->mutex);[m[41m [m [32m+[m[32m }[m[41m [m [32m+[m[32m });[m[41m [m }[m
text/gemini; charset=utf-8
This content has been proxied by September (3851b).