replaced CPPFLAGS with AM_CPPFLAGS in some Makefile.am's to avoid overwriting the...
[wmaker-crm.git] / WINGs / connection.c
blob31ba076061733fc4cbfb9253ed96bd96d412ee54
1 /*
2 * WINGs WMConnection function library
4 * Copyright (c) 1999-2003 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 // should we close it no matter what (after calling the didTimeout
178 // delegate)? -Dan
179 if (cPtr->delegate && cPtr->delegate->didTimeout) {
180 (*cPtr->delegate->didTimeout)(cPtr->delegate, cPtr);
181 } else {
182 WMCloseConnection(cPtr);
183 cPtr->state = WCTimedOut; /* the above set state to WCClosed */
189 static void
190 inputHandler(int fd, int mask, void *clientData)
192 WMConnection *cPtr = (WMConnection*)clientData;
194 if (cPtr->state==WCClosed || cPtr->state==WCDied)
195 return;
197 if ((mask & WIWriteMask)) {
198 int result;
200 if (cPtr->state == WCInProgress) {
201 Bool failed;
202 int len = sizeof(result);
204 WCErrorCode = 0;
205 if (getsockopt(cPtr->sock, SOL_SOCKET, SO_ERROR,
206 (void*)&result, &len) == 0 && result != 0) {
207 cPtr->state = WCFailed;
208 WCErrorCode = result;
209 failed = True;
210 /* should call wsyserrorwithcode(result, ...) here? */
211 } else {
212 cPtr->state = WCConnected;
213 failed = False;
216 if (cPtr->handler.write) {
217 WMDeleteInputHandler(cPtr->handler.write);
218 cPtr->handler.write = NULL;
221 if (cPtr->openTimeout.handler) {
222 WMDeleteTimerHandler(cPtr->openTimeout.handler);
223 cPtr->openTimeout.handler = NULL;
226 if (cPtr->delegate && cPtr->delegate->didInitialize)
227 (*cPtr->delegate->didInitialize)(cPtr->delegate, cPtr);
229 /* we use failed and not cPtr->state here, because cPtr may be
230 * destroyed by the delegate called above if the connection failed
232 if (failed)
233 return;
234 } else if (cPtr->state == WCConnected) {
235 result = WMFlushConnection(cPtr);
236 if (result>0 && cPtr->delegate && cPtr->delegate->canResumeSending) {
237 (*cPtr->delegate->canResumeSending)(cPtr->delegate, cPtr);
242 if (!cPtr->delegate)
243 return;
245 /* if the connection died, may get destroyed in the delegate, so retain */
246 wretain(cPtr);
248 if ((mask & WIReadMask) && cPtr->delegate->didReceiveInput)
249 (*cPtr->delegate->didReceiveInput)(cPtr->delegate, cPtr);
251 if ((mask & WIExceptMask) && cPtr->delegate->didCatchException)
252 (*cPtr->delegate->didCatchException)(cPtr->delegate, cPtr);
254 wrelease(cPtr);
258 static Bool
259 setSocketNonBlocking(int sock, Bool flag)
261 int state;
262 Bool isNonBlock;
264 state = fcntl(sock, F_GETFL, 0);
266 if (state < 0) {
267 /* set WCErrorCode here? -Dan*/
268 return False;
271 isNonBlock = (state & NONBLOCK_OPT) != 0;
273 if (flag) {
274 if (isNonBlock)
275 return True;
276 state |= NONBLOCK_OPT;
277 } else {
278 if (!isNonBlock)
279 return True;
280 state &= ~NONBLOCK_OPT;
283 if (fcntl(sock, F_SETFL, state) < 0) {
284 /* set WCErrorCode here? -Dan*/
285 return False;
288 return True;
292 static void
293 setConnectionAddress(WMConnection *cPtr, struct sockaddr_in *socketaddr)
295 wassertr(cPtr->address==NULL);
297 cPtr->address = wstrdup(inet_ntoa(socketaddr->sin_addr));
298 cPtr->service = wmalloc(16);
299 sprintf(cPtr->service, "%hu", ntohs(socketaddr->sin_port));
300 cPtr->protocol = wstrdup("tcp");
304 static struct sockaddr_in*
305 getSocketAddress(char* name, char* service, char* protocol)
307 static struct sockaddr_in socketaddr;
308 struct servent *sp;
310 if (!protocol || protocol[0]==0)
311 protocol = "tcp";
313 memset(&socketaddr, 0, sizeof(struct sockaddr_in));
314 socketaddr.sin_family = AF_INET;
317 * If we were given a hostname, we use any address for that host.
318 * Otherwise we expect the given name to be an address unless it is
319 * NULL (any address).
321 if (name && name[0]!=0) {
322 WMHost *host = WMGetHostWithName(name);
324 if (!host)
325 return NULL; /* name is not a hostname nor a number and dot adr */
327 name = WMGetHostAddress(host);
328 #ifndef HAVE_INET_ATON
329 if ((socketaddr.sin_addr.s_addr = inet_addr(name)) == INADDR_NONE) {
330 #else
331 if (inet_aton(name, &socketaddr.sin_addr) == 0) {
332 #endif
333 WMReleaseHost(host);
334 return NULL;
336 WMReleaseHost(host);
337 } else {
338 socketaddr.sin_addr.s_addr = htonl(INADDR_ANY);
341 if (!service || service[0]==0) {
342 socketaddr.sin_port = 0;
343 } else if ((sp = getservbyname(service, protocol))==0) {
344 char *endptr;
345 unsigned portNumber;
347 portNumber = strtoul(service, &endptr, 10);
349 if (service[0]!=0 && *endptr==0 && portNumber<65536) {
350 socketaddr.sin_port = htons(portNumber);
351 } else {
352 return NULL;
354 } else {
355 socketaddr.sin_port = sp->s_port;
358 return &socketaddr;
362 static void
363 dummyHandler(int signum)
368 static WMConnection*
369 createConnectionWithSocket(int sock, Bool closeOnRelease)
371 WMConnection *cPtr;
372 struct sigaction sig_action;
374 cPtr = wmalloc(sizeof(WMConnection));
375 wretain(cPtr);
376 memset(cPtr, 0, sizeof(WMConnection));
378 fcntl(sock, F_SETFD, FD_CLOEXEC); /* by default close on exec */
380 cPtr->sock = sock;
381 cPtr->openTimeout.timeout = OpenTimeout;
382 cPtr->openTimeout.handler = NULL;
383 cPtr->sendTimeout.timeout = DefaultTimeout;
384 cPtr->sendTimeout.handler = NULL;
385 cPtr->closeOnRelease = closeOnRelease;
386 cPtr->shutdownOnClose = 1;
387 cPtr->outputQueue =
388 WMCreateArrayWithDestructor(16, (WMFreeDataProc*)WMReleaseData);
389 cPtr->state = WCNotConnected;
390 cPtr->timeoutState = WCTNone;
392 /* ignore dead pipe */
393 if (!SigInitialized) {
394 /* Because POSIX mandates that only signal with handlers are reset
395 * accross an exec*(), we do not want to propagate ignoring SIGPIPEs
396 * to children. Hence the dummy handler. Philippe Troin <phil@fifi.org>
398 sig_action.sa_handler = &dummyHandler;
399 sig_action.sa_flags = SA_RESTART;
400 sigaction(SIGPIPE, &sig_action, NULL);
401 SigInitialized = True;
404 return cPtr;
408 #if 0
409 WMConnection*
410 WMCreateConnectionWithSocket(int sock, Bool closeOnRelease)
412 WMConnection *cPtr;
413 struct sockaddr_in clientname;
414 int size;
415 int n;
417 cPtr = createConnectionWithSocket(sock, closeOnRelease);
418 cPtr->wasNonBlocking = WMIsConnectionNonBlocking(cPtr);
419 cPtr->isNonBlocking = cPtr->wasNonBlocking;
421 /* some way to find out if it is connected, and binded. can't find
422 if it listens though!!!
425 size = sizeof(clientname);
426 n = getpeername(sock, (struct sockaddr*) &clientname, &size);
427 if (n==0) {
428 /* Since we have a peer, it means we are connected */
429 cPtr->state = WCConnected;
430 } else {
431 size = sizeof(clientname);
432 n = getsockname(sock, (struct sockaddr*) &clientname, &size);
433 if (n==0) {
434 /* We don't have a peer, but we are binded to an address.
435 * Assume we are listening on it (we don't know that for sure!)
437 cPtr->state = WCListening;
438 } else {
439 cPtr->state = WCNotConnected;
443 return cPtr;
445 #endif
449 * host is the name on which we want to listen for incoming connections,
450 * and it must be a name of this host, or NULL if we want to listen
451 * on any incoming address.
452 * service is either a service name as present in /etc/services, or the port
453 * number we want to listen on. If NULL, a random port between
454 * 1024 and 65535 will be assigned to us.
455 * protocol is one of "tcp" or "udp". If NULL, "tcp" will be used by default.
456 * currently only "tcp" is supported.
458 WMConnection*
459 WMCreateConnectionAsServerAtAddress(char *host, char *service, char *protocol)
461 WMConnection *cPtr;
462 struct sockaddr_in *socketaddr;
463 int sock, on;
464 int size;
466 WCErrorCode = 0;
468 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
469 wwarning(_("Bad address-service-protocol combination"));
470 return NULL;
473 /* Create the actual socket */
474 sock = socket(PF_INET, SOCK_STREAM, 0);
475 if (sock<0) {
476 WCErrorCode = errno;
477 return NULL;
481 * Set socket options. We try to make the port reusable and have it
482 * close as fast as possible without waiting in unnecessary wait states
483 * on close.
485 on = 1;
486 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
488 if (bind(sock, (struct sockaddr *)socketaddr, sizeof(*socketaddr)) < 0) {
489 WCErrorCode = errno;
490 close(sock);
491 return NULL;
494 if (listen(sock, 10) < 0) {
495 WCErrorCode = errno;
496 close(sock);
497 return NULL;
500 /* Find out what is the address/service/protocol we get */
501 /* In case some of address/service/protocol were NULL */
502 size = sizeof(*socketaddr);
503 if (getsockname(sock, (struct sockaddr*)socketaddr, &size) < 0) {
504 WCErrorCode = errno;
505 close(sock);
506 return NULL;
509 cPtr = createConnectionWithSocket(sock, True);
510 cPtr->state = WCListening;
511 WMSetConnectionNonBlocking(cPtr, True);
513 setConnectionAddress(cPtr, socketaddr);
515 return cPtr;
519 WMConnection*
520 WMCreateConnectionToAddress(char *host, char *service, char *protocol)
522 WMConnection *cPtr;
523 struct sockaddr_in *socketaddr;
524 int sock;
526 WCErrorCode = 0;
528 wassertrv(service!=NULL && service[0]!=0, NULL);
530 if (host==NULL || host[0]==0)
531 host = "localhost";
533 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
534 wwarning(_("Bad address-service-protocol combination"));
535 return NULL;
538 /* Create the actual socket */
539 sock = socket(PF_INET, SOCK_STREAM, 0);
540 if (sock<0) {
541 WCErrorCode = errno;
542 return NULL;
544 /* make socket blocking while we connect. */
545 setSocketNonBlocking(sock, False);
546 if (connect(sock, (struct sockaddr*)socketaddr, sizeof(*socketaddr)) < 0) {
547 WCErrorCode = errno;
548 close(sock);
549 return NULL;
552 cPtr = createConnectionWithSocket(sock, True);
553 cPtr->state = WCConnected;
554 WMSetConnectionNonBlocking(cPtr, True);
555 setConnectionAddress(cPtr, socketaddr);
557 return cPtr;
561 WMConnection*
562 WMCreateConnectionToAddressAndNotify(char *host, char *service, char *protocol)
564 WMConnection *cPtr;
565 struct sockaddr_in *socketaddr;
566 int sock;
567 Bool isNonBlocking;
569 WCErrorCode = 0;
571 wassertrv(service!=NULL && service[0]!=0, NULL);
573 if (host==NULL || host[0]==0)
574 host = "localhost";
576 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
577 wwarning(_("Bad address-service-protocol combination"));
578 return NULL;
581 /* Create the actual socket */
582 sock = socket(PF_INET, SOCK_STREAM, 0);
583 if (sock<0) {
584 WCErrorCode = errno;
585 return NULL;
587 isNonBlocking = setSocketNonBlocking(sock, True);
588 if (connect(sock, (struct sockaddr*)socketaddr, sizeof(*socketaddr)) < 0) {
589 if (errno!=EINPROGRESS) {
590 WCErrorCode = errno;
591 close(sock);
592 return NULL;
596 cPtr = createConnectionWithSocket(sock, True);
597 cPtr->state = WCInProgress;
598 cPtr->isNonBlocking = isNonBlocking;
600 cPtr->handler.write = WMAddInputHandler(cPtr->sock, WIWriteMask,
601 inputHandler, cPtr);
603 cPtr->openTimeout.handler =
604 WMAddTimerHandler(cPtr->openTimeout.timeout*1000, openTimeout, cPtr);
606 setConnectionAddress(cPtr, socketaddr);
608 return cPtr;
612 static void
613 removeAllHandlers(WMConnection *cPtr)
615 if (cPtr->handler.read)
616 WMDeleteInputHandler(cPtr->handler.read);
617 if (cPtr->handler.write)
618 WMDeleteInputHandler(cPtr->handler.write);
619 if (cPtr->handler.exception)
620 WMDeleteInputHandler(cPtr->handler.exception);
621 if (cPtr->openTimeout.handler)
622 WMDeleteTimerHandler(cPtr->openTimeout.handler);
623 if (cPtr->sendTimeout.handler)
624 WMDeleteTimerHandler(cPtr->sendTimeout.handler);
626 cPtr->handler.read = NULL;
627 cPtr->handler.write = NULL;
628 cPtr->handler.exception = NULL;
629 cPtr->openTimeout.handler = NULL;
630 cPtr->sendTimeout.handler = NULL;
634 void
635 WMDestroyConnection(WMConnection *cPtr)
637 if (cPtr->closeOnRelease && cPtr->sock>=0) {
638 if (cPtr->shutdownOnClose) {
639 shutdown(cPtr->sock, SHUT_RDWR);
641 close(cPtr->sock);
644 removeAllHandlers(cPtr);
645 WMFreeArray(cPtr->outputQueue); /* will also free the items with the destructor */
647 if (cPtr->address) {
648 wfree(cPtr->address);
649 wfree(cPtr->service);
650 wfree(cPtr->protocol);
653 wrelease(cPtr);
657 void
658 WMCloseConnection(WMConnection *cPtr)
660 if (cPtr->sock>=0) {
661 if (cPtr->shutdownOnClose) {
662 shutdown(cPtr->sock, SHUT_RDWR);
664 close(cPtr->sock);
665 cPtr->sock = -1;
668 removeAllHandlers(cPtr);
669 clearOutputQueue(cPtr);
671 cPtr->state = WCClosed;
675 WMConnection*
676 WMAcceptConnection(WMConnection *listener)
678 struct sockaddr_in clientname;
679 int size;
680 int newSock;
681 WMConnection *newConnection;
683 WCErrorCode = 0;
684 wassertrv(listener && listener->state==WCListening, NULL);
686 size = sizeof(clientname);
687 newSock = accept(listener->sock, (struct sockaddr*) &clientname, &size);
688 if (newSock<0) {
689 WCErrorCode = ((errno!=EAGAIN && errno!=EWOULDBLOCK) ? errno : 0);
690 return NULL;
693 newConnection = createConnectionWithSocket(newSock, True);
694 WMSetConnectionNonBlocking(newConnection, True);
695 newConnection->state = WCConnected;
696 setConnectionAddress(newConnection, &clientname);
698 return newConnection;
702 char*
703 WMGetConnectionAddress(WMConnection *cPtr)
705 return cPtr->address;
709 char*
710 WMGetConnectionService(WMConnection *cPtr)
712 return cPtr->service;
716 char*
717 WMGetConnectionProtocol(WMConnection *cPtr)
719 return cPtr->protocol;
724 WMGetConnectionSocket(WMConnection *cPtr)
726 return cPtr->sock;
730 WMConnectionState
731 WMGetConnectionState(WMConnection *cPtr)
733 return cPtr->state;
737 WMConnectionTimeoutState
738 WMGetConnectionTimeoutState(WMConnection *cPtr)
740 return cPtr->timeoutState;
744 Bool
745 WMEnqueueConnectionData(WMConnection *cPtr, WMData *data)
747 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, False);
748 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, False);
750 if (cPtr->state!=WCConnected)
751 return False;
753 WMAddToArray(cPtr->outputQueue, WMRetainData(data));
754 return True;
759 * Return value:
760 * -1 - not connected or connection died while sending
761 * 0 - couldn't send the data (or part of it). data is saved in a queue
762 * and will be sent when possible. after it is sent the canResumeSending
763 * callback will be called.
764 * 1 - data was succesfully sent
767 WMSendConnectionData(WMConnection *cPtr, WMData *data)
769 int bytes, pos, len;
770 TimeoutData *tPtr = &cPtr->sendTimeout;
771 const unsigned char *dataBytes;
773 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, -1);
774 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, -1);
776 if (cPtr->state!=WCConnected)
777 return -1;
779 /* If we have no data just flush the queue, else try to send data */
780 if (data && WMGetDataLength(data)>0) {
781 WMAddToArray(cPtr->outputQueue, WMRetainData(data));
782 /* If there already was something in queue, and also a write input
783 * handler is established, it means we were unable to send, so
784 * return and let the write handler notify us when we can send.
786 if (WMGetArrayItemCount(cPtr->outputQueue)>1 && cPtr->handler.write)
787 return 0;
790 while (WMGetArrayItemCount(cPtr->outputQueue) > 0) {
791 data = WMGetFromArray(cPtr->outputQueue, 0);
792 dataBytes = (const unsigned char *)WMDataBytes(data);
793 len = WMGetDataLength(data);
794 pos = cPtr->bufPos; /* where we're left last time */
795 while(pos < len) {
796 again:
797 bytes = write(cPtr->sock, dataBytes+pos, len - pos);
798 if(bytes<0) {
799 switch (errno) {
800 case EINTR:
801 goto again;
802 case EWOULDBLOCK:
803 /* save the position where we're left and add a timeout */
804 cPtr->bufPos = pos;
805 if (!tPtr->handler) {
806 tPtr->handler = WMAddTimerHandler(tPtr->timeout*1000,
807 sendTimeout, cPtr);
809 if (!cPtr->handler.write) {
810 cPtr->handler.write =
811 WMAddInputHandler(cPtr->sock, WIWriteMask,
812 inputHandler, cPtr);
814 return 0;
815 default:
816 WCErrorCode = errno;
817 cPtr->state = WCDied;
818 removeAllHandlers(cPtr);
819 if (cPtr->delegate && cPtr->delegate->didDie)
820 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
821 return -1;
824 pos += bytes;
826 WMDeleteFromArray(cPtr->outputQueue, 0);
827 cPtr->bufPos = 0;
828 if (tPtr->handler) {
829 WMDeleteTimerHandler(tPtr->handler);
830 tPtr->handler = NULL;
832 /*if (cPtr->handler.write) {
833 WMDeleteInputHandler(cPtr->handler.write);
834 cPtr->handler.write = NULL;
838 if (cPtr->handler.write) {
839 WMDeleteInputHandler(cPtr->handler.write);
840 cPtr->handler.write = NULL;
843 return 1;
848 * WMGetConnectionAvailableData(connection):
850 * will return a WMData structure containing the available data on the
851 * specified connection. If connection is non-blocking (default) and no data
852 * is available when this function is called, an empty WMData is returned.
854 * If an error occurs while reading or the other side closed connection,
855 * it will return NULL.
856 * Also trying to read from an already died or closed connection is
857 * considered to be an error condition, and will return NULL.
859 WMData*
860 WMGetConnectionAvailableData(WMConnection *cPtr)
862 char buffer[NETBUF_SIZE];
863 int nbytes;
864 WMData *aData;
866 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, NULL);
867 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, NULL);
869 if (cPtr->state!=WCConnected)
870 return NULL;
872 aData = NULL;
874 again:
875 nbytes = read(cPtr->sock, buffer, NETBUF_SIZE);
876 if (nbytes<0) {
877 switch (errno) {
878 case EINTR:
879 goto again;
880 case EWOULDBLOCK:
881 aData = WMCreateDataWithCapacity(0);
882 break;
883 default:
884 WCErrorCode = errno;
885 cPtr->state = WCDied;
886 removeAllHandlers(cPtr);
887 if (cPtr->delegate && cPtr->delegate->didDie)
888 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
889 break;
891 } else if (nbytes==0) { /* the other side has closed connection */
892 cPtr->state = WCClosed;
893 removeAllHandlers(cPtr);
894 if (cPtr->delegate && cPtr->delegate->didDie)
895 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
896 } else {
897 aData = WMCreateDataWithBytes(buffer, nbytes);
900 return aData;
904 void
905 WMSetConnectionDelegate(WMConnection *cPtr, ConnectionDelegate *delegate)
907 wassertr(cPtr->sock >= 0);
908 /* Don't try to set the delegate multiple times */
909 wassertr(cPtr->delegate == NULL);
911 cPtr->delegate = delegate;
912 if (delegate && delegate->didReceiveInput && !cPtr->handler.read)
913 cPtr->handler.read = WMAddInputHandler(cPtr->sock, WIReadMask,
914 inputHandler, cPtr);
915 if (delegate && delegate->didCatchException && !cPtr->handler.exception)
916 cPtr->handler.exception = WMAddInputHandler(cPtr->sock, WIExceptMask,
917 inputHandler, cPtr);
921 #if 0
922 Bool
923 WMIsConnectionNonBlocking(WMConnection *cPtr)
925 #if 1
926 int state;
928 state = fcntl(cPtr->sock, F_GETFL, 0);
930 if (state < 0) {
931 /* If we can't use fcntl on socket, this probably also means we could
932 * not use fcntl to set non-blocking mode, and since a socket defaults
933 * to blocking when created, return False as the best assumption */
934 return False;
937 return ((state & NONBLOCK_OPT)!=0);
938 #else
939 return cPtr->isNonBlocking;
940 #endif
942 #endif
945 Bool
946 WMSetConnectionNonBlocking(WMConnection *cPtr, Bool flag)
948 wassertrv(cPtr!=NULL && cPtr->sock>=0, False);
950 flag = ((flag==0) ? 0 : 1);
952 if (cPtr->isNonBlocking == flag)
953 return True;
955 if (setSocketNonBlocking(cPtr->sock, flag)==True) {
956 cPtr->isNonBlocking = flag;
957 return True;
960 return False;
964 Bool
965 WMSetConnectionCloseOnExec(WMConnection *cPtr, Bool flag)
967 wassertrv(cPtr!=NULL && cPtr->sock>=0, False);
969 if (fcntl(cPtr->sock, F_SETFD, ((flag==0) ? 0 : FD_CLOEXEC)) < 0) {
970 return False;
973 return True;
977 void
978 WMSetConnectionShutdownOnClose(WMConnection *cPtr, Bool flag)
980 cPtr->shutdownOnClose = ((flag==0) ? 0 : 1);
984 void*
985 WMGetConnectionClientData(WMConnection *cPtr)
987 return cPtr->clientData;
991 void
992 WMSetConnectionClientData(WMConnection *cPtr, void *data)
994 cPtr->clientData = data;
998 unsigned int
999 WMGetConnectionFlags(WMConnection *cPtr)
1001 return cPtr->uflags;
1005 void
1006 WMSetConnectionFlags(WMConnection *cPtr, unsigned int flags)
1008 cPtr->uflags = flags;
1012 WMArray*
1013 WMGetConnectionUnsentData(WMConnection *cPtr)
1015 return cPtr->outputQueue;
1019 void
1020 WMSetConnectionDefaultTimeout(unsigned int timeout)
1022 if (timeout == 0) {
1023 DefaultTimeout = DEF_TIMEOUT;
1024 } else {
1025 DefaultTimeout = timeout;
1030 void
1031 WMSetConnectionOpenTimeout(unsigned int timeout)
1033 if (timeout == 0) {
1034 OpenTimeout = DefaultTimeout;
1035 } else {
1036 OpenTimeout = timeout;
1041 void
1042 WMSetConnectionSendTimeout(WMConnection *cPtr, unsigned int timeout)
1044 if (timeout == 0) {
1045 cPtr->sendTimeout.timeout = DefaultTimeout;
1046 } else {
1047 cPtr->sendTimeout.timeout = timeout;