- s/sprintf/snprintf
[wmaker-crm.git] / WINGs / connection.c
blob8f2330e75dc6df237ef2d9a883839ef662cbce91
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"
32 #include "wconfig.h"
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <stdarg.h>
40 #include <errno.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 #include <netdb.h>
45 #include <signal.h>
46 #ifdef __FreeBSD__
47 #include <sys/signal.h>
48 #endif
50 #include "WINGs.h"
53 /* Some older systems does not define this (linux libc5, maybe others too) */
54 #ifndef SHUT_RDWR
55 # define SHUT_RDWR 2
56 #endif
58 /* For SunOS */
59 #ifndef SA_RESTART
60 # define SA_RESTART 0
61 #endif
63 /* For Solaris */
64 #ifndef INADDR_NONE
65 # define INADDR_NONE -1
66 #endif
68 /* Stuff for setting the sockets into non-blocking mode. */
69 /*#ifdef __POSIX_SOURCE
70 # define NONBLOCK_OPT O_NONBLOCK
71 #else
72 # define NONBLOCK_OPT FNDELAY
73 #endif*/
75 #define NONBLOCK_OPT O_NONBLOCK
77 #define NETBUF_SIZE 4096
79 #define DEF_TIMEOUT 600 /* 600 seconds == 10 minutes */
83 int WCErrorCode = 0;
85 static Bool SigInitialized = False;
87 static unsigned int DefaultTimeout = DEF_TIMEOUT;
88 static unsigned int OpenTimeout = DEF_TIMEOUT;
92 typedef struct TimeoutData {
93 unsigned timeout;
94 WMHandlerID *handler;
95 } TimeoutData;
98 typedef struct W_Connection {
99 int sock; /* the socket we speak through */
101 struct {
102 WMHandlerID *read; /* the input read handler */
103 WMHandlerID *write; /* the input write handler */
104 WMHandlerID *exception; /* the input exception handler */
105 } handler;
107 ConnectionDelegate *delegate; /* client delegates */
108 void *clientData; /* client data */
109 unsigned int uflags; /* flags for the client */
111 WMArray *outputQueue;
112 unsigned bufPos;
114 TimeoutData sendTimeout;
115 TimeoutData openTimeout;
117 WMConnectionState state;
118 WMConnectionTimeoutState timeoutState;
120 char *address;
121 char *service;
122 char *protocol;
124 Bool closeOnRelease;
125 Bool wasNonBlocking;
126 Bool isNonBlocking;
128 } W_Connection;
132 static void
133 clearOutputQueue(WMConnection *cPtr) /*FOLD00*/
135 cPtr->bufPos = 0;
136 WMEmptyArray(cPtr->outputQueue);
140 static void
141 openTimeout(void *cdata) /*FOLD00*/
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) /*FOLD00*/
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) /*FOLD00*/
190 WMConnection *cPtr = (WMConnection*)clientData;
192 if (cPtr->state==WCClosed || cPtr->state==WCDied)
193 return;
195 if ((mask & WIWriteMask)) {
196 if (cPtr->state == WCInProgress) {
197 Bool failed;
198 int result;
199 int len = sizeof(result);
201 WCErrorCode = 0;
202 if (getsockopt(cPtr->sock, SOL_SOCKET, SO_ERROR,
203 (void*)&result, &len) == 0 && result != 0) {
204 cPtr->state = WCFailed;
205 WCErrorCode = result;
206 failed = True;
207 /* should call wsyserrorwithcode(result, ...) here? */
208 } else {
209 cPtr->state = WCConnected;
210 failed = False;
213 if (cPtr->handler.write) {
214 WMDeleteInputHandler(cPtr->handler.write);
215 cPtr->handler.write = NULL;
218 if (cPtr->openTimeout.handler) {
219 WMDeleteTimerHandler(cPtr->openTimeout.handler);
220 cPtr->openTimeout.handler = NULL;
223 if (cPtr->delegate && cPtr->delegate->didInitialize)
224 (*cPtr->delegate->didInitialize)(cPtr->delegate, cPtr);
226 /* we use failed and not cPtr->state here, because cPtr may be
227 * destroyed by the delegate called above if the connection failed
229 if (failed)
230 return;
231 } else if (cPtr->state == WCConnected) {
232 WMFlushConnection(cPtr);
236 if (!cPtr->delegate)
237 return;
239 /* if the connection died, may get destroyed in the delegate, so retain */
240 wretain(cPtr);
242 if ((mask & WIReadMask) && cPtr->delegate->didReceiveInput)
243 (*cPtr->delegate->didReceiveInput)(cPtr->delegate, cPtr);
245 if ((mask & WIExceptMask) && cPtr->delegate->didCatchException)
246 (*cPtr->delegate->didCatchException)(cPtr->delegate, cPtr);
248 wrelease(cPtr);
252 static Bool
253 setSocketNonBlocking(int sock, Bool flag) /*FOLD00*/
255 int state;
256 Bool isNonBlock;
258 state = fcntl(sock, F_GETFL, 0);
260 if (state < 0) {
261 /* set WCErrorCode here? -Dan*/
262 return False;
265 isNonBlock = (state & NONBLOCK_OPT) != 0;
267 if (flag) {
268 if (isNonBlock)
269 return True;
270 state |= NONBLOCK_OPT;
271 } else {
272 if (!isNonBlock)
273 return True;
274 state &= ~NONBLOCK_OPT;
277 if (fcntl(sock, F_SETFL, state) < 0) {
278 /* set WCErrorCode here? -Dan*/
279 return False;
282 return True;
286 static void
287 setConnectionAddress(WMConnection *cPtr, struct sockaddr_in *socketaddr) /*FOLD00*/
289 wassertr(cPtr->address==NULL);
291 cPtr->address = wstrdup(inet_ntoa(socketaddr->sin_addr));
292 cPtr->service = wmalloc(16);
293 sprintf(cPtr->service, "%hu", ntohs(socketaddr->sin_port));
294 cPtr->protocol = wstrdup("tcp");
298 static struct sockaddr_in*
299 getSocketAddress(char* name, char* service, char* protocol) /*FOLD00*/
301 static struct sockaddr_in socketaddr;
302 struct servent *sp;
304 if (!protocol || protocol[0]==0)
305 protocol = "tcp";
307 memset(&socketaddr, 0, sizeof(struct sockaddr_in));
308 socketaddr.sin_family = AF_INET;
311 * If we were given a hostname, we use any address for that host.
312 * Otherwise we expect the given name to be an address unless it is
313 * NULL (any address).
315 if (name && name[0]!=0) {
316 WMHost *host = WMGetHostWithName(name);
318 if (!host)
319 return NULL; /* name is not a hostname nor a number and dot adr */
321 name = WMGetHostAddress(host);
322 #ifndef HAVE_INET_ATON
323 if ((socketaddr.sin_addr.s_addr = inet_addr(name)) == INADDR_NONE) {
324 #else
325 if (inet_aton(name, &socketaddr.sin_addr) == 0) {
326 #endif
327 WMReleaseHost(host);
328 return NULL;
330 WMReleaseHost(host);
331 } else {
332 socketaddr.sin_addr.s_addr = htonl(INADDR_ANY);
335 if (!service || service[0]==0) {
336 socketaddr.sin_port = 0;
337 } else if ((sp = getservbyname(service, protocol))==0) {
338 char *endptr;
339 unsigned portNumber;
341 portNumber = strtoul(service, &endptr, 10);
343 if (service[0]!=0 && *endptr==0 && portNumber<65536) {
344 socketaddr.sin_port = htons(portNumber);
345 } else {
346 return NULL;
348 } else {
349 socketaddr.sin_port = sp->s_port;
352 return &socketaddr;
355 static void
356 handle_sigpipe(int signum)
358 if (0) signum=0; /* To avoid a gcc warning */
359 return;
362 static WMConnection*
363 createConnectionWithSocket(int sock, Bool closeOnRelease) /*FOLD00*/
365 WMConnection *cPtr;
366 struct sigaction sig_action;
368 cPtr = wmalloc(sizeof(WMConnection));
369 wretain(cPtr);
370 memset(cPtr, 0, sizeof(WMConnection));
372 fcntl(sock, F_SETFD, FD_CLOEXEC); /* by default close on exec */
374 cPtr->sock = sock;
375 cPtr->openTimeout.timeout = OpenTimeout;
376 cPtr->openTimeout.handler = NULL;
377 cPtr->sendTimeout.timeout = DefaultTimeout;
378 cPtr->sendTimeout.handler = NULL;
379 cPtr->closeOnRelease = closeOnRelease;
380 cPtr->outputQueue =
381 WMCreateArrayWithDestructor(16, (WMFreeDataProc*)WMReleaseData);
382 cPtr->state = WCNotConnected;
383 cPtr->timeoutState = WCTNone;
385 /* ignore dead pipe */
386 if (!SigInitialized) {
387 sig_action.sa_handler = &handle_sigpipe;
388 /* Because POSIX mandates that only signal with handlers are reset
389 accross an exec*(), we do not want to propagate ignoring SIGPIPEs
390 to children. Hence the dummy handler.
391 Philippe Troin <phil@fifi.org>
393 sig_action.sa_flags = SA_RESTART;
394 sigaction(SIGPIPE, &sig_action, NULL);
395 SigInitialized = True;
398 return cPtr;
402 #if 0
403 WMConnection*
404 WMCreateConnectionWithSocket(int sock, Bool closeOnRelease) /*FOLD00*/
406 WMConnection *cPtr;
407 struct sockaddr_in clientname;
408 int size;
409 int n;
411 cPtr = createConnectionWithSocket(sock, closeOnRelease);
412 cPtr->wasNonBlocking = WMIsConnectionNonBlocking(cPtr);
413 cPtr->isNonBlocking = cPtr->wasNonBlocking;
415 /* some way to find out if it is connected, and binded. can't find
416 if it listens though!!!
419 size = sizeof(clientname);
420 n = getpeername(sock, (struct sockaddr*) &clientname, &size);
421 if (n==0) {
422 /* Since we have a peer, it means we are connected */
423 cPtr->state = WCConnected;
424 } else {
425 size = sizeof(clientname);
426 n = getsockname(sock, (struct sockaddr*) &clientname, &size);
427 if (n==0) {
428 /* We don't have a peer, but we are binded to an address.
429 * Assume we are listening on it (we don't know that for sure!)
431 cPtr->state = WCListening;
432 } else {
433 cPtr->state = WCNotConnected;
437 return cPtr;
439 #endif
443 * host is the name on which we want to listen for incoming connections,
444 * and it must be a name of this host, or NULL if we want to listen
445 * on any incoming address.
446 * service is either a service name as present in /etc/services, or the port
447 * number we want to listen on. If NULL, a random port between
448 * 1024 and 65535 will be assigned to us.
449 * protocol is one of "tcp" or "udp". If NULL, "tcp" will be used by default.
450 * currently only "tcp" is supported.
452 WMConnection*
453 WMCreateConnectionAsServerAtAddress(char *host, char *service, char *protocol) /*FOLD00*/
455 WMConnection *cPtr;
456 struct sockaddr_in *socketaddr;
457 int sock, on;
458 int size;
460 WCErrorCode = 0;
462 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
463 wwarning(_("Bad address-service-protocol combination"));
464 return NULL;
467 /* Create the actual socket */
468 sock = socket(PF_INET, SOCK_STREAM, 0);
469 if (sock<0) {
470 WCErrorCode = errno;
471 return NULL;
475 * Set socket options. We try to make the port reusable and have it
476 * close as fast as possible without waiting in unnecessary wait states
477 * on close.
479 on = 1;
480 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
482 if (bind(sock, (struct sockaddr *)socketaddr, sizeof(*socketaddr)) < 0) {
483 WCErrorCode = errno;
484 close(sock);
485 return NULL;
488 if (listen(sock, 10) < 0) {
489 WCErrorCode = errno;
490 close(sock);
491 return NULL;
494 /* Find out what is the address/service/protocol we get */
495 /* In case some of address/service/protocol were NULL */
496 size = sizeof(*socketaddr);
497 if (getsockname(sock, (struct sockaddr*)socketaddr, &size) < 0) {
498 WCErrorCode = errno;
499 close(sock);
500 return NULL;
503 cPtr = createConnectionWithSocket(sock, True);
504 cPtr->state = WCListening;
505 WMSetConnectionNonBlocking(cPtr, True);
507 setConnectionAddress(cPtr, socketaddr);
509 return cPtr;
513 WMConnection*
514 WMCreateConnectionToAddress(char *host, char *service, char *protocol) /*FOLD00*/
516 WMConnection *cPtr;
517 struct sockaddr_in *socketaddr;
518 int sock;
520 WCErrorCode = 0;
522 wassertrv(service!=NULL && service[0]!=0, NULL);
524 if (host==NULL || host[0]==0)
525 host = "localhost";
527 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
528 wwarning(_("Bad address-service-protocol combination"));
529 return NULL;
532 /* Create the actual socket */
533 sock = socket(PF_INET, SOCK_STREAM, 0);
534 if (sock<0) {
535 WCErrorCode = errno;
536 return NULL;
538 /* make socket blocking while we connect. */
539 setSocketNonBlocking(sock, False);
540 if (connect(sock, (struct sockaddr*)socketaddr, sizeof(*socketaddr)) < 0) {
541 WCErrorCode = errno;
542 close(sock);
543 return NULL;
546 cPtr = createConnectionWithSocket(sock, True);
547 cPtr->state = WCConnected;
548 WMSetConnectionNonBlocking(cPtr, True);
549 setConnectionAddress(cPtr, socketaddr);
551 return cPtr;
555 WMConnection*
556 WMCreateConnectionToAddressAndNotify(char *host, char *service, char *protocol) /*FOLD00*/
558 WMConnection *cPtr;
559 struct sockaddr_in *socketaddr;
560 int sock;
561 Bool isNonBlocking;
563 WCErrorCode = 0;
565 wassertrv(service!=NULL && service[0]!=0, NULL);
567 if (host==NULL || host[0]==0)
568 host = "localhost";
570 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
571 wwarning(_("Bad address-service-protocol combination"));
572 return NULL;
575 /* Create the actual socket */
576 sock = socket(PF_INET, SOCK_STREAM, 0);
577 if (sock<0) {
578 WCErrorCode = errno;
579 return NULL;
581 isNonBlocking = setSocketNonBlocking(sock, True);
582 if (connect(sock, (struct sockaddr*)socketaddr, sizeof(*socketaddr)) < 0) {
583 if (errno!=EINPROGRESS) {
584 WCErrorCode = errno;
585 close(sock);
586 return NULL;
590 cPtr = createConnectionWithSocket(sock, True);
591 cPtr->state = WCInProgress;
592 cPtr->isNonBlocking = isNonBlocking;
594 cPtr->handler.write = WMAddInputHandler(cPtr->sock, WIWriteMask,
595 inputHandler, cPtr);
597 cPtr->openTimeout.handler =
598 WMAddTimerHandler(cPtr->openTimeout.timeout*1000, openTimeout, cPtr);
600 setConnectionAddress(cPtr, socketaddr);
602 return cPtr;
606 static void
607 removeAllHandlers(WMConnection *cPtr) /*FOLD00*/
609 if (cPtr->handler.read)
610 WMDeleteInputHandler(cPtr->handler.read);
611 if (cPtr->handler.write)
612 WMDeleteInputHandler(cPtr->handler.write);
613 if (cPtr->handler.exception)
614 WMDeleteInputHandler(cPtr->handler.exception);
615 if (cPtr->openTimeout.handler)
616 WMDeleteTimerHandler(cPtr->openTimeout.handler);
617 if (cPtr->sendTimeout.handler)
618 WMDeleteTimerHandler(cPtr->sendTimeout.handler);
620 cPtr->handler.read = NULL;
621 cPtr->handler.write = NULL;
622 cPtr->handler.exception = NULL;
623 cPtr->openTimeout.handler = NULL;
624 cPtr->sendTimeout.handler = NULL;
628 void
629 WMDestroyConnection(WMConnection *cPtr) /*FOLD00*/
631 if (cPtr->closeOnRelease && cPtr->sock>=0) {
632 shutdown(cPtr->sock, SHUT_RDWR);
633 close(cPtr->sock);
636 removeAllHandlers(cPtr);
637 WMFreeArray(cPtr->outputQueue); /* will also free the items with the destructor */
639 if (cPtr->address) {
640 wfree(cPtr->address);
641 wfree(cPtr->service);
642 wfree(cPtr->protocol);
645 wrelease(cPtr);
649 void
650 WMCloseConnection(WMConnection *cPtr) /*FOLD00*/
652 if (cPtr->sock>=0) {
653 shutdown(cPtr->sock, SHUT_RDWR);
654 close(cPtr->sock);
655 cPtr->sock = -1;
658 removeAllHandlers(cPtr);
659 clearOutputQueue(cPtr);
661 cPtr->state = WCClosed;
665 WMConnection*
666 WMAcceptConnection(WMConnection *listener) /*FOLD00*/
668 struct sockaddr_in clientname;
669 int size;
670 int newSock;
671 WMConnection *newConnection;
673 WCErrorCode = 0;
674 wassertrv(listener && listener->state==WCListening, NULL);
676 size = sizeof(clientname);
677 newSock = accept(listener->sock, (struct sockaddr*) &clientname, &size);
678 if (newSock<0) {
679 WCErrorCode = ((errno!=EAGAIN && errno!=EWOULDBLOCK) ? errno : 0);
680 return NULL;
683 newConnection = createConnectionWithSocket(newSock, True);
684 WMSetConnectionNonBlocking(newConnection, True);
685 newConnection->state = WCConnected;
686 setConnectionAddress(newConnection, &clientname);
688 return newConnection;
692 char*
693 WMGetConnectionAddress(WMConnection *cPtr) /*FOLD00*/
695 return cPtr->address;
699 char*
700 WMGetConnectionService(WMConnection *cPtr) /*FOLD00*/
702 return cPtr->service;
706 char*
707 WMGetConnectionProtocol(WMConnection *cPtr) /*FOLD00*/
709 return cPtr->protocol;
714 WMGetConnectionSocket(WMConnection *cPtr) /*FOLD00*/
716 return cPtr->sock;
720 WMConnectionState
721 WMGetConnectionState(WMConnection *cPtr) /*FOLD00*/
723 return cPtr->state;
727 WMConnectionTimeoutState
728 WMGetConnectionTimeoutState(WMConnection *cPtr) /*FOLD00*/
730 return cPtr->timeoutState;
734 Bool
735 WMEnqueueConnectionData(WMConnection *cPtr, WMData *data) /*FOLD00*/
737 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, False);
738 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, False);
740 if (cPtr->state!=WCConnected)
741 return False;
743 WMAddToArray(cPtr->outputQueue, WMRetainData(data));
744 return True;
749 WMSendConnectionData(WMConnection *cPtr, WMData *data) /*FOLD00*/
751 int bytes, pos, len, totalTransfer;
752 TimeoutData *tPtr = &cPtr->sendTimeout;
753 const unsigned char *dataBytes;
755 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, -1);
756 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, -1);
758 if (cPtr->state!=WCConnected)
759 return -1;
761 /* If we have no data just flush the queue, else try to send data */
762 if (data && WMGetDataLength(data)>0) {
763 WMAddToArray(cPtr->outputQueue, WMRetainData(data));
764 /* If there already was something in queue, and also a write input
765 * handler is established, it means we were unable to send, so
766 * return and let the write handler notify us when we can send.
768 if (WMGetArrayItemCount(cPtr->outputQueue)>1 && cPtr->handler.write)
769 return 0;
772 totalTransfer = 0;
774 while (WMGetArrayItemCount(cPtr->outputQueue) > 0) {
775 data = WMGetFromArray(cPtr->outputQueue, 0);
776 dataBytes = (const unsigned char *)WMDataBytes(data);
777 len = WMGetDataLength(data);
778 pos = cPtr->bufPos; /* where we're left last time */
779 while(pos < len) {
780 again:
781 bytes = write(cPtr->sock, dataBytes+pos, len - pos);
782 if(bytes<0) {
783 switch (errno) {
784 case EINTR:
785 goto again;
786 case EWOULDBLOCK:
787 /* save the position where we're left and add a timeout */
788 cPtr->bufPos = pos;
789 if (!tPtr->handler) {
790 tPtr->handler = WMAddTimerHandler(tPtr->timeout*1000,
791 sendTimeout, cPtr);
793 if (!cPtr->handler.write) {
794 cPtr->handler.write =
795 WMAddInputHandler(cPtr->sock, WIWriteMask,
796 inputHandler, cPtr);
798 return totalTransfer;
799 default:
800 WCErrorCode = errno;
801 cPtr->state = WCDied;
802 removeAllHandlers(cPtr);
803 if (cPtr->delegate && cPtr->delegate->didDie)
804 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
805 return -1;
808 pos += bytes;
809 totalTransfer += bytes;
811 WMDeleteFromArray(cPtr->outputQueue, 0);
812 cPtr->bufPos = 0;
813 if (tPtr->handler) {
814 WMDeleteTimerHandler(tPtr->handler);
815 tPtr->handler = NULL;
817 if (cPtr->handler.write) {
818 WMDeleteInputHandler(cPtr->handler.write);
819 cPtr->handler.write = NULL;
823 return totalTransfer;
828 * WMGetConnectionAvailableData(connection):
830 * will return a WMData structure containing the available data on the
831 * specified connection. If connection is non-blocking (default) and no data
832 * is available when this function is called, an empty WMData is returned.
834 * If an error occurs while reading or the other side closed connection,
835 * it will return NULL.
836 * Also trying to read from an already died or closed connection is
837 * considered to be an error condition, and will return NULL.
839 WMData*
840 WMGetConnectionAvailableData(WMConnection *cPtr) /*FOLD00*/
842 char buffer[NETBUF_SIZE];
843 int nbytes;
844 WMData *aData;
846 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, NULL);
847 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, NULL);
849 if (cPtr->state!=WCConnected)
850 return NULL;
852 aData = NULL;
854 again:
855 nbytes = read(cPtr->sock, buffer, NETBUF_SIZE);
856 if (nbytes<0) {
857 switch (errno) {
858 case EINTR:
859 goto again;
860 case EWOULDBLOCK:
861 aData = WMCreateDataWithCapacity(0);
862 break;
863 default:
864 WCErrorCode = errno;
865 cPtr->state = WCDied;
866 removeAllHandlers(cPtr);
867 if (cPtr->delegate && cPtr->delegate->didDie)
868 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
869 break;
871 } else if (nbytes==0) { /* the other side has closed connection */
872 cPtr->state = WCClosed;
873 removeAllHandlers(cPtr);
874 if (cPtr->delegate && cPtr->delegate->didDie)
875 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
876 } else {
877 aData = WMCreateDataWithBytes(buffer, nbytes);
880 return aData;
884 void
885 WMSetConnectionDelegate(WMConnection *cPtr, ConnectionDelegate *delegate) /*FOLD00*/
887 wassertr(cPtr->sock >= 0);
888 /* Don't try to set the delegate multiple times */
889 wassertr(cPtr->delegate == NULL);
891 cPtr->delegate = delegate;
892 if (delegate && delegate->didReceiveInput && !cPtr->handler.read)
893 cPtr->handler.read = WMAddInputHandler(cPtr->sock, WIReadMask,
894 inputHandler, cPtr);
895 if (delegate && delegate->didCatchException && !cPtr->handler.exception)
896 cPtr->handler.exception = WMAddInputHandler(cPtr->sock, WIExceptMask,
897 inputHandler, cPtr);
901 #if 0
902 Bool
903 WMIsConnectionNonBlocking(WMConnection *cPtr) /*FOLD00*/
905 #if 1
906 int state;
908 state = fcntl(cPtr->sock, F_GETFL, 0);
910 if (state < 0) {
911 /* If we can't use fcntl on socket, this probably also means we could
912 * not use fcntl to set non-blocking mode, and since a socket defaults
913 * to blocking when created, return False as the best assumption */
914 return False;
917 return ((state & NONBLOCK_OPT)!=0);
918 #else
919 return cPtr->isNonBlocking;
920 #endif
922 #endif
925 Bool
926 WMSetConnectionNonBlocking(WMConnection *cPtr, Bool flag) /*FOLD00*/
928 wassertrv(cPtr!=NULL && cPtr->sock>=0, False);
930 if (cPtr->isNonBlocking == flag)
931 return True;
933 if (setSocketNonBlocking(cPtr->sock, flag)==True) {
934 cPtr->isNonBlocking = flag;
935 return True;
938 return False;
942 Bool
943 WMSetConnectionCloseOnExec(WMConnection *cPtr, Bool flag)
945 wassertrv(cPtr!=NULL && cPtr->sock>=0, False);
947 if (fcntl(cPtr->sock, F_SETFD, (flag ? FD_CLOEXEC : 0)) < 0) {
948 return False;
951 return True;
955 void*
956 WMGetConnectionClientData(WMConnection *cPtr) /*FOLD00*/
958 return cPtr->clientData;
962 void
963 WMSetConnectionClientData(WMConnection *cPtr, void *data) /*FOLD00*/
965 cPtr->clientData = data;
969 unsigned int
970 WMGetConnectionFlags(WMConnection *cPtr) /*FOLD00*/
972 return cPtr->uflags;
976 void
977 WMSetConnectionFlags(WMConnection *cPtr, unsigned int flags) /*FOLD00*/
979 cPtr->uflags = flags;
983 WMArray*
984 WMGetConnectionUnsentData(WMConnection *cPtr)
986 return cPtr->outputQueue;
990 void
991 WMSetConnectionDefaultTimeout(unsigned int timeout) /*FOLD00*/
993 if (timeout == 0) {
994 DefaultTimeout = DEF_TIMEOUT;
995 } else {
996 DefaultTimeout = timeout;
1001 void
1002 WMSetConnectionOpenTimeout(unsigned int timeout) /*FOLD00*/
1004 if (timeout == 0) {
1005 OpenTimeout = DefaultTimeout;
1006 } else {
1007 OpenTimeout = timeout;
1012 void
1013 WMSetConnectionSendTimeout(WMConnection *cPtr, unsigned int timeout) /*FOLD00*/
1015 if (timeout == 0) {
1016 cPtr->sendTimeout.timeout = DefaultTimeout;
1017 } else {
1018 cPtr->sendTimeout.timeout = timeout;