- new function in WINGs: WMSetConnectionShutdownOnClose()
[wmaker-crm.git] / WINGs / connection.c
blob94878e7d36cd4cdf8fc96f998c200d6f509c1750
1 /*
2 * WINGs WMConnection function library
4 * Copyright (c) 1999-2002 Dan Pascu
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * TODO:
24 * - decide if we want to support connections with external sockets, else
25 * clean up the structure of the unneeded members.
26 * - decide what to do with all wwarning() calls that are still there.
31 #include "wconfig.h"
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <stdarg.h>
39 #include <errno.h>
40 #include <sys/socket.h>
41 #include <netinet/in.h>
42 #include <arpa/inet.h>
43 #include <netdb.h>
44 #include <signal.h>
45 #ifdef __FreeBSD__
46 #include <sys/signal.h>
47 #endif
49 #include "WINGs.h"
52 /* Some older systems does not define this (linux libc5, maybe others too) */
53 #ifndef SHUT_RDWR
54 # define SHUT_RDWR 2
55 #endif
57 /* For SunOS */
58 #ifndef SA_RESTART
59 # define SA_RESTART 0
60 #endif
62 /* For Solaris */
63 #ifndef INADDR_NONE
64 # define INADDR_NONE -1
65 #endif
67 /* Stuff for setting the sockets into non-blocking mode. */
68 /*#ifdef __POSIX_SOURCE
69 # define NONBLOCK_OPT O_NONBLOCK
70 #else
71 # define NONBLOCK_OPT FNDELAY
72 #endif*/
74 #define NONBLOCK_OPT O_NONBLOCK
76 #define NETBUF_SIZE 4096
78 #define DEF_TIMEOUT 600 /* 600 seconds == 10 minutes */
82 int WCErrorCode = 0;
84 static Bool SigInitialized = False;
86 static unsigned int DefaultTimeout = DEF_TIMEOUT;
87 static unsigned int OpenTimeout = DEF_TIMEOUT;
91 typedef struct TimeoutData {
92 unsigned timeout;
93 WMHandlerID *handler;
94 } TimeoutData;
97 typedef struct W_Connection {
98 int sock; /* the socket we speak through */
100 struct {
101 WMHandlerID *read; /* the input read handler */
102 WMHandlerID *write; /* the input write handler */
103 WMHandlerID *exception; /* the input exception handler */
104 } handler;
106 ConnectionDelegate *delegate; /* client delegates */
107 void *clientData; /* client data */
108 unsigned int uflags; /* flags for the client */
110 WMArray *outputQueue;
111 unsigned bufPos;
113 TimeoutData sendTimeout;
114 TimeoutData openTimeout;
116 WMConnectionState state;
117 WMConnectionTimeoutState timeoutState;
119 char *address;
120 char *service;
121 char *protocol;
123 Bool closeOnRelease;
124 Bool shutdownOnClose;
125 Bool wasNonBlocking;
126 Bool isNonBlocking;
128 } W_Connection;
132 static void
133 clearOutputQueue(WMConnection *cPtr)
135 cPtr->bufPos = 0;
136 WMEmptyArray(cPtr->outputQueue);
140 static void
141 openTimeout(void *cdata)
143 WMConnection *cPtr = (WMConnection*) cdata;
145 cPtr->openTimeout.handler = NULL;
146 if (cPtr->handler.write) {
147 WMDeleteInputHandler(cPtr->handler.write);
148 cPtr->handler.write = NULL;
150 if (cPtr->state != WCConnected) {
151 cPtr->state = WCTimedOut;
152 cPtr->timeoutState = WCTWhileOpening;
153 if (cPtr->delegate && cPtr->delegate->didTimeout) {
154 (*cPtr->delegate->didTimeout)(cPtr->delegate, cPtr);
155 } else {
156 WMCloseConnection(cPtr);
157 cPtr->state = WCTimedOut; /* the above set state to WCClosed */
163 static void
164 sendTimeout(void *cdata)
166 WMConnection *cPtr = (WMConnection*) cdata;
168 cPtr->sendTimeout.handler = NULL;
169 if (cPtr->handler.write) {
170 WMDeleteInputHandler(cPtr->handler.write);
171 cPtr->handler.write = NULL;
173 if (WMGetArrayItemCount(cPtr->outputQueue)>0) {
174 clearOutputQueue(cPtr);
175 cPtr->state = WCTimedOut;
176 cPtr->timeoutState = WCTWhileSending;
177 if (cPtr->delegate && cPtr->delegate->didTimeout) {
178 (*cPtr->delegate->didTimeout)(cPtr->delegate, cPtr);
179 } else {
180 WMCloseConnection(cPtr);
181 cPtr->state = WCTimedOut; /* the above set state to WCClosed */
187 static void
188 inputHandler(int fd, int mask, void *clientData)
190 WMConnection *cPtr = (WMConnection*)clientData;
192 if (cPtr->state==WCClosed || cPtr->state==WCDied)
193 return;
195 if ((mask & WIWriteMask)) {
196 int result;
198 if (cPtr->state == WCInProgress) {
199 Bool failed;
200 int len = sizeof(result);
202 WCErrorCode = 0;
203 if (getsockopt(cPtr->sock, SOL_SOCKET, SO_ERROR,
204 (void*)&result, &len) == 0 && result != 0) {
205 cPtr->state = WCFailed;
206 WCErrorCode = result;
207 failed = True;
208 /* should call wsyserrorwithcode(result, ...) here? */
209 } else {
210 cPtr->state = WCConnected;
211 failed = False;
214 if (cPtr->handler.write) {
215 WMDeleteInputHandler(cPtr->handler.write);
216 cPtr->handler.write = NULL;
219 if (cPtr->openTimeout.handler) {
220 WMDeleteTimerHandler(cPtr->openTimeout.handler);
221 cPtr->openTimeout.handler = NULL;
224 if (cPtr->delegate && cPtr->delegate->didInitialize)
225 (*cPtr->delegate->didInitialize)(cPtr->delegate, cPtr);
227 /* we use failed and not cPtr->state here, because cPtr may be
228 * destroyed by the delegate called above if the connection failed
230 if (failed)
231 return;
232 } else if (cPtr->state == WCConnected) {
233 result = WMFlushConnection(cPtr);
234 if (result>0 && cPtr->delegate && cPtr->delegate->canResumeSending) {
235 (*cPtr->delegate->canResumeSending)(cPtr->delegate, cPtr);
240 if (!cPtr->delegate)
241 return;
243 /* if the connection died, may get destroyed in the delegate, so retain */
244 wretain(cPtr);
246 if ((mask & WIReadMask) && cPtr->delegate->didReceiveInput)
247 (*cPtr->delegate->didReceiveInput)(cPtr->delegate, cPtr);
249 if ((mask & WIExceptMask) && cPtr->delegate->didCatchException)
250 (*cPtr->delegate->didCatchException)(cPtr->delegate, cPtr);
252 wrelease(cPtr);
256 static Bool
257 setSocketNonBlocking(int sock, Bool flag)
259 int state;
260 Bool isNonBlock;
262 state = fcntl(sock, F_GETFL, 0);
264 if (state < 0) {
265 /* set WCErrorCode here? -Dan*/
266 return False;
269 isNonBlock = (state & NONBLOCK_OPT) != 0;
271 if (flag) {
272 if (isNonBlock)
273 return True;
274 state |= NONBLOCK_OPT;
275 } else {
276 if (!isNonBlock)
277 return True;
278 state &= ~NONBLOCK_OPT;
281 if (fcntl(sock, F_SETFL, state) < 0) {
282 /* set WCErrorCode here? -Dan*/
283 return False;
286 return True;
290 static void
291 setConnectionAddress(WMConnection *cPtr, struct sockaddr_in *socketaddr)
293 wassertr(cPtr->address==NULL);
295 cPtr->address = wstrdup(inet_ntoa(socketaddr->sin_addr));
296 cPtr->service = wmalloc(16);
297 sprintf(cPtr->service, "%hu", ntohs(socketaddr->sin_port));
298 cPtr->protocol = wstrdup("tcp");
302 static struct sockaddr_in*
303 getSocketAddress(char* name, char* service, char* protocol)
305 static struct sockaddr_in socketaddr;
306 struct servent *sp;
308 if (!protocol || protocol[0]==0)
309 protocol = "tcp";
311 memset(&socketaddr, 0, sizeof(struct sockaddr_in));
312 socketaddr.sin_family = AF_INET;
315 * If we were given a hostname, we use any address for that host.
316 * Otherwise we expect the given name to be an address unless it is
317 * NULL (any address).
319 if (name && name[0]!=0) {
320 WMHost *host = WMGetHostWithName(name);
322 if (!host)
323 return NULL; /* name is not a hostname nor a number and dot adr */
325 name = WMGetHostAddress(host);
326 #ifndef HAVE_INET_ATON
327 if ((socketaddr.sin_addr.s_addr = inet_addr(name)) == INADDR_NONE) {
328 #else
329 if (inet_aton(name, &socketaddr.sin_addr) == 0) {
330 #endif
331 WMReleaseHost(host);
332 return NULL;
334 WMReleaseHost(host);
335 } else {
336 socketaddr.sin_addr.s_addr = htonl(INADDR_ANY);
339 if (!service || service[0]==0) {
340 socketaddr.sin_port = 0;
341 } else if ((sp = getservbyname(service, protocol))==0) {
342 char *endptr;
343 unsigned portNumber;
345 portNumber = strtoul(service, &endptr, 10);
347 if (service[0]!=0 && *endptr==0 && portNumber<65536) {
348 socketaddr.sin_port = htons(portNumber);
349 } else {
350 return NULL;
352 } else {
353 socketaddr.sin_port = sp->s_port;
356 return &socketaddr;
360 static void
361 dummyHandler(int signum)
366 static WMConnection*
367 createConnectionWithSocket(int sock, Bool closeOnRelease)
369 WMConnection *cPtr;
370 struct sigaction sig_action;
372 cPtr = wmalloc(sizeof(WMConnection));
373 wretain(cPtr);
374 memset(cPtr, 0, sizeof(WMConnection));
376 fcntl(sock, F_SETFD, FD_CLOEXEC); /* by default close on exec */
378 cPtr->sock = sock;
379 cPtr->openTimeout.timeout = OpenTimeout;
380 cPtr->openTimeout.handler = NULL;
381 cPtr->sendTimeout.timeout = DefaultTimeout;
382 cPtr->sendTimeout.handler = NULL;
383 cPtr->closeOnRelease = closeOnRelease;
384 cPtr->shutdownOnClose = 1;
385 cPtr->outputQueue =
386 WMCreateArrayWithDestructor(16, (WMFreeDataProc*)WMReleaseData);
387 cPtr->state = WCNotConnected;
388 cPtr->timeoutState = WCTNone;
390 /* ignore dead pipe */
391 if (!SigInitialized) {
392 /* Because POSIX mandates that only signal with handlers are reset
393 * accross an exec*(), we do not want to propagate ignoring SIGPIPEs
394 * to children. Hence the dummy handler. Philippe Troin <phil@fifi.org>
396 sig_action.sa_handler = &dummyHandler;
397 sig_action.sa_flags = SA_RESTART;
398 sigaction(SIGPIPE, &sig_action, NULL);
399 SigInitialized = True;
402 return cPtr;
406 #if 0
407 WMConnection*
408 WMCreateConnectionWithSocket(int sock, Bool closeOnRelease)
410 WMConnection *cPtr;
411 struct sockaddr_in clientname;
412 int size;
413 int n;
415 cPtr = createConnectionWithSocket(sock, closeOnRelease);
416 cPtr->wasNonBlocking = WMIsConnectionNonBlocking(cPtr);
417 cPtr->isNonBlocking = cPtr->wasNonBlocking;
419 /* some way to find out if it is connected, and binded. can't find
420 if it listens though!!!
423 size = sizeof(clientname);
424 n = getpeername(sock, (struct sockaddr*) &clientname, &size);
425 if (n==0) {
426 /* Since we have a peer, it means we are connected */
427 cPtr->state = WCConnected;
428 } else {
429 size = sizeof(clientname);
430 n = getsockname(sock, (struct sockaddr*) &clientname, &size);
431 if (n==0) {
432 /* We don't have a peer, but we are binded to an address.
433 * Assume we are listening on it (we don't know that for sure!)
435 cPtr->state = WCListening;
436 } else {
437 cPtr->state = WCNotConnected;
441 return cPtr;
443 #endif
447 * host is the name on which we want to listen for incoming connections,
448 * and it must be a name of this host, or NULL if we want to listen
449 * on any incoming address.
450 * service is either a service name as present in /etc/services, or the port
451 * number we want to listen on. If NULL, a random port between
452 * 1024 and 65535 will be assigned to us.
453 * protocol is one of "tcp" or "udp". If NULL, "tcp" will be used by default.
454 * currently only "tcp" is supported.
456 WMConnection*
457 WMCreateConnectionAsServerAtAddress(char *host, char *service, char *protocol)
459 WMConnection *cPtr;
460 struct sockaddr_in *socketaddr;
461 int sock, on;
462 int size;
464 WCErrorCode = 0;
466 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
467 wwarning(_("Bad address-service-protocol combination"));
468 return NULL;
471 /* Create the actual socket */
472 sock = socket(PF_INET, SOCK_STREAM, 0);
473 if (sock<0) {
474 WCErrorCode = errno;
475 return NULL;
479 * Set socket options. We try to make the port reusable and have it
480 * close as fast as possible without waiting in unnecessary wait states
481 * on close.
483 on = 1;
484 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
486 if (bind(sock, (struct sockaddr *)socketaddr, sizeof(*socketaddr)) < 0) {
487 WCErrorCode = errno;
488 close(sock);
489 return NULL;
492 if (listen(sock, 10) < 0) {
493 WCErrorCode = errno;
494 close(sock);
495 return NULL;
498 /* Find out what is the address/service/protocol we get */
499 /* In case some of address/service/protocol were NULL */
500 size = sizeof(*socketaddr);
501 if (getsockname(sock, (struct sockaddr*)socketaddr, &size) < 0) {
502 WCErrorCode = errno;
503 close(sock);
504 return NULL;
507 cPtr = createConnectionWithSocket(sock, True);
508 cPtr->state = WCListening;
509 WMSetConnectionNonBlocking(cPtr, True);
511 setConnectionAddress(cPtr, socketaddr);
513 return cPtr;
517 WMConnection*
518 WMCreateConnectionToAddress(char *host, char *service, char *protocol)
520 WMConnection *cPtr;
521 struct sockaddr_in *socketaddr;
522 int sock;
524 WCErrorCode = 0;
526 wassertrv(service!=NULL && service[0]!=0, NULL);
528 if (host==NULL || host[0]==0)
529 host = "localhost";
531 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
532 wwarning(_("Bad address-service-protocol combination"));
533 return NULL;
536 /* Create the actual socket */
537 sock = socket(PF_INET, SOCK_STREAM, 0);
538 if (sock<0) {
539 WCErrorCode = errno;
540 return NULL;
542 /* make socket blocking while we connect. */
543 setSocketNonBlocking(sock, False);
544 if (connect(sock, (struct sockaddr*)socketaddr, sizeof(*socketaddr)) < 0) {
545 WCErrorCode = errno;
546 close(sock);
547 return NULL;
550 cPtr = createConnectionWithSocket(sock, True);
551 cPtr->state = WCConnected;
552 WMSetConnectionNonBlocking(cPtr, True);
553 setConnectionAddress(cPtr, socketaddr);
555 return cPtr;
559 WMConnection*
560 WMCreateConnectionToAddressAndNotify(char *host, char *service, char *protocol)
562 WMConnection *cPtr;
563 struct sockaddr_in *socketaddr;
564 int sock;
565 Bool isNonBlocking;
567 WCErrorCode = 0;
569 wassertrv(service!=NULL && service[0]!=0, NULL);
571 if (host==NULL || host[0]==0)
572 host = "localhost";
574 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
575 wwarning(_("Bad address-service-protocol combination"));
576 return NULL;
579 /* Create the actual socket */
580 sock = socket(PF_INET, SOCK_STREAM, 0);
581 if (sock<0) {
582 WCErrorCode = errno;
583 return NULL;
585 isNonBlocking = setSocketNonBlocking(sock, True);
586 if (connect(sock, (struct sockaddr*)socketaddr, sizeof(*socketaddr)) < 0) {
587 if (errno!=EINPROGRESS) {
588 WCErrorCode = errno;
589 close(sock);
590 return NULL;
594 cPtr = createConnectionWithSocket(sock, True);
595 cPtr->state = WCInProgress;
596 cPtr->isNonBlocking = isNonBlocking;
598 cPtr->handler.write = WMAddInputHandler(cPtr->sock, WIWriteMask,
599 inputHandler, cPtr);
601 cPtr->openTimeout.handler =
602 WMAddTimerHandler(cPtr->openTimeout.timeout*1000, openTimeout, cPtr);
604 setConnectionAddress(cPtr, socketaddr);
606 return cPtr;
610 static void
611 removeAllHandlers(WMConnection *cPtr)
613 if (cPtr->handler.read)
614 WMDeleteInputHandler(cPtr->handler.read);
615 if (cPtr->handler.write)
616 WMDeleteInputHandler(cPtr->handler.write);
617 if (cPtr->handler.exception)
618 WMDeleteInputHandler(cPtr->handler.exception);
619 if (cPtr->openTimeout.handler)
620 WMDeleteTimerHandler(cPtr->openTimeout.handler);
621 if (cPtr->sendTimeout.handler)
622 WMDeleteTimerHandler(cPtr->sendTimeout.handler);
624 cPtr->handler.read = NULL;
625 cPtr->handler.write = NULL;
626 cPtr->handler.exception = NULL;
627 cPtr->openTimeout.handler = NULL;
628 cPtr->sendTimeout.handler = NULL;
632 void
633 WMDestroyConnection(WMConnection *cPtr)
635 if (cPtr->closeOnRelease && cPtr->sock>=0) {
636 if (cPtr->shutdownOnClose) {
637 shutdown(cPtr->sock, SHUT_RDWR);
639 close(cPtr->sock);
642 removeAllHandlers(cPtr);
643 WMFreeArray(cPtr->outputQueue); /* will also free the items with the destructor */
645 if (cPtr->address) {
646 wfree(cPtr->address);
647 wfree(cPtr->service);
648 wfree(cPtr->protocol);
651 wrelease(cPtr);
655 void
656 WMCloseConnection(WMConnection *cPtr)
658 if (cPtr->sock>=0) {
659 if (cPtr->shutdownOnClose) {
660 shutdown(cPtr->sock, SHUT_RDWR);
662 close(cPtr->sock);
663 cPtr->sock = -1;
666 removeAllHandlers(cPtr);
667 clearOutputQueue(cPtr);
669 cPtr->state = WCClosed;
673 WMConnection*
674 WMAcceptConnection(WMConnection *listener)
676 struct sockaddr_in clientname;
677 int size;
678 int newSock;
679 WMConnection *newConnection;
681 WCErrorCode = 0;
682 wassertrv(listener && listener->state==WCListening, NULL);
684 size = sizeof(clientname);
685 newSock = accept(listener->sock, (struct sockaddr*) &clientname, &size);
686 if (newSock<0) {
687 WCErrorCode = ((errno!=EAGAIN && errno!=EWOULDBLOCK) ? errno : 0);
688 return NULL;
691 newConnection = createConnectionWithSocket(newSock, True);
692 WMSetConnectionNonBlocking(newConnection, True);
693 newConnection->state = WCConnected;
694 setConnectionAddress(newConnection, &clientname);
696 return newConnection;
700 char*
701 WMGetConnectionAddress(WMConnection *cPtr)
703 return cPtr->address;
707 char*
708 WMGetConnectionService(WMConnection *cPtr)
710 return cPtr->service;
714 char*
715 WMGetConnectionProtocol(WMConnection *cPtr)
717 return cPtr->protocol;
722 WMGetConnectionSocket(WMConnection *cPtr)
724 return cPtr->sock;
728 WMConnectionState
729 WMGetConnectionState(WMConnection *cPtr)
731 return cPtr->state;
735 WMConnectionTimeoutState
736 WMGetConnectionTimeoutState(WMConnection *cPtr)
738 return cPtr->timeoutState;
742 Bool
743 WMEnqueueConnectionData(WMConnection *cPtr, WMData *data)
745 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, False);
746 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, False);
748 if (cPtr->state!=WCConnected)
749 return False;
751 WMAddToArray(cPtr->outputQueue, WMRetainData(data));
752 return True;
757 * Return value:
758 * -1 - not connected or connection died while sending
759 * 0 - couldn't send the data (or part of it). data is saved in a queue
760 * and will be sent when possible. after it is sent the canResumeSending
761 * callback will be called.
762 * 1 - data was succesfully sent
765 WMSendConnectionData(WMConnection *cPtr, WMData *data)
767 int bytes, pos, len;
768 TimeoutData *tPtr = &cPtr->sendTimeout;
769 const unsigned char *dataBytes;
771 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, -1);
772 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, -1);
774 if (cPtr->state!=WCConnected)
775 return -1;
777 /* If we have no data just flush the queue, else try to send data */
778 if (data && WMGetDataLength(data)>0) {
779 WMAddToArray(cPtr->outputQueue, WMRetainData(data));
780 /* If there already was something in queue, and also a write input
781 * handler is established, it means we were unable to send, so
782 * return and let the write handler notify us when we can send.
784 if (WMGetArrayItemCount(cPtr->outputQueue)>1 && cPtr->handler.write)
785 return 0;
788 while (WMGetArrayItemCount(cPtr->outputQueue) > 0) {
789 data = WMGetFromArray(cPtr->outputQueue, 0);
790 dataBytes = (const unsigned char *)WMDataBytes(data);
791 len = WMGetDataLength(data);
792 pos = cPtr->bufPos; /* where we're left last time */
793 while(pos < len) {
794 again:
795 bytes = write(cPtr->sock, dataBytes+pos, len - pos);
796 if(bytes<0) {
797 switch (errno) {
798 case EINTR:
799 goto again;
800 case EWOULDBLOCK:
801 /* save the position where we're left and add a timeout */
802 cPtr->bufPos = pos;
803 if (!tPtr->handler) {
804 tPtr->handler = WMAddTimerHandler(tPtr->timeout*1000,
805 sendTimeout, cPtr);
807 if (!cPtr->handler.write) {
808 cPtr->handler.write =
809 WMAddInputHandler(cPtr->sock, WIWriteMask,
810 inputHandler, cPtr);
812 return 0;
813 default:
814 WCErrorCode = errno;
815 cPtr->state = WCDied;
816 removeAllHandlers(cPtr);
817 if (cPtr->delegate && cPtr->delegate->didDie)
818 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
819 return -1;
822 pos += bytes;
824 WMDeleteFromArray(cPtr->outputQueue, 0);
825 cPtr->bufPos = 0;
826 if (tPtr->handler) {
827 WMDeleteTimerHandler(tPtr->handler);
828 tPtr->handler = NULL;
830 /*if (cPtr->handler.write) {
831 WMDeleteInputHandler(cPtr->handler.write);
832 cPtr->handler.write = NULL;
836 if (cPtr->handler.write) {
837 WMDeleteInputHandler(cPtr->handler.write);
838 cPtr->handler.write = NULL;
841 return 1;
846 * WMGetConnectionAvailableData(connection):
848 * will return a WMData structure containing the available data on the
849 * specified connection. If connection is non-blocking (default) and no data
850 * is available when this function is called, an empty WMData is returned.
852 * If an error occurs while reading or the other side closed connection,
853 * it will return NULL.
854 * Also trying to read from an already died or closed connection is
855 * considered to be an error condition, and will return NULL.
857 WMData*
858 WMGetConnectionAvailableData(WMConnection *cPtr)
860 char buffer[NETBUF_SIZE];
861 int nbytes;
862 WMData *aData;
864 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, NULL);
865 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, NULL);
867 if (cPtr->state!=WCConnected)
868 return NULL;
870 aData = NULL;
872 again:
873 nbytes = read(cPtr->sock, buffer, NETBUF_SIZE);
874 if (nbytes<0) {
875 switch (errno) {
876 case EINTR:
877 goto again;
878 case EWOULDBLOCK:
879 aData = WMCreateDataWithCapacity(0);
880 break;
881 default:
882 WCErrorCode = errno;
883 cPtr->state = WCDied;
884 removeAllHandlers(cPtr);
885 if (cPtr->delegate && cPtr->delegate->didDie)
886 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
887 break;
889 } else if (nbytes==0) { /* the other side has closed connection */
890 cPtr->state = WCClosed;
891 removeAllHandlers(cPtr);
892 if (cPtr->delegate && cPtr->delegate->didDie)
893 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
894 } else {
895 aData = WMCreateDataWithBytes(buffer, nbytes);
898 return aData;
902 void
903 WMSetConnectionDelegate(WMConnection *cPtr, ConnectionDelegate *delegate)
905 wassertr(cPtr->sock >= 0);
906 /* Don't try to set the delegate multiple times */
907 wassertr(cPtr->delegate == NULL);
909 cPtr->delegate = delegate;
910 if (delegate && delegate->didReceiveInput && !cPtr->handler.read)
911 cPtr->handler.read = WMAddInputHandler(cPtr->sock, WIReadMask,
912 inputHandler, cPtr);
913 if (delegate && delegate->didCatchException && !cPtr->handler.exception)
914 cPtr->handler.exception = WMAddInputHandler(cPtr->sock, WIExceptMask,
915 inputHandler, cPtr);
919 #if 0
920 Bool
921 WMIsConnectionNonBlocking(WMConnection *cPtr)
923 #if 1
924 int state;
926 state = fcntl(cPtr->sock, F_GETFL, 0);
928 if (state < 0) {
929 /* If we can't use fcntl on socket, this probably also means we could
930 * not use fcntl to set non-blocking mode, and since a socket defaults
931 * to blocking when created, return False as the best assumption */
932 return False;
935 return ((state & NONBLOCK_OPT)!=0);
936 #else
937 return cPtr->isNonBlocking;
938 #endif
940 #endif
943 Bool
944 WMSetConnectionNonBlocking(WMConnection *cPtr, Bool flag)
946 wassertrv(cPtr!=NULL && cPtr->sock>=0, False);
948 flag = ((flag==0) ? 0 : 1);
950 if (cPtr->isNonBlocking == flag)
951 return True;
953 if (setSocketNonBlocking(cPtr->sock, flag)==True) {
954 cPtr->isNonBlocking = flag;
955 return True;
958 return False;
962 Bool
963 WMSetConnectionCloseOnExec(WMConnection *cPtr, Bool flag)
965 wassertrv(cPtr!=NULL && cPtr->sock>=0, False);
967 if (fcntl(cPtr->sock, F_SETFD, ((flag==0) ? 0 : FD_CLOEXEC)) < 0) {
968 return False;
971 return True;
975 void
976 WMSetConnectionShutdownOnClose(WMConnection *cPtr, Bool flag)
978 cPtr->shutdownOnClose = ((flag==0) ? 0 : 1);
982 void*
983 WMGetConnectionClientData(WMConnection *cPtr)
985 return cPtr->clientData;
989 void
990 WMSetConnectionClientData(WMConnection *cPtr, void *data)
992 cPtr->clientData = data;
996 unsigned int
997 WMGetConnectionFlags(WMConnection *cPtr)
999 return cPtr->uflags;
1003 void
1004 WMSetConnectionFlags(WMConnection *cPtr, unsigned int flags)
1006 cPtr->uflags = flags;
1010 WMArray*
1011 WMGetConnectionUnsentData(WMConnection *cPtr)
1013 return cPtr->outputQueue;
1017 void
1018 WMSetConnectionDefaultTimeout(unsigned int timeout)
1020 if (timeout == 0) {
1021 DefaultTimeout = DEF_TIMEOUT;
1022 } else {
1023 DefaultTimeout = timeout;
1028 void
1029 WMSetConnectionOpenTimeout(unsigned int timeout)
1031 if (timeout == 0) {
1032 OpenTimeout = DefaultTimeout;
1033 } else {
1034 OpenTimeout = timeout;
1039 void
1040 WMSetConnectionSendTimeout(WMConnection *cPtr, unsigned int timeout)
1042 if (timeout == 0) {
1043 cPtr->sendTimeout.timeout = DefaultTimeout;
1044 } else {
1045 cPtr->sendTimeout.timeout = timeout;