Put back int instead of socklen_t, because in libc5 socklen_t is not
[wmaker-crm.git] / WINGs / connection.c
blobecb98e730bee23454c0cc283f397a932f5bc324f
1 /*
2 * WINGs WMConnection function library
3 *
4 * Copyright (c) 1999-2000 Dan Pascu
5 *
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 "../src/config.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 wasNonBlocking;
125 Bool isNonBlocking;
127 } W_Connection;
131 static void
132 clearOutputQueue(WMConnection *cPtr) /*FOLD00*/
134 cPtr->bufPos = 0;
135 WMEmptyArray(cPtr->outputQueue);
139 static void
140 openTimeout(void *cdata) /*FOLD00*/
142 WMConnection *cPtr = (WMConnection*) cdata;
144 cPtr->openTimeout.handler = NULL;
145 if (cPtr->handler.write) {
146 WMDeleteInputHandler(cPtr->handler.write);
147 cPtr->handler.write = NULL;
149 if (cPtr->state != WCConnected) {
150 cPtr->state = WCTimedOut;
151 cPtr->timeoutState = WCTWhileOpening;
152 if (cPtr->delegate && cPtr->delegate->didTimeout) {
153 (*cPtr->delegate->didTimeout)(cPtr->delegate, cPtr);
154 } else {
155 WMCloseConnection(cPtr);
156 cPtr->state = WCTimedOut; /* the above set state to WCClosed */
162 static void
163 sendTimeout(void *cdata) /*FOLD00*/
165 WMConnection *cPtr = (WMConnection*) cdata;
167 cPtr->sendTimeout.handler = NULL;
168 if (cPtr->handler.write) {
169 WMDeleteInputHandler(cPtr->handler.write);
170 cPtr->handler.write = NULL;
172 if (WMGetArrayItemCount(cPtr->outputQueue)>0) {
173 clearOutputQueue(cPtr);
174 cPtr->state = WCTimedOut;
175 cPtr->timeoutState = WCTWhileSending;
176 if (cPtr->delegate && cPtr->delegate->didTimeout) {
177 (*cPtr->delegate->didTimeout)(cPtr->delegate, cPtr);
178 } else {
179 WMCloseConnection(cPtr);
180 cPtr->state = WCTimedOut; /* the above set state to WCClosed */
186 static void
187 inputHandler(int fd, int mask, void *clientData) /*FOLD00*/
189 WMConnection *cPtr = (WMConnection*)clientData;
191 if (cPtr->state==WCClosed || cPtr->state==WCDied)
192 return;
194 if ((mask & WIWriteMask)) {
195 if (cPtr->state == WCInProgress) {
196 Bool failed;
197 int result;
198 int len = sizeof(result);
200 WCErrorCode = 0;
201 if (getsockopt(cPtr->sock, SOL_SOCKET, SO_ERROR,
202 (void*)&result, &len) == 0 && result != 0) {
203 cPtr->state = WCFailed;
204 WCErrorCode = result;
205 failed = True;
206 /* should call wsyserrorwithcode(result, ...) here? */
207 } else {
208 cPtr->state = WCConnected;
209 failed = False;
212 if (cPtr->handler.write) {
213 WMDeleteInputHandler(cPtr->handler.write);
214 cPtr->handler.write = NULL;
217 if (cPtr->openTimeout.handler) {
218 WMDeleteTimerHandler(cPtr->openTimeout.handler);
219 cPtr->openTimeout.handler = NULL;
222 if (cPtr->delegate && cPtr->delegate->didInitialize)
223 (*cPtr->delegate->didInitialize)(cPtr->delegate, cPtr);
225 /* we use failed and not cPtr->state here, because cPtr may be
226 * destroyed by the delegate called above if the connection failed
228 if (failed)
229 return;
230 } else if (cPtr->state == WCConnected) {
231 WMFlushConnection(cPtr);
235 if (!cPtr->delegate)
236 return;
238 /* if the connection died, may get destroyed in the delegate, so retain */
239 wretain(cPtr);
241 if ((mask & WIReadMask) && cPtr->delegate->didReceiveInput)
242 (*cPtr->delegate->didReceiveInput)(cPtr->delegate, cPtr);
244 if ((mask & WIExceptMask) && cPtr->delegate->didCatchException)
245 (*cPtr->delegate->didCatchException)(cPtr->delegate, cPtr);
247 wrelease(cPtr);
251 static Bool
252 setSocketNonBlocking(int sock, Bool flag) /*FOLD00*/
254 int state;
255 Bool isNonBlock;
257 state = fcntl(sock, F_GETFL, 0);
259 if (state < 0) {
260 /* set WCErrorCode here? -Dan*/
261 return False;
264 isNonBlock = (state & NONBLOCK_OPT) != 0;
266 if (flag) {
267 if (isNonBlock)
268 return True;
269 state |= NONBLOCK_OPT;
270 } else {
271 if (!isNonBlock)
272 return True;
273 state &= ~NONBLOCK_OPT;
276 if (fcntl(sock, F_SETFL, state) < 0) {
277 /* set WCErrorCode here? -Dan*/
278 return False;
281 return True;
285 static void
286 setConnectionAddress(WMConnection *cPtr, struct sockaddr_in *socketaddr) /*FOLD00*/
288 wassertr(cPtr->address==NULL);
290 cPtr->address = wstrdup(inet_ntoa(socketaddr->sin_addr));
291 cPtr->service = wmalloc(16);
292 sprintf(cPtr->service, "%hu", ntohs(socketaddr->sin_port));
293 cPtr->protocol = wstrdup("tcp");
297 static struct sockaddr_in*
298 getSocketAddress(char* name, char* service, char* protocol) /*FOLD00*/
300 static struct sockaddr_in socketaddr;
301 struct servent *sp;
303 if (!protocol || protocol[0]==0)
304 protocol = "tcp";
306 memset(&socketaddr, 0, sizeof(struct sockaddr_in));
307 socketaddr.sin_family = AF_INET;
310 * If we were given a hostname, we use any address for that host.
311 * Otherwise we expect the given name to be an address unless it is
312 * NULL (any address).
314 if (name && name[0]!=0) {
315 WMHost *host = WMGetHostWithName(name);
317 if (!host)
318 return NULL; /* name is not a hostname nor a number and dot adr */
320 name = WMGetHostAddress(host);
321 #ifndef HAVE_INET_ATON
322 if ((socketaddr.sin_addr.s_addr = inet_addr(name)) == INADDR_NONE) {
323 #else
324 if (inet_aton(name, &socketaddr.sin_addr) == 0) {
325 #endif
326 WMReleaseHost(host);
327 return NULL;
329 WMReleaseHost(host);
330 } else {
331 socketaddr.sin_addr.s_addr = htonl(INADDR_ANY);
334 if (!service || service[0]==0) {
335 socketaddr.sin_port = 0;
336 } else if ((sp = getservbyname(service, protocol))==0) {
337 char *endptr;
338 unsigned portNumber;
340 portNumber = strtoul(service, &endptr, 10);
342 if (service[0]!=0 && *endptr==0 && portNumber<65536) {
343 socketaddr.sin_port = htons(portNumber);
344 } else {
345 return NULL;
347 } else {
348 socketaddr.sin_port = sp->s_port;
351 return &socketaddr;
355 static WMConnection*
356 createConnectionWithSocket(int sock, Bool closeOnRelease) /*FOLD00*/
358 WMConnection *cPtr;
359 struct sigaction sig_action;
361 cPtr = wmalloc(sizeof(WMConnection));
362 wretain(cPtr);
363 memset(cPtr, 0, sizeof(WMConnection));
365 fcntl(sock, F_SETFD, FD_CLOEXEC); /* by default close on exec */
367 cPtr->sock = sock;
368 cPtr->openTimeout.timeout = OpenTimeout;
369 cPtr->openTimeout.handler = NULL;
370 cPtr->sendTimeout.timeout = DefaultTimeout;
371 cPtr->sendTimeout.handler = NULL;
372 cPtr->closeOnRelease = closeOnRelease;
373 cPtr->outputQueue =
374 WMCreateArrayWithDestructor(16, (WMFreeDataProc*)WMReleaseData);
375 cPtr->state = WCNotConnected;
376 cPtr->timeoutState = WCTNone;
378 /* ignore dead pipe */
379 if (!SigInitialized) {
380 sig_action.sa_handler = SIG_IGN;
381 sig_action.sa_flags = SA_RESTART;
382 sigaction(SIGPIPE, &sig_action, NULL);
383 SigInitialized = True;
386 return cPtr;
390 #if 0
391 WMConnection*
392 WMCreateConnectionWithSocket(int sock, Bool closeOnRelease) /*FOLD00*/
394 WMConnection *cPtr;
395 struct sockaddr_in clientname;
396 int size;
397 int n;
399 cPtr = createConnectionWithSocket(sock, closeOnRelease);
400 cPtr->wasNonBlocking = WMIsConnectionNonBlocking(cPtr);
401 cPtr->isNonBlocking = cPtr->wasNonBlocking;
403 /* some way to find out if it is connected, and binded. can't find
404 if it listens though!!!
407 size = sizeof(clientname);
408 n = getpeername(sock, (struct sockaddr*) &clientname, &size);
409 if (n==0) {
410 /* Since we have a peer, it means we are connected */
411 cPtr->state = WCConnected;
412 } else {
413 size = sizeof(clientname);
414 n = getsockname(sock, (struct sockaddr*) &clientname, &size);
415 if (n==0) {
416 /* We don't have a peer, but we are binded to an address.
417 * Assume we are listening on it (we don't know that for sure!)
419 cPtr->state = WCListening;
420 } else {
421 cPtr->state = WCNotConnected;
425 return cPtr;
427 #endif
431 * host is the name on which we want to listen for incoming connections,
432 * and it must be a name of this host, or NULL if we want to listen
433 * on any incoming address.
434 * service is either a service name as present in /etc/services, or the port
435 * number we want to listen on. If NULL, a random port between
436 * 1024 and 65535 will be assigned to us.
437 * protocol is one of "tcp" or "udp". If NULL, "tcp" will be used by default.
438 * currently only "tcp" is supported.
440 WMConnection*
441 WMCreateConnectionAsServerAtAddress(char *host, char *service, char *protocol) /*FOLD00*/
443 WMConnection *cPtr;
444 struct sockaddr_in *socketaddr;
445 int sock, on;
446 int size;
448 WCErrorCode = 0;
450 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
451 wwarning("Bad address-service-protocol combination");
452 return NULL;
455 /* Create the actual socket */
456 sock = socket(PF_INET, SOCK_STREAM, 0);
457 if (sock<0) {
458 WCErrorCode = errno;
459 return NULL;
463 * Set socket options. We try to make the port reusable and have it
464 * close as fast as possible without waiting in unnecessary wait states
465 * on close.
467 on = 1;
468 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
470 if (bind(sock, (struct sockaddr *)socketaddr, sizeof(*socketaddr)) < 0) {
471 WCErrorCode = errno;
472 close(sock);
473 return NULL;
476 if (listen(sock, 10) < 0) {
477 WCErrorCode = errno;
478 close(sock);
479 return NULL;
482 /* Find out what is the address/service/protocol we get */
483 /* In case some of address/service/protocol were NULL */
484 size = sizeof(*socketaddr);
485 if (getsockname(sock, (struct sockaddr*)socketaddr, &size) < 0) {
486 WCErrorCode = errno;
487 close(sock);
488 return NULL;
491 cPtr = createConnectionWithSocket(sock, True);
492 cPtr->state = WCListening;
493 WMSetConnectionNonBlocking(cPtr, True);
495 setConnectionAddress(cPtr, socketaddr);
497 return cPtr;
501 WMConnection*
502 WMCreateConnectionToAddress(char *host, char *service, char *protocol) /*FOLD00*/
504 WMConnection *cPtr;
505 struct sockaddr_in *socketaddr;
506 int sock;
508 WCErrorCode = 0;
510 wassertrv(service!=NULL && service[0]!=0, NULL);
512 if (host==NULL || host[0]==0)
513 host = "localhost";
515 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
516 wwarning("Bad address-service-protocol combination");
517 return NULL;
520 /* Create the actual socket */
521 sock = socket(PF_INET, SOCK_STREAM, 0);
522 if (sock<0) {
523 WCErrorCode = errno;
524 return NULL;
526 /* make socket blocking while we connect. */
527 setSocketNonBlocking(sock, False);
528 if (connect(sock, (struct sockaddr*)socketaddr, sizeof(*socketaddr)) < 0) {
529 WCErrorCode = errno;
530 close(sock);
531 return NULL;
534 cPtr = createConnectionWithSocket(sock, True);
535 cPtr->state = WCConnected;
536 WMSetConnectionNonBlocking(cPtr, True);
537 setConnectionAddress(cPtr, socketaddr);
539 return cPtr;
543 WMConnection*
544 WMCreateConnectionToAddressAndNotify(char *host, char *service, char *protocol) /*FOLD00*/
546 WMConnection *cPtr;
547 struct sockaddr_in *socketaddr;
548 int sock;
549 Bool isNonBlocking;
551 WCErrorCode = 0;
553 wassertrv(service!=NULL && service[0]!=0, NULL);
555 if (host==NULL || host[0]==0)
556 host = "localhost";
558 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
559 wwarning("Bad address-service-protocol combination");
560 return NULL;
563 /* Create the actual socket */
564 sock = socket(PF_INET, SOCK_STREAM, 0);
565 if (sock<0) {
566 WCErrorCode = errno;
567 return NULL;
569 isNonBlocking = setSocketNonBlocking(sock, True);
570 if (connect(sock, (struct sockaddr*)socketaddr, sizeof(*socketaddr)) < 0) {
571 if (errno!=EINPROGRESS) {
572 WCErrorCode = errno;
573 close(sock);
574 return NULL;
578 cPtr = createConnectionWithSocket(sock, True);
579 cPtr->state = WCInProgress;
580 cPtr->isNonBlocking = isNonBlocking;
582 cPtr->handler.write = WMAddInputHandler(cPtr->sock, WIWriteMask,
583 inputHandler, cPtr);
585 cPtr->openTimeout.handler =
586 WMAddTimerHandler(cPtr->openTimeout.timeout*1000, openTimeout, cPtr);
588 setConnectionAddress(cPtr, socketaddr);
590 return cPtr;
594 static void
595 removeAllHandlers(WMConnection *cPtr) /*FOLD00*/
597 if (cPtr->handler.read)
598 WMDeleteInputHandler(cPtr->handler.read);
599 if (cPtr->handler.write)
600 WMDeleteInputHandler(cPtr->handler.write);
601 if (cPtr->handler.exception)
602 WMDeleteInputHandler(cPtr->handler.exception);
603 if (cPtr->openTimeout.handler)
604 WMDeleteTimerHandler(cPtr->openTimeout.handler);
605 if (cPtr->sendTimeout.handler)
606 WMDeleteTimerHandler(cPtr->sendTimeout.handler);
608 cPtr->handler.read = NULL;
609 cPtr->handler.write = NULL;
610 cPtr->handler.exception = NULL;
611 cPtr->openTimeout.handler = NULL;
612 cPtr->sendTimeout.handler = NULL;
616 void
617 WMDestroyConnection(WMConnection *cPtr) /*FOLD00*/
619 if (cPtr->closeOnRelease && cPtr->sock>=0) {
620 shutdown(cPtr->sock, SHUT_RDWR);
621 close(cPtr->sock);
624 removeAllHandlers(cPtr);
625 WMFreeArray(cPtr->outputQueue); /* will also free the items with the destructor */
627 if (cPtr->address) {
628 wfree(cPtr->address);
629 wfree(cPtr->service);
630 wfree(cPtr->protocol);
633 wrelease(cPtr);
637 void
638 WMCloseConnection(WMConnection *cPtr) /*FOLD00*/
640 if (cPtr->sock>=0) {
641 shutdown(cPtr->sock, SHUT_RDWR);
642 close(cPtr->sock);
643 cPtr->sock = -1;
646 removeAllHandlers(cPtr);
647 clearOutputQueue(cPtr);
649 cPtr->state = WCClosed;
653 WMConnection*
654 WMAcceptConnection(WMConnection *listener) /*FOLD00*/
656 struct sockaddr_in clientname;
657 int size;
658 int newSock;
659 WMConnection *newConnection;
661 WCErrorCode = 0;
662 wassertrv(listener && listener->state==WCListening, NULL);
664 size = sizeof(clientname);
665 newSock = accept(listener->sock, (struct sockaddr*) &clientname, &size);
666 if (newSock<0) {
667 WCErrorCode = ((errno!=EAGAIN && errno!=EWOULDBLOCK) ? errno : 0);
668 return NULL;
671 newConnection = createConnectionWithSocket(newSock, True);
672 WMSetConnectionNonBlocking(newConnection, True);
673 newConnection->state = WCConnected;
674 setConnectionAddress(newConnection, &clientname);
676 return newConnection;
680 char*
681 WMGetConnectionAddress(WMConnection *cPtr) /*FOLD00*/
683 return cPtr->address;
687 char*
688 WMGetConnectionService(WMConnection *cPtr) /*FOLD00*/
690 return cPtr->service;
694 char*
695 WMGetConnectionProtocol(WMConnection *cPtr) /*FOLD00*/
697 return cPtr->protocol;
702 WMGetConnectionSocket(WMConnection *cPtr) /*FOLD00*/
704 return cPtr->sock;
708 WMConnectionState
709 WMGetConnectionState(WMConnection *cPtr) /*FOLD00*/
711 return cPtr->state;
715 WMConnectionTimeoutState
716 WMGetConnectionTimeoutState(WMConnection *cPtr) /*FOLD00*/
718 return cPtr->timeoutState;
722 Bool
723 WMEnqueueConnectionData(WMConnection *cPtr, WMData *data) /*FOLD00*/
725 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, False);
726 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, False);
728 if (cPtr->state!=WCConnected)
729 return False;
731 WMAddToArray(cPtr->outputQueue, WMRetainData(data));
732 return True;
737 WMSendConnectionData(WMConnection *cPtr, WMData *data) /*FOLD00*/
739 int bytes, pos, len, totalTransfer;
740 TimeoutData *tPtr = &cPtr->sendTimeout;
741 const unsigned char *dataBytes;
743 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, -1);
744 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, -1);
746 if (cPtr->state!=WCConnected)
747 return -1;
749 /* If we have no data just flush the queue, else try to send data */
750 if (data && WMGetDataLength(data)>0) {
751 WMAddToArray(cPtr->outputQueue, WMRetainData(data));
752 /* If there already was something in queue, and also a write input
753 * handler is established, it means we were unable to send, so
754 * return and let the write handler notify us when we can send.
756 if (WMGetArrayItemCount(cPtr->outputQueue)>1 && cPtr->handler.write)
757 return 0;
760 totalTransfer = 0;
762 while (WMGetArrayItemCount(cPtr->outputQueue) > 0) {
763 data = WMGetFromArray(cPtr->outputQueue, 0);
764 dataBytes = (const unsigned char *)WMDataBytes(data);
765 len = WMGetDataLength(data);
766 pos = cPtr->bufPos; /* where we're left last time */
767 while(pos < len) {
768 again:
769 bytes = write(cPtr->sock, dataBytes+pos, len - pos);
770 if(bytes<0) {
771 switch (errno) {
772 case EINTR:
773 goto again;
774 case EWOULDBLOCK:
775 /* save the position where we're left and add a timeout */
776 cPtr->bufPos = pos;
777 if (!tPtr->handler) {
778 tPtr->handler = WMAddTimerHandler(tPtr->timeout*1000,
779 sendTimeout, cPtr);
781 if (!cPtr->handler.write) {
782 cPtr->handler.write =
783 WMAddInputHandler(cPtr->sock, WIWriteMask,
784 inputHandler, cPtr);
786 return totalTransfer;
787 default:
788 WCErrorCode = errno;
789 cPtr->state = WCDied;
790 removeAllHandlers(cPtr);
791 if (cPtr->delegate && cPtr->delegate->didDie)
792 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
793 return -1;
796 pos += bytes;
797 totalTransfer += bytes;
799 WMDeleteFromArray(cPtr->outputQueue, 0);
800 cPtr->bufPos = 0;
801 if (tPtr->handler) {
802 WMDeleteTimerHandler(tPtr->handler);
803 tPtr->handler = NULL;
805 if (cPtr->handler.write) {
806 WMDeleteInputHandler(cPtr->handler.write);
807 cPtr->handler.write = NULL;
811 return totalTransfer;
816 * WMGetConnectionAvailableData(connection):
818 * will return a WMData structure containing the available data on the
819 * specified connection. If connection is non-blocking (default) and no data
820 * is available when this function is called, an empty WMData is returned.
822 * If an error occurs while reading or the other side closed connection,
823 * it will return NULL.
824 * Also trying to read from an already died or closed connection is
825 * considered to be an error condition, and will return NULL.
827 WMData*
828 WMGetConnectionAvailableData(WMConnection *cPtr) /*FOLD00*/
830 char buffer[NETBUF_SIZE];
831 int nbytes;
832 WMData *aData;
834 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, NULL);
835 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, NULL);
837 if (cPtr->state!=WCConnected)
838 return NULL;
840 aData = NULL;
842 again:
843 nbytes = read(cPtr->sock, buffer, NETBUF_SIZE);
844 if (nbytes<0) {
845 switch (errno) {
846 case EINTR:
847 goto again;
848 case EWOULDBLOCK:
849 aData = WMCreateDataWithCapacity(0);
850 break;
851 default:
852 WCErrorCode = errno;
853 cPtr->state = WCDied;
854 removeAllHandlers(cPtr);
855 if (cPtr->delegate && cPtr->delegate->didDie)
856 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
857 break;
859 } else if (nbytes==0) { /* the other side has closed connection */
860 cPtr->state = WCClosed;
861 removeAllHandlers(cPtr);
862 if (cPtr->delegate && cPtr->delegate->didDie)
863 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
864 } else {
865 aData = WMCreateDataWithBytes(buffer, nbytes);
868 return aData;
872 void
873 WMSetConnectionDelegate(WMConnection *cPtr, ConnectionDelegate *delegate) /*FOLD00*/
875 wassertr(cPtr->sock >= 0);
876 /* Don't try to set the delegate multiple times */
877 wassertr(cPtr->delegate == NULL);
879 cPtr->delegate = delegate;
880 if (delegate && delegate->didReceiveInput && !cPtr->handler.read)
881 cPtr->handler.read = WMAddInputHandler(cPtr->sock, WIReadMask,
882 inputHandler, cPtr);
883 if (delegate && delegate->didCatchException && !cPtr->handler.exception)
884 cPtr->handler.exception = WMAddInputHandler(cPtr->sock, WIExceptMask,
885 inputHandler, cPtr);
889 #if 0
890 Bool
891 WMIsConnectionNonBlocking(WMConnection *cPtr) /*FOLD00*/
893 #if 1
894 int state;
896 state = fcntl(cPtr->sock, F_GETFL, 0);
898 if (state < 0) {
899 /* If we can't use fcntl on socket, this probably also means we could
900 * not use fcntl to set non-blocking mode, and since a socket defaults
901 * to blocking when created, return False as the best assumption */
902 return False;
905 return ((state & NONBLOCK_OPT)!=0);
906 #else
907 return cPtr->isNonBlocking;
908 #endif
910 #endif
913 Bool
914 WMSetConnectionNonBlocking(WMConnection *cPtr, Bool flag) /*FOLD00*/
916 wassertrv(cPtr!=NULL && cPtr->sock>=0, False);
918 if (cPtr->isNonBlocking == flag)
919 return True;
921 if (setSocketNonBlocking(cPtr->sock, flag)==True) {
922 cPtr->isNonBlocking = flag;
923 return True;
926 return False;
930 Bool
931 WMSetConnectionCloseOnExec(WMConnection *cPtr, Bool flag)
933 wassertrv(cPtr!=NULL && cPtr->sock>=0, False);
935 if (fcntl(cPtr->sock, F_SETFD, (flag ? FD_CLOEXEC : 0)) < 0) {
936 return False;
939 return True;
943 void*
944 WMGetConnectionClientData(WMConnection *cPtr) /*FOLD00*/
946 return cPtr->clientData;
950 void
951 WMSetConnectionClientData(WMConnection *cPtr, void *data) /*FOLD00*/
953 cPtr->clientData = data;
957 unsigned int
958 WMGetConnectionFlags(WMConnection *cPtr) /*FOLD00*/
960 return cPtr->uflags;
964 void
965 WMSetConnectionFlags(WMConnection *cPtr, unsigned int flags) /*FOLD00*/
967 cPtr->uflags = flags;
971 WMArray*
972 WMGetConnectionUnsentData(WMConnection *cPtr)
974 return cPtr->outputQueue;
978 void
979 WMSetConnectionDefaultTimeout(unsigned int timeout) /*FOLD00*/
981 if (timeout == 0) {
982 DefaultTimeout = DEF_TIMEOUT;
983 } else {
984 DefaultTimeout = timeout;
989 void
990 WMSetConnectionOpenTimeout(unsigned int timeout) /*FOLD00*/
992 if (timeout == 0) {
993 OpenTimeout = DefaultTimeout;
994 } else {
995 OpenTimeout = timeout;
1000 void
1001 WMSetConnectionSendTimeout(WMConnection *cPtr, unsigned int timeout) /*FOLD00*/
1003 if (timeout == 0) {
1004 cPtr->sendTimeout.timeout = DefaultTimeout;
1005 } else {
1006 cPtr->sendTimeout.timeout = timeout;