Fix periodic focus bug
[wmaker-crm.git] / WINGs / connection.c
blobec5e92ee82cfe43b1bed2976cbe018be225ead42
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. */
69 #ifdef __POSIX_SOURCE
70 # define NONBLOCK_OPT O_NONBLOCK
71 #else
72 # define NONBLOCK_OPT FNDELAY
73 #endif
76 #define NONBLOCK_OPT O_NONBLOCK
78 #define NETBUF_SIZE 4096
80 #define DEF_TIMEOUT 600 /* 600 seconds == 10 minutes */
84 int WCErrorCode = 0;
86 static Bool SigInitialized = False;
88 static unsigned int DefaultTimeout = DEF_TIMEOUT;
89 static unsigned int OpenTimeout = DEF_TIMEOUT;
93 typedef struct TimeoutData {
94 unsigned timeout;
95 WMHandlerID *handler;
96 } TimeoutData;
99 typedef struct W_Connection {
100 int sock; /* the socket we speak through */
102 struct {
103 WMHandlerID *read; /* the input read handler */
104 WMHandlerID *write; /* the input write handler */
105 WMHandlerID *exception; /* the input exception handler */
106 } handler;
108 ConnectionDelegate *delegate; /* client delegates */
109 void *clientData; /* client data */
110 unsigned int uflags; /* flags for the client */
112 WMArray *outputQueue;
113 unsigned bufPos;
115 TimeoutData sendTimeout;
116 TimeoutData openTimeout;
118 WMConnectionState state;
119 WMConnectionTimeoutState timeoutState;
121 char *address;
122 char *service;
123 char *protocol;
125 Bool closeOnRelease;
126 Bool shutdownOnClose;
127 Bool wasNonBlocking;
128 Bool isNonBlocking;
130 } W_Connection;
134 static void
135 clearOutputQueue(WMConnection *cPtr)
137 cPtr->bufPos = 0;
138 WMEmptyArray(cPtr->outputQueue);
142 static void
143 openTimeout(void *cdata)
145 WMConnection *cPtr = (WMConnection*) cdata;
147 cPtr->openTimeout.handler = NULL;
148 if (cPtr->handler.write) {
149 WMDeleteInputHandler(cPtr->handler.write);
150 cPtr->handler.write = NULL;
152 if (cPtr->state != WCConnected) {
153 cPtr->state = WCTimedOut;
154 cPtr->timeoutState = WCTWhileOpening;
155 if (cPtr->delegate && cPtr->delegate->didTimeout) {
156 (*cPtr->delegate->didTimeout)(cPtr->delegate, cPtr);
157 } else {
158 WMCloseConnection(cPtr);
159 cPtr->state = WCTimedOut; /* the above set state to WCClosed */
165 static void
166 sendTimeout(void *cdata)
168 WMConnection *cPtr = (WMConnection*) cdata;
170 cPtr->sendTimeout.handler = NULL;
171 if (cPtr->handler.write) {
172 WMDeleteInputHandler(cPtr->handler.write);
173 cPtr->handler.write = NULL;
175 if (WMGetArrayItemCount(cPtr->outputQueue)>0) {
176 clearOutputQueue(cPtr);
177 cPtr->state = WCTimedOut;
178 cPtr->timeoutState = WCTWhileSending;
179 /* // should we close it no matter what (after calling the didTimeout
180 // delegate)? -Dan */
181 if (cPtr->delegate && cPtr->delegate->didTimeout) {
182 (*cPtr->delegate->didTimeout)(cPtr->delegate, cPtr);
183 } else {
184 WMCloseConnection(cPtr);
185 cPtr->state = WCTimedOut; /* the above set state to WCClosed */
191 static void
192 inputHandler(int fd, int mask, void *clientData)
194 WMConnection *cPtr = (WMConnection*)clientData;
196 if (cPtr->state==WCClosed || cPtr->state==WCDied)
197 return;
199 if ((mask & WIWriteMask)) {
200 int result;
202 if (cPtr->state == WCInProgress) {
203 Bool failed;
204 socklen_t len = sizeof(result);
206 WCErrorCode = 0;
207 if (getsockopt(cPtr->sock, SOL_SOCKET, SO_ERROR,
208 (void*)&result, &len) == 0 && result != 0) {
209 cPtr->state = WCFailed;
210 WCErrorCode = result;
211 failed = True;
212 /* should call wsyserrorwithcode(result, ...) here? */
213 } else {
214 cPtr->state = WCConnected;
215 failed = False;
218 if (cPtr->handler.write) {
219 WMDeleteInputHandler(cPtr->handler.write);
220 cPtr->handler.write = NULL;
223 if (cPtr->openTimeout.handler) {
224 WMDeleteTimerHandler(cPtr->openTimeout.handler);
225 cPtr->openTimeout.handler = NULL;
228 if (cPtr->delegate && cPtr->delegate->didInitialize)
229 (*cPtr->delegate->didInitialize)(cPtr->delegate, cPtr);
231 /* we use failed and not cPtr->state here, because cPtr may be
232 * destroyed by the delegate called above if the connection failed
234 if (failed)
235 return;
236 } else if (cPtr->state == WCConnected) {
237 result = WMFlushConnection(cPtr);
238 if (result>0 && cPtr->delegate && cPtr->delegate->canResumeSending) {
239 (*cPtr->delegate->canResumeSending)(cPtr->delegate, cPtr);
244 if (!cPtr->delegate)
245 return;
247 /* if the connection died, may get destroyed in the delegate, so retain */
248 wretain(cPtr);
250 if ((mask & WIReadMask) && cPtr->delegate->didReceiveInput)
251 (*cPtr->delegate->didReceiveInput)(cPtr->delegate, cPtr);
253 if ((mask & WIExceptMask) && cPtr->delegate->didCatchException)
254 (*cPtr->delegate->didCatchException)(cPtr->delegate, cPtr);
256 wrelease(cPtr);
260 static Bool
261 setSocketNonBlocking(int sock, Bool flag)
263 int state;
264 Bool isNonBlock;
266 state = fcntl(sock, F_GETFL, 0);
268 if (state < 0) {
269 /* set WCErrorCode here? -Dan*/
270 return False;
273 isNonBlock = (state & NONBLOCK_OPT) != 0;
275 if (flag) {
276 if (isNonBlock)
277 return True;
278 state |= NONBLOCK_OPT;
279 } else {
280 if (!isNonBlock)
281 return True;
282 state &= ~NONBLOCK_OPT;
285 if (fcntl(sock, F_SETFL, state) < 0) {
286 /* set WCErrorCode here? -Dan*/
287 return False;
290 return True;
294 static void
295 setConnectionAddress(WMConnection *cPtr, struct sockaddr_in *socketaddr)
297 wassertr(cPtr->address==NULL);
299 cPtr->address = wstrdup(inet_ntoa(socketaddr->sin_addr));
300 cPtr->service = wmalloc(16);
301 sprintf(cPtr->service, "%hu", ntohs(socketaddr->sin_port));
302 cPtr->protocol = wstrdup("tcp");
306 static struct sockaddr_in*
307 getSocketAddress(char* name, char* service, char* protocol)
309 static struct sockaddr_in socketaddr;
310 struct servent *sp;
312 if (!protocol || protocol[0]==0)
313 protocol = "tcp";
315 memset(&socketaddr, 0, sizeof(struct sockaddr_in));
316 socketaddr.sin_family = AF_INET;
319 * If we were given a hostname, we use any address for that host.
320 * Otherwise we expect the given name to be an address unless it is
321 * NULL (any address).
323 if (name && name[0]!=0) {
324 WMHost *host = WMGetHostWithName(name);
326 if (!host)
327 return NULL; /* name is not a hostname nor a number and dot adr */
329 name = WMGetHostAddress(host);
330 #ifndef HAVE_INET_ATON
331 if ((socketaddr.sin_addr.s_addr = inet_addr(name)) == INADDR_NONE) {
332 #else
333 if (inet_aton(name, &socketaddr.sin_addr) == 0) {
334 #endif
335 WMReleaseHost(host);
336 return NULL;
338 WMReleaseHost(host);
339 } else {
340 socketaddr.sin_addr.s_addr = htonl(INADDR_ANY);
343 if (!service || service[0]==0) {
344 socketaddr.sin_port = 0;
345 } else if ((sp = getservbyname(service, protocol))==0) {
346 char *endptr;
347 unsigned portNumber;
349 portNumber = strtoul(service, &endptr, 10);
351 if (service[0]!=0 && *endptr==0 && portNumber<65536) {
352 socketaddr.sin_port = htons(portNumber);
353 } else {
354 return NULL;
356 } else {
357 socketaddr.sin_port = sp->s_port;
360 return &socketaddr;
364 static void
365 dummyHandler(int signum)
370 static WMConnection*
371 createConnectionWithSocket(int sock, Bool closeOnRelease)
373 WMConnection *cPtr;
374 struct sigaction sig_action;
376 cPtr = wmalloc(sizeof(WMConnection));
377 wretain(cPtr);
378 memset(cPtr, 0, sizeof(WMConnection));
380 fcntl(sock, F_SETFD, FD_CLOEXEC); /* by default close on exec */
382 cPtr->sock = sock;
383 cPtr->openTimeout.timeout = OpenTimeout;
384 cPtr->openTimeout.handler = NULL;
385 cPtr->sendTimeout.timeout = DefaultTimeout;
386 cPtr->sendTimeout.handler = NULL;
387 cPtr->closeOnRelease = closeOnRelease;
388 cPtr->shutdownOnClose = 1;
389 cPtr->outputQueue =
390 WMCreateArrayWithDestructor(16, (WMFreeDataProc*)WMReleaseData);
391 cPtr->state = WCNotConnected;
392 cPtr->timeoutState = WCTNone;
394 /* ignore dead pipe */
395 if (!SigInitialized) {
396 /* Because POSIX mandates that only signal with handlers are reset
397 * accross an exec*(), we do not want to propagate ignoring SIGPIPEs
398 * to children. Hence the dummy handler. Philippe Troin <phil@fifi.org>
400 sig_action.sa_handler = &dummyHandler;
401 sig_action.sa_flags = SA_RESTART;
402 sigaction(SIGPIPE, &sig_action, NULL);
403 SigInitialized = True;
406 return cPtr;
410 #if 0
411 WMConnection*
412 WMCreateConnectionWithSocket(int sock, Bool closeOnRelease)
414 WMConnection *cPtr;
415 struct sockaddr_in clientname;
416 int size;
417 int n;
419 cPtr = createConnectionWithSocket(sock, closeOnRelease);
420 cPtr->wasNonBlocking = WMIsConnectionNonBlocking(cPtr);
421 cPtr->isNonBlocking = cPtr->wasNonBlocking;
423 /* some way to find out if it is connected, and binded. can't find
424 if it listens though!!!
427 size = sizeof(clientname);
428 n = getpeername(sock, (struct sockaddr*) &clientname, &size);
429 if (n==0) {
430 /* Since we have a peer, it means we are connected */
431 cPtr->state = WCConnected;
432 } else {
433 size = sizeof(clientname);
434 n = getsockname(sock, (struct sockaddr*) &clientname, &size);
435 if (n==0) {
436 /* We don't have a peer, but we are binded to an address.
437 * Assume we are listening on it (we don't know that for sure!)
439 cPtr->state = WCListening;
440 } else {
441 cPtr->state = WCNotConnected;
445 return cPtr;
447 #endif
451 * host is the name on which we want to listen for incoming connections,
452 * and it must be a name of this host, or NULL if we want to listen
453 * on any incoming address.
454 * service is either a service name as present in /etc/services, or the port
455 * number we want to listen on. If NULL, a random port between
456 * 1024 and 65535 will be assigned to us.
457 * protocol is one of "tcp" or "udp". If NULL, "tcp" will be used by default.
458 * currently only "tcp" is supported.
460 WMConnection*
461 WMCreateConnectionAsServerAtAddress(char *host, char *service, char *protocol)
463 WMConnection *cPtr;
464 struct sockaddr_in *socketaddr;
465 socklen_t size;
466 int sock, on;
468 WCErrorCode = 0;
470 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
471 wwarning(_("Bad address-service-protocol combination"));
472 return NULL;
475 /* Create the actual socket */
476 sock = socket(PF_INET, SOCK_STREAM, 0);
477 if (sock<0) {
478 WCErrorCode = errno;
479 return NULL;
483 * Set socket options. We try to make the port reusable and have it
484 * close as fast as possible without waiting in unnecessary wait states
485 * on close.
487 on = 1;
488 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
490 if (bind(sock, (struct sockaddr *)socketaddr, sizeof(*socketaddr)) < 0) {
491 WCErrorCode = errno;
492 close(sock);
493 return NULL;
496 if (listen(sock, 10) < 0) {
497 WCErrorCode = errno;
498 close(sock);
499 return NULL;
502 /* Find out what is the address/service/protocol we get */
503 /* In case some of address/service/protocol were NULL */
504 size = sizeof(*socketaddr);
505 if (getsockname(sock, (struct sockaddr*)socketaddr, &size) < 0) {
506 WCErrorCode = errno;
507 close(sock);
508 return NULL;
511 cPtr = createConnectionWithSocket(sock, True);
512 cPtr->state = WCListening;
513 WMSetConnectionNonBlocking(cPtr, True);
515 setConnectionAddress(cPtr, socketaddr);
517 return cPtr;
521 WMConnection*
522 WMCreateConnectionToAddress(char *host, char *service, char *protocol)
524 WMConnection *cPtr;
525 struct sockaddr_in *socketaddr;
526 int sock;
528 WCErrorCode = 0;
530 wassertrv(service!=NULL && service[0]!=0, NULL);
532 if (host==NULL || host[0]==0)
533 host = "localhost";
535 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
536 wwarning(_("Bad address-service-protocol combination"));
537 return NULL;
540 /* Create the actual socket */
541 sock = socket(PF_INET, SOCK_STREAM, 0);
542 if (sock<0) {
543 WCErrorCode = errno;
544 return NULL;
546 /* make socket blocking while we connect. */
547 setSocketNonBlocking(sock, False);
548 if (connect(sock, (struct sockaddr*)socketaddr, sizeof(*socketaddr)) < 0) {
549 WCErrorCode = errno;
550 close(sock);
551 return NULL;
554 cPtr = createConnectionWithSocket(sock, True);
555 cPtr->state = WCConnected;
556 WMSetConnectionNonBlocking(cPtr, True);
557 setConnectionAddress(cPtr, socketaddr);
559 return cPtr;
563 WMConnection*
564 WMCreateConnectionToAddressAndNotify(char *host, char *service, char *protocol)
566 WMConnection *cPtr;
567 struct sockaddr_in *socketaddr;
568 int sock;
569 Bool isNonBlocking;
571 WCErrorCode = 0;
573 wassertrv(service!=NULL && service[0]!=0, NULL);
575 if (host==NULL || host[0]==0)
576 host = "localhost";
578 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
579 wwarning(_("Bad address-service-protocol combination"));
580 return NULL;
583 /* Create the actual socket */
584 sock = socket(PF_INET, SOCK_STREAM, 0);
585 if (sock<0) {
586 WCErrorCode = errno;
587 return NULL;
589 isNonBlocking = setSocketNonBlocking(sock, True);
590 if (connect(sock, (struct sockaddr*)socketaddr, sizeof(*socketaddr)) < 0) {
591 if (errno!=EINPROGRESS) {
592 WCErrorCode = errno;
593 close(sock);
594 return NULL;
598 cPtr = createConnectionWithSocket(sock, True);
599 cPtr->state = WCInProgress;
600 cPtr->isNonBlocking = isNonBlocking;
602 cPtr->handler.write = WMAddInputHandler(cPtr->sock, WIWriteMask,
603 inputHandler, cPtr);
605 cPtr->openTimeout.handler =
606 WMAddTimerHandler(cPtr->openTimeout.timeout*1000, openTimeout, cPtr);
608 setConnectionAddress(cPtr, socketaddr);
610 return cPtr;
614 static void
615 removeAllHandlers(WMConnection *cPtr)
617 if (cPtr->handler.read)
618 WMDeleteInputHandler(cPtr->handler.read);
619 if (cPtr->handler.write)
620 WMDeleteInputHandler(cPtr->handler.write);
621 if (cPtr->handler.exception)
622 WMDeleteInputHandler(cPtr->handler.exception);
623 if (cPtr->openTimeout.handler)
624 WMDeleteTimerHandler(cPtr->openTimeout.handler);
625 if (cPtr->sendTimeout.handler)
626 WMDeleteTimerHandler(cPtr->sendTimeout.handler);
628 cPtr->handler.read = NULL;
629 cPtr->handler.write = NULL;
630 cPtr->handler.exception = NULL;
631 cPtr->openTimeout.handler = NULL;
632 cPtr->sendTimeout.handler = NULL;
636 void
637 WMDestroyConnection(WMConnection *cPtr)
639 if (cPtr->closeOnRelease && cPtr->sock>=0) {
640 if (cPtr->shutdownOnClose) {
641 shutdown(cPtr->sock, SHUT_RDWR);
643 close(cPtr->sock);
646 removeAllHandlers(cPtr);
647 WMFreeArray(cPtr->outputQueue); /* will also free the items with the destructor */
649 if (cPtr->address) {
650 wfree(cPtr->address);
651 wfree(cPtr->service);
652 wfree(cPtr->protocol);
655 wrelease(cPtr);
659 void
660 WMCloseConnection(WMConnection *cPtr)
662 if (cPtr->sock>=0) {
663 if (cPtr->shutdownOnClose) {
664 shutdown(cPtr->sock, SHUT_RDWR);
666 close(cPtr->sock);
667 cPtr->sock = -1;
670 removeAllHandlers(cPtr);
671 clearOutputQueue(cPtr);
673 cPtr->state = WCClosed;
677 WMConnection*
678 WMAcceptConnection(WMConnection *listener)
680 struct sockaddr_in clientname;
681 socklen_t size;
682 int newSock;
683 WMConnection *newConnection;
685 WCErrorCode = 0;
686 wassertrv(listener && listener->state==WCListening, NULL);
688 size = sizeof(clientname);
689 newSock = accept(listener->sock, (struct sockaddr*) &clientname, &size);
690 if (newSock<0) {
691 WCErrorCode = ((errno!=EAGAIN && errno!=EWOULDBLOCK) ? errno : 0);
692 return NULL;
695 newConnection = createConnectionWithSocket(newSock, True);
696 WMSetConnectionNonBlocking(newConnection, True);
697 newConnection->state = WCConnected;
698 setConnectionAddress(newConnection, &clientname);
700 return newConnection;
704 char*
705 WMGetConnectionAddress(WMConnection *cPtr)
707 return cPtr->address;
711 char*
712 WMGetConnectionService(WMConnection *cPtr)
714 return cPtr->service;
718 char*
719 WMGetConnectionProtocol(WMConnection *cPtr)
721 return cPtr->protocol;
726 WMGetConnectionSocket(WMConnection *cPtr)
728 return cPtr->sock;
732 WMConnectionState
733 WMGetConnectionState(WMConnection *cPtr)
735 return cPtr->state;
739 WMConnectionTimeoutState
740 WMGetConnectionTimeoutState(WMConnection *cPtr)
742 return cPtr->timeoutState;
746 Bool
747 WMEnqueueConnectionData(WMConnection *cPtr, WMData *data)
749 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, False);
750 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, False);
752 if (cPtr->state!=WCConnected)
753 return False;
755 WMAddToArray(cPtr->outputQueue, WMRetainData(data));
756 return True;
761 * Return value:
762 * -1 - not connected or connection died while sending
763 * 0 - couldn't send the data (or part of it). data is saved in a queue
764 * and will be sent when possible. after it is sent the canResumeSending
765 * callback will be called.
766 * 1 - data was succesfully sent
769 WMSendConnectionData(WMConnection *cPtr, WMData *data)
771 int bytes, pos, len;
772 TimeoutData *tPtr = &cPtr->sendTimeout;
773 const unsigned char *dataBytes;
775 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, -1);
776 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, -1);
778 if (cPtr->state!=WCConnected)
779 return -1;
781 /* If we have no data just flush the queue, else try to send data */
782 if (data && WMGetDataLength(data)>0) {
783 WMAddToArray(cPtr->outputQueue, WMRetainData(data));
784 /* If there already was something in queue, and also a write input
785 * handler is established, it means we were unable to send, so
786 * return and let the write handler notify us when we can send.
788 if (WMGetArrayItemCount(cPtr->outputQueue)>1 && cPtr->handler.write)
789 return 0;
792 while (WMGetArrayItemCount(cPtr->outputQueue) > 0) {
793 data = WMGetFromArray(cPtr->outputQueue, 0);
794 dataBytes = (const unsigned char *)WMDataBytes(data);
795 len = WMGetDataLength(data);
796 pos = cPtr->bufPos; /* where we're left last time */
797 while(pos < len) {
798 again:
799 bytes = write(cPtr->sock, dataBytes+pos, len - pos);
800 if(bytes<0) {
801 switch (errno) {
802 case EINTR:
803 goto again;
804 case EWOULDBLOCK:
805 /* save the position where we're left and add a timeout */
806 cPtr->bufPos = pos;
807 if (!tPtr->handler) {
808 tPtr->handler = WMAddTimerHandler(tPtr->timeout*1000,
809 sendTimeout, cPtr);
811 if (!cPtr->handler.write) {
812 cPtr->handler.write =
813 WMAddInputHandler(cPtr->sock, WIWriteMask,
814 inputHandler, cPtr);
816 return 0;
817 default:
818 WCErrorCode = errno;
819 cPtr->state = WCDied;
820 removeAllHandlers(cPtr);
821 if (cPtr->delegate && cPtr->delegate->didDie)
822 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
823 return -1;
826 pos += bytes;
828 WMDeleteFromArray(cPtr->outputQueue, 0);
829 cPtr->bufPos = 0;
830 if (tPtr->handler) {
831 WMDeleteTimerHandler(tPtr->handler);
832 tPtr->handler = NULL;
834 /*if (cPtr->handler.write) {
835 WMDeleteInputHandler(cPtr->handler.write);
836 cPtr->handler.write = NULL;
840 if (cPtr->handler.write) {
841 WMDeleteInputHandler(cPtr->handler.write);
842 cPtr->handler.write = NULL;
845 return 1;
850 * WMGetConnectionAvailableData(connection):
852 * will return a WMData structure containing the available data on the
853 * specified connection. If connection is non-blocking (default) and no data
854 * is available when this function is called, an empty WMData is returned.
856 * If an error occurs while reading or the other side closed connection,
857 * it will return NULL.
858 * Also trying to read from an already died or closed connection is
859 * considered to be an error condition, and will return NULL.
861 WMData*
862 WMGetConnectionAvailableData(WMConnection *cPtr)
864 char buffer[NETBUF_SIZE];
865 int nbytes;
866 WMData *aData;
868 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, NULL);
869 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, NULL);
871 if (cPtr->state!=WCConnected)
872 return NULL;
874 aData = NULL;
876 again:
877 nbytes = read(cPtr->sock, buffer, NETBUF_SIZE);
878 if (nbytes<0) {
879 switch (errno) {
880 case EINTR:
881 goto again;
882 case EWOULDBLOCK:
883 aData = WMCreateDataWithCapacity(0);
884 break;
885 default:
886 WCErrorCode = errno;
887 cPtr->state = WCDied;
888 removeAllHandlers(cPtr);
889 if (cPtr->delegate && cPtr->delegate->didDie)
890 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
891 break;
893 } else if (nbytes==0) { /* the other side has closed connection */
894 cPtr->state = WCClosed;
895 removeAllHandlers(cPtr);
896 if (cPtr->delegate && cPtr->delegate->didDie)
897 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
898 } else {
899 aData = WMCreateDataWithBytes(buffer, nbytes);
902 return aData;
906 void
907 WMSetConnectionDelegate(WMConnection *cPtr, ConnectionDelegate *delegate)
909 wassertr(cPtr->sock >= 0);
910 /* Don't try to set the delegate multiple times */
911 wassertr(cPtr->delegate == NULL);
913 cPtr->delegate = delegate;
914 if (delegate && delegate->didReceiveInput && !cPtr->handler.read)
915 cPtr->handler.read = WMAddInputHandler(cPtr->sock, WIReadMask,
916 inputHandler, cPtr);
917 if (delegate && delegate->didCatchException && !cPtr->handler.exception)
918 cPtr->handler.exception = WMAddInputHandler(cPtr->sock, WIExceptMask,
919 inputHandler, cPtr);
923 #if 0
924 Bool
925 WMIsConnectionNonBlocking(WMConnection *cPtr)
927 #if 1
928 int state;
930 state = fcntl(cPtr->sock, F_GETFL, 0);
932 if (state < 0) {
933 /* If we can't use fcntl on socket, this probably also means we could
934 * not use fcntl to set non-blocking mode, and since a socket defaults
935 * to blocking when created, return False as the best assumption */
936 return False;
939 return ((state & NONBLOCK_OPT)!=0);
940 #else
941 return cPtr->isNonBlocking;
942 #endif
944 #endif
947 Bool
948 WMSetConnectionNonBlocking(WMConnection *cPtr, Bool flag)
950 wassertrv(cPtr!=NULL && cPtr->sock>=0, False);
952 flag = ((flag==0) ? 0 : 1);
954 if (cPtr->isNonBlocking == flag)
955 return True;
957 if (setSocketNonBlocking(cPtr->sock, flag)==True) {
958 cPtr->isNonBlocking = flag;
959 return True;
962 return False;
966 Bool
967 WMSetConnectionCloseOnExec(WMConnection *cPtr, Bool flag)
969 wassertrv(cPtr!=NULL && cPtr->sock>=0, False);
971 if (fcntl(cPtr->sock, F_SETFD, ((flag==0) ? 0 : FD_CLOEXEC)) < 0) {
972 return False;
975 return True;
979 void
980 WMSetConnectionShutdownOnClose(WMConnection *cPtr, Bool flag)
982 cPtr->shutdownOnClose = ((flag==0) ? 0 : 1);
986 void*
987 WMGetConnectionClientData(WMConnection *cPtr)
989 return cPtr->clientData;
993 void
994 WMSetConnectionClientData(WMConnection *cPtr, void *data)
996 cPtr->clientData = data;
1000 unsigned int
1001 WMGetConnectionFlags(WMConnection *cPtr)
1003 return cPtr->uflags;
1007 void
1008 WMSetConnectionFlags(WMConnection *cPtr, unsigned int flags)
1010 cPtr->uflags = flags;
1014 WMArray*
1015 WMGetConnectionUnsentData(WMConnection *cPtr)
1017 return cPtr->outputQueue;
1021 void
1022 WMSetConnectionDefaultTimeout(unsigned int timeout)
1024 if (timeout == 0) {
1025 DefaultTimeout = DEF_TIMEOUT;
1026 } else {
1027 DefaultTimeout = timeout;
1032 void
1033 WMSetConnectionOpenTimeout(unsigned int timeout)
1035 if (timeout == 0) {
1036 OpenTimeout = DefaultTimeout;
1037 } else {
1038 OpenTimeout = timeout;
1043 void
1044 WMSetConnectionSendTimeout(WMConnection *cPtr, unsigned int timeout)
1046 if (timeout == 0) {
1047 cPtr->sendTimeout.timeout = DefaultTimeout;
1048 } else {
1049 cPtr->sendTimeout.timeout = timeout;