Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / connection.c
blobcfbc0937e68b7e4901cbbeea4a7f878d4f13f9db
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.
22 * TODO:
23 * - decide if we want to support connections with external sockets, else
24 * clean up the structure of the unneeded members.
25 * - decide what to do with all wwarning() calls that are still there.
29 #include "wconfig.h"
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <stdarg.h>
37 #include <errno.h>
38 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41 #include <netdb.h>
42 #include <signal.h>
43 #ifdef __FreeBSD__
44 #include <sys/signal.h>
45 #endif
47 #include "WINGs.h"
49 /* Some older systems does not define this (linux libc5, maybe others too) */
50 #ifndef SHUT_RDWR
51 # define SHUT_RDWR 2
52 #endif
54 /* For SunOS */
55 #ifndef SA_RESTART
56 # define SA_RESTART 0
57 #endif
59 /* For Solaris */
60 #ifndef INADDR_NONE
61 # define INADDR_NONE -1
62 #endif
64 /* Stuff for setting the sockets into non-blocking mode. */
66 #ifdef __POSIX_SOURCE
67 # define NONBLOCK_OPT O_NONBLOCK
68 #else
69 # define NONBLOCK_OPT FNDELAY
70 #endif
73 #define NONBLOCK_OPT O_NONBLOCK
75 #define NETBUF_SIZE 4096
77 #define DEF_TIMEOUT 600 /* 600 seconds == 10 minutes */
79 int WCErrorCode = 0;
81 static Bool SigInitialized = False;
83 static unsigned int DefaultTimeout = DEF_TIMEOUT;
84 static unsigned int OpenTimeout = DEF_TIMEOUT;
86 typedef struct TimeoutData {
87 unsigned timeout;
88 WMHandlerID *handler;
89 } TimeoutData;
91 typedef struct W_Connection {
92 int sock; /* the socket we speak through */
94 struct {
95 WMHandlerID *read; /* the input read handler */
96 WMHandlerID *write; /* the input write handler */
97 WMHandlerID *exception; /* the input exception handler */
98 } handler;
100 ConnectionDelegate *delegate; /* client delegates */
101 void *clientData; /* client data */
102 unsigned int uflags; /* flags for the client */
104 WMArray *outputQueue;
105 unsigned bufPos;
107 TimeoutData sendTimeout;
108 TimeoutData openTimeout;
110 WMConnectionState state;
111 WMConnectionTimeoutState timeoutState;
113 char *address;
114 char *service;
115 char *protocol;
117 Bool closeOnRelease;
118 Bool shutdownOnClose;
119 Bool wasNonBlocking;
120 Bool isNonBlocking;
122 } W_Connection;
124 static void clearOutputQueue(WMConnection * cPtr)
126 cPtr->bufPos = 0;
127 WMEmptyArray(cPtr->outputQueue);
130 static void openTimeout(void *cdata)
132 WMConnection *cPtr = (WMConnection *) cdata;
134 cPtr->openTimeout.handler = NULL;
135 if (cPtr->handler.write) {
136 WMDeleteInputHandler(cPtr->handler.write);
137 cPtr->handler.write = NULL;
139 if (cPtr->state != WCConnected) {
140 cPtr->state = WCTimedOut;
141 cPtr->timeoutState = WCTWhileOpening;
142 if (cPtr->delegate && cPtr->delegate->didTimeout) {
143 (*cPtr->delegate->didTimeout) (cPtr->delegate, cPtr);
144 } else {
145 WMCloseConnection(cPtr);
146 cPtr->state = WCTimedOut; /* the above set state to WCClosed */
151 static void sendTimeout(void *cdata)
153 WMConnection *cPtr = (WMConnection *) cdata;
155 cPtr->sendTimeout.handler = NULL;
156 if (cPtr->handler.write) {
157 WMDeleteInputHandler(cPtr->handler.write);
158 cPtr->handler.write = NULL;
160 if (WMGetArrayItemCount(cPtr->outputQueue) > 0) {
161 clearOutputQueue(cPtr);
162 cPtr->state = WCTimedOut;
163 cPtr->timeoutState = WCTWhileSending;
164 /* // should we close it no matter what (after calling the didTimeout
165 // delegate)? -Dan */
166 if (cPtr->delegate && cPtr->delegate->didTimeout) {
167 (*cPtr->delegate->didTimeout) (cPtr->delegate, cPtr);
168 } else {
169 WMCloseConnection(cPtr);
170 cPtr->state = WCTimedOut; /* the above set state to WCClosed */
175 static void inputHandler(int fd, int mask, void *clientData)
177 WMConnection *cPtr = (WMConnection *) clientData;
179 if (cPtr->state == WCClosed || cPtr->state == WCDied)
180 return;
182 if ((mask & WIWriteMask)) {
183 int result;
185 if (cPtr->state == WCInProgress) {
186 Bool failed;
187 socklen_t len = sizeof(result);
189 WCErrorCode = 0;
190 if (getsockopt(cPtr->sock, SOL_SOCKET, SO_ERROR,
191 (void *)&result, &len) == 0 && result != 0) {
192 cPtr->state = WCFailed;
193 WCErrorCode = result;
194 failed = True;
195 /* should call wsyserrorwithcode(result, ...) here? */
196 } else {
197 cPtr->state = WCConnected;
198 failed = False;
201 if (cPtr->handler.write) {
202 WMDeleteInputHandler(cPtr->handler.write);
203 cPtr->handler.write = NULL;
206 if (cPtr->openTimeout.handler) {
207 WMDeleteTimerHandler(cPtr->openTimeout.handler);
208 cPtr->openTimeout.handler = NULL;
211 if (cPtr->delegate && cPtr->delegate->didInitialize)
212 (*cPtr->delegate->didInitialize) (cPtr->delegate, cPtr);
214 /* we use failed and not cPtr->state here, because cPtr may be
215 * destroyed by the delegate called above if the connection failed
217 if (failed)
218 return;
219 } else if (cPtr->state == WCConnected) {
220 result = WMFlushConnection(cPtr);
221 if (result > 0 && cPtr->delegate && cPtr->delegate->canResumeSending) {
222 (*cPtr->delegate->canResumeSending) (cPtr->delegate, cPtr);
227 if (!cPtr->delegate)
228 return;
230 /* if the connection died, may get destroyed in the delegate, so retain */
231 wretain(cPtr);
233 if ((mask & WIReadMask) && cPtr->delegate->didReceiveInput)
234 (*cPtr->delegate->didReceiveInput) (cPtr->delegate, cPtr);
236 if ((mask & WIExceptMask) && cPtr->delegate->didCatchException)
237 (*cPtr->delegate->didCatchException) (cPtr->delegate, cPtr);
239 wrelease(cPtr);
242 static Bool setSocketNonBlocking(int sock, Bool flag)
244 int state;
245 Bool isNonBlock;
247 state = fcntl(sock, F_GETFL, 0);
249 if (state < 0) {
250 /* set WCErrorCode here? -Dan */
251 return False;
254 isNonBlock = (state & NONBLOCK_OPT) != 0;
256 if (flag) {
257 if (isNonBlock)
258 return True;
259 state |= NONBLOCK_OPT;
260 } else {
261 if (!isNonBlock)
262 return True;
263 state &= ~NONBLOCK_OPT;
266 if (fcntl(sock, F_SETFL, state) < 0) {
267 /* set WCErrorCode here? -Dan */
268 return False;
271 return True;
274 static void setConnectionAddress(WMConnection * cPtr, struct sockaddr_in *socketaddr)
276 wassertr(cPtr->address == NULL);
278 cPtr->address = wstrdup(inet_ntoa(socketaddr->sin_addr));
279 cPtr->service = wmalloc(16);
280 sprintf(cPtr->service, "%hu", ntohs(socketaddr->sin_port));
281 cPtr->protocol = wstrdup("tcp");
284 static struct sockaddr_in *getSocketAddress(char *name, char *service, char *protocol)
286 static struct sockaddr_in socketaddr;
287 struct servent *sp;
289 if (!protocol || protocol[0] == 0)
290 protocol = "tcp";
292 memset(&socketaddr, 0, sizeof(struct sockaddr_in));
293 socketaddr.sin_family = AF_INET;
296 * If we were given a hostname, we use any address for that host.
297 * Otherwise we expect the given name to be an address unless it is
298 * NULL (any address).
300 if (name && name[0] != 0) {
301 WMHost *host = WMGetHostWithName(name);
303 if (!host)
304 return NULL; /* name is not a hostname nor a number and dot adr */
306 name = WMGetHostAddress(host);
307 #ifndef HAVE_INET_ATON
308 if ((socketaddr.sin_addr.s_addr = inet_addr(name)) == INADDR_NONE) {
309 #else
310 if (inet_aton(name, &socketaddr.sin_addr) == 0) {
311 #endif
312 WMReleaseHost(host);
313 return NULL;
315 WMReleaseHost(host);
316 } else {
317 socketaddr.sin_addr.s_addr = htonl(INADDR_ANY);
320 if (!service || service[0] == 0) {
321 socketaddr.sin_port = 0;
322 } else if ((sp = getservbyname(service, protocol)) == 0) {
323 char *endptr;
324 unsigned portNumber;
326 portNumber = strtoul(service, &endptr, 10);
328 if (service[0] != 0 && *endptr == 0 && portNumber < 65536) {
329 socketaddr.sin_port = htons(portNumber);
330 } else {
331 return NULL;
333 } else {
334 socketaddr.sin_port = sp->s_port;
337 return &socketaddr;
340 static void dummyHandler(int signum)
344 static WMConnection *createConnectionWithSocket(int sock, Bool closeOnRelease)
346 WMConnection *cPtr;
347 struct sigaction sig_action;
349 cPtr = wmalloc(sizeof(WMConnection));
350 wretain(cPtr);
351 memset(cPtr, 0, sizeof(WMConnection));
353 fcntl(sock, F_SETFD, FD_CLOEXEC); /* by default close on exec */
355 cPtr->sock = sock;
356 cPtr->openTimeout.timeout = OpenTimeout;
357 cPtr->openTimeout.handler = NULL;
358 cPtr->sendTimeout.timeout = DefaultTimeout;
359 cPtr->sendTimeout.handler = NULL;
360 cPtr->closeOnRelease = closeOnRelease;
361 cPtr->shutdownOnClose = 1;
362 cPtr->outputQueue = WMCreateArrayWithDestructor(16, (WMFreeDataProc *) WMReleaseData);
363 cPtr->state = WCNotConnected;
364 cPtr->timeoutState = WCTNone;
366 /* ignore dead pipe */
367 if (!SigInitialized) {
368 /* Because POSIX mandates that only signal with handlers are reset
369 * accross an exec*(), we do not want to propagate ignoring SIGPIPEs
370 * to children. Hence the dummy handler. Philippe Troin <phil@fifi.org>
372 sig_action.sa_handler = &dummyHandler;
373 sig_action.sa_flags = SA_RESTART;
374 sigaction(SIGPIPE, &sig_action, NULL);
375 SigInitialized = True;
378 return cPtr;
381 #if 0
382 WMConnection *WMCreateConnectionWithSocket(int sock, Bool closeOnRelease)
384 WMConnection *cPtr;
385 struct sockaddr_in clientname;
386 int size;
387 int n;
389 cPtr = createConnectionWithSocket(sock, closeOnRelease);
390 cPtr->wasNonBlocking = WMIsConnectionNonBlocking(cPtr);
391 cPtr->isNonBlocking = cPtr->wasNonBlocking;
393 /* some way to find out if it is connected, and binded. can't find
394 if it listens though!!!
397 size = sizeof(clientname);
398 n = getpeername(sock, (struct sockaddr *)&clientname, &size);
399 if (n == 0) {
400 /* Since we have a peer, it means we are connected */
401 cPtr->state = WCConnected;
402 } else {
403 size = sizeof(clientname);
404 n = getsockname(sock, (struct sockaddr *)&clientname, &size);
405 if (n == 0) {
406 /* We don't have a peer, but we are binded to an address.
407 * Assume we are listening on it (we don't know that for sure!)
409 cPtr->state = WCListening;
410 } else {
411 cPtr->state = WCNotConnected;
415 return cPtr;
417 #endif
420 * host is the name on which we want to listen for incoming connections,
421 * and it must be a name of this host, or NULL if we want to listen
422 * on any incoming address.
423 * service is either a service name as present in /etc/services, or the port
424 * number we want to listen on. If NULL, a random port between
425 * 1024 and 65535 will be assigned to us.
426 * protocol is one of "tcp" or "udp". If NULL, "tcp" will be used by default.
427 * currently only "tcp" is supported.
429 WMConnection *WMCreateConnectionAsServerAtAddress(char *host, char *service, char *protocol)
431 WMConnection *cPtr;
432 struct sockaddr_in *socketaddr;
433 socklen_t size;
434 int sock, on;
436 WCErrorCode = 0;
438 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
439 wwarning(_("Bad address-service-protocol combination"));
440 return NULL;
443 /* Create the actual socket */
444 sock = socket(PF_INET, SOCK_STREAM, 0);
445 if (sock < 0) {
446 WCErrorCode = errno;
447 return NULL;
451 * Set socket options. We try to make the port reusable and have it
452 * close as fast as possible without waiting in unnecessary wait states
453 * on close.
455 on = 1;
456 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
458 if (bind(sock, (struct sockaddr *)socketaddr, sizeof(*socketaddr)) < 0) {
459 WCErrorCode = errno;
460 close(sock);
461 return NULL;
464 if (listen(sock, 10) < 0) {
465 WCErrorCode = errno;
466 close(sock);
467 return NULL;
470 /* Find out what is the address/service/protocol we get */
471 /* In case some of address/service/protocol were NULL */
472 size = sizeof(*socketaddr);
473 if (getsockname(sock, (struct sockaddr *)socketaddr, &size) < 0) {
474 WCErrorCode = errno;
475 close(sock);
476 return NULL;
479 cPtr = createConnectionWithSocket(sock, True);
480 cPtr->state = WCListening;
481 WMSetConnectionNonBlocking(cPtr, True);
483 setConnectionAddress(cPtr, socketaddr);
485 return cPtr;
488 WMConnection *WMCreateConnectionToAddress(char *host, char *service, char *protocol)
490 WMConnection *cPtr;
491 struct sockaddr_in *socketaddr;
492 int sock;
494 WCErrorCode = 0;
496 wassertrv(service != NULL && service[0] != 0, NULL);
498 if (host == NULL || host[0] == 0)
499 host = "localhost";
501 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
502 wwarning(_("Bad address-service-protocol combination"));
503 return NULL;
506 /* Create the actual socket */
507 sock = socket(PF_INET, SOCK_STREAM, 0);
508 if (sock < 0) {
509 WCErrorCode = errno;
510 return NULL;
512 /* make socket blocking while we connect. */
513 setSocketNonBlocking(sock, False);
514 if (connect(sock, (struct sockaddr *)socketaddr, sizeof(*socketaddr)) < 0) {
515 WCErrorCode = errno;
516 close(sock);
517 return NULL;
520 cPtr = createConnectionWithSocket(sock, True);
521 cPtr->state = WCConnected;
522 WMSetConnectionNonBlocking(cPtr, True);
523 setConnectionAddress(cPtr, socketaddr);
525 return cPtr;
528 WMConnection *WMCreateConnectionToAddressAndNotify(char *host, char *service, char *protocol)
530 WMConnection *cPtr;
531 struct sockaddr_in *socketaddr;
532 int sock;
533 Bool isNonBlocking;
535 WCErrorCode = 0;
537 wassertrv(service != NULL && service[0] != 0, NULL);
539 if (host == NULL || host[0] == 0)
540 host = "localhost";
542 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
543 wwarning(_("Bad address-service-protocol combination"));
544 return NULL;
547 /* Create the actual socket */
548 sock = socket(PF_INET, SOCK_STREAM, 0);
549 if (sock < 0) {
550 WCErrorCode = errno;
551 return NULL;
553 isNonBlocking = setSocketNonBlocking(sock, True);
554 if (connect(sock, (struct sockaddr *)socketaddr, sizeof(*socketaddr)) < 0) {
555 if (errno != EINPROGRESS) {
556 WCErrorCode = errno;
557 close(sock);
558 return NULL;
562 cPtr = createConnectionWithSocket(sock, True);
563 cPtr->state = WCInProgress;
564 cPtr->isNonBlocking = isNonBlocking;
566 cPtr->handler.write = WMAddInputHandler(cPtr->sock, WIWriteMask, inputHandler, cPtr);
568 cPtr->openTimeout.handler = WMAddTimerHandler(cPtr->openTimeout.timeout * 1000, openTimeout, cPtr);
570 setConnectionAddress(cPtr, socketaddr);
572 return cPtr;
575 static void removeAllHandlers(WMConnection * cPtr)
577 if (cPtr->handler.read)
578 WMDeleteInputHandler(cPtr->handler.read);
579 if (cPtr->handler.write)
580 WMDeleteInputHandler(cPtr->handler.write);
581 if (cPtr->handler.exception)
582 WMDeleteInputHandler(cPtr->handler.exception);
583 if (cPtr->openTimeout.handler)
584 WMDeleteTimerHandler(cPtr->openTimeout.handler);
585 if (cPtr->sendTimeout.handler)
586 WMDeleteTimerHandler(cPtr->sendTimeout.handler);
588 cPtr->handler.read = NULL;
589 cPtr->handler.write = NULL;
590 cPtr->handler.exception = NULL;
591 cPtr->openTimeout.handler = NULL;
592 cPtr->sendTimeout.handler = NULL;
595 void WMDestroyConnection(WMConnection * cPtr)
597 if (cPtr->closeOnRelease && cPtr->sock >= 0) {
598 if (cPtr->shutdownOnClose) {
599 shutdown(cPtr->sock, SHUT_RDWR);
601 close(cPtr->sock);
604 removeAllHandlers(cPtr);
605 WMFreeArray(cPtr->outputQueue); /* will also free the items with the destructor */
607 if (cPtr->address) {
608 wfree(cPtr->address);
609 wfree(cPtr->service);
610 wfree(cPtr->protocol);
613 wrelease(cPtr);
616 void WMCloseConnection(WMConnection * cPtr)
618 if (cPtr->sock >= 0) {
619 if (cPtr->shutdownOnClose) {
620 shutdown(cPtr->sock, SHUT_RDWR);
622 close(cPtr->sock);
623 cPtr->sock = -1;
626 removeAllHandlers(cPtr);
627 clearOutputQueue(cPtr);
629 cPtr->state = WCClosed;
632 WMConnection *WMAcceptConnection(WMConnection * listener)
634 struct sockaddr_in clientname;
635 socklen_t size;
636 int newSock;
637 WMConnection *newConnection;
639 WCErrorCode = 0;
640 wassertrv(listener && listener->state == WCListening, NULL);
642 size = sizeof(clientname);
643 newSock = accept(listener->sock, (struct sockaddr *)&clientname, &size);
644 if (newSock < 0) {
645 WCErrorCode = ((errno != EAGAIN && errno != EWOULDBLOCK) ? errno : 0);
646 return NULL;
649 newConnection = createConnectionWithSocket(newSock, True);
650 WMSetConnectionNonBlocking(newConnection, True);
651 newConnection->state = WCConnected;
652 setConnectionAddress(newConnection, &clientname);
654 return newConnection;
657 char *WMGetConnectionAddress(WMConnection * cPtr)
659 return cPtr->address;
662 char *WMGetConnectionService(WMConnection * cPtr)
664 return cPtr->service;
667 char *WMGetConnectionProtocol(WMConnection * cPtr)
669 return cPtr->protocol;
672 int WMGetConnectionSocket(WMConnection * cPtr)
674 return cPtr->sock;
677 WMConnectionState WMGetConnectionState(WMConnection * cPtr)
679 return cPtr->state;
682 WMConnectionTimeoutState WMGetConnectionTimeoutState(WMConnection * cPtr)
684 return cPtr->timeoutState;
687 Bool WMEnqueueConnectionData(WMConnection * cPtr, WMData * data)
689 wassertrv(cPtr->state != WCNotConnected && cPtr->state != WCListening, False);
690 wassertrv(cPtr->state != WCInProgress && cPtr->state != WCFailed, False);
692 if (cPtr->state != WCConnected)
693 return False;
695 WMAddToArray(cPtr->outputQueue, WMRetainData(data));
696 return True;
700 * Return value:
701 * -1 - not connected or connection died while sending
702 * 0 - couldn't send the data (or part of it). data is saved in a queue
703 * and will be sent when possible. after it is sent the canResumeSending
704 * callback will be called.
705 * 1 - data was succesfully sent
707 int WMSendConnectionData(WMConnection * cPtr, WMData * data)
709 int bytes, pos, len;
710 TimeoutData *tPtr = &cPtr->sendTimeout;
711 const unsigned char *dataBytes;
713 wassertrv(cPtr->state != WCNotConnected && cPtr->state != WCListening, -1);
714 wassertrv(cPtr->state != WCInProgress && cPtr->state != WCFailed, -1);
716 if (cPtr->state != WCConnected)
717 return -1;
719 /* If we have no data just flush the queue, else try to send data */
720 if (data && WMGetDataLength(data) > 0) {
721 WMAddToArray(cPtr->outputQueue, WMRetainData(data));
722 /* If there already was something in queue, and also a write input
723 * handler is established, it means we were unable to send, so
724 * return and let the write handler notify us when we can send.
726 if (WMGetArrayItemCount(cPtr->outputQueue) > 1 && cPtr->handler.write)
727 return 0;
730 while (WMGetArrayItemCount(cPtr->outputQueue) > 0) {
731 data = WMGetFromArray(cPtr->outputQueue, 0);
732 dataBytes = (const unsigned char *)WMDataBytes(data);
733 len = WMGetDataLength(data);
734 pos = cPtr->bufPos; /* where we're left last time */
735 while (pos < len) {
736 again:
737 bytes = write(cPtr->sock, dataBytes + pos, len - pos);
738 if (bytes < 0) {
739 switch (errno) {
740 case EINTR:
741 goto again;
742 case EWOULDBLOCK:
743 /* save the position where we're left and add a timeout */
744 cPtr->bufPos = pos;
745 if (!tPtr->handler) {
746 tPtr->handler = WMAddTimerHandler(tPtr->timeout * 1000,
747 sendTimeout, cPtr);
749 if (!cPtr->handler.write) {
750 cPtr->handler.write =
751 WMAddInputHandler(cPtr->sock, WIWriteMask, inputHandler, cPtr);
753 return 0;
754 default:
755 WCErrorCode = errno;
756 cPtr->state = WCDied;
757 removeAllHandlers(cPtr);
758 if (cPtr->delegate && cPtr->delegate->didDie)
759 (*cPtr->delegate->didDie) (cPtr->delegate, cPtr);
760 return -1;
763 pos += bytes;
765 WMDeleteFromArray(cPtr->outputQueue, 0);
766 cPtr->bufPos = 0;
767 if (tPtr->handler) {
768 WMDeleteTimerHandler(tPtr->handler);
769 tPtr->handler = NULL;
771 /*if (cPtr->handler.write) {
772 WMDeleteInputHandler(cPtr->handler.write);
773 cPtr->handler.write = NULL;
774 } */
777 if (cPtr->handler.write) {
778 WMDeleteInputHandler(cPtr->handler.write);
779 cPtr->handler.write = NULL;
782 return 1;
786 * WMGetConnectionAvailableData(connection):
788 * will return a WMData structure containing the available data on the
789 * specified connection. If connection is non-blocking (default) and no data
790 * is available when this function is called, an empty WMData is returned.
792 * If an error occurs while reading or the other side closed connection,
793 * it will return NULL.
794 * Also trying to read from an already died or closed connection is
795 * considered to be an error condition, and will return NULL.
797 WMData *WMGetConnectionAvailableData(WMConnection * cPtr)
799 char buffer[NETBUF_SIZE];
800 int nbytes;
801 WMData *aData;
803 wassertrv(cPtr->state != WCNotConnected && cPtr->state != WCListening, NULL);
804 wassertrv(cPtr->state != WCInProgress && cPtr->state != WCFailed, NULL);
806 if (cPtr->state != WCConnected)
807 return NULL;
809 aData = NULL;
811 again:
812 nbytes = read(cPtr->sock, buffer, NETBUF_SIZE);
813 if (nbytes < 0) {
814 switch (errno) {
815 case EINTR:
816 goto again;
817 case EWOULDBLOCK:
818 aData = WMCreateDataWithCapacity(0);
819 break;
820 default:
821 WCErrorCode = errno;
822 cPtr->state = WCDied;
823 removeAllHandlers(cPtr);
824 if (cPtr->delegate && cPtr->delegate->didDie)
825 (*cPtr->delegate->didDie) (cPtr->delegate, cPtr);
826 break;
828 } else if (nbytes == 0) { /* the other side has closed connection */
829 cPtr->state = WCClosed;
830 removeAllHandlers(cPtr);
831 if (cPtr->delegate && cPtr->delegate->didDie)
832 (*cPtr->delegate->didDie) (cPtr->delegate, cPtr);
833 } else {
834 aData = WMCreateDataWithBytes(buffer, nbytes);
837 return aData;
840 void WMSetConnectionDelegate(WMConnection * cPtr, ConnectionDelegate * delegate)
842 wassertr(cPtr->sock >= 0);
843 /* Don't try to set the delegate multiple times */
844 wassertr(cPtr->delegate == NULL);
846 cPtr->delegate = delegate;
847 if (delegate && delegate->didReceiveInput && !cPtr->handler.read)
848 cPtr->handler.read = WMAddInputHandler(cPtr->sock, WIReadMask, inputHandler, cPtr);
849 if (delegate && delegate->didCatchException && !cPtr->handler.exception)
850 cPtr->handler.exception = WMAddInputHandler(cPtr->sock, WIExceptMask, inputHandler, cPtr);
853 #if 0
854 Bool WMIsConnectionNonBlocking(WMConnection * cPtr)
856 #if 1
857 int state;
859 state = fcntl(cPtr->sock, F_GETFL, 0);
861 if (state < 0) {
862 /* If we can't use fcntl on socket, this probably also means we could
863 * not use fcntl to set non-blocking mode, and since a socket defaults
864 * to blocking when created, return False as the best assumption */
865 return False;
868 return ((state & NONBLOCK_OPT) != 0);
869 #else
870 return cPtr->isNonBlocking;
871 #endif
873 #endif
875 Bool WMSetConnectionNonBlocking(WMConnection * cPtr, Bool flag)
877 wassertrv(cPtr != NULL && cPtr->sock >= 0, False);
879 flag = ((flag == 0) ? 0 : 1);
881 if (cPtr->isNonBlocking == flag)
882 return True;
884 if (setSocketNonBlocking(cPtr->sock, flag) == True) {
885 cPtr->isNonBlocking = flag;
886 return True;
889 return False;
892 Bool WMSetConnectionCloseOnExec(WMConnection * cPtr, Bool flag)
894 wassertrv(cPtr != NULL && cPtr->sock >= 0, False);
896 if (fcntl(cPtr->sock, F_SETFD, ((flag == 0) ? 0 : FD_CLOEXEC)) < 0) {
897 return False;
900 return True;
903 void WMSetConnectionShutdownOnClose(WMConnection * cPtr, Bool flag)
905 cPtr->shutdownOnClose = ((flag == 0) ? 0 : 1);
908 void *WMGetConnectionClientData(WMConnection * cPtr)
910 return cPtr->clientData;
913 void WMSetConnectionClientData(WMConnection * cPtr, void *data)
915 cPtr->clientData = data;
918 unsigned int WMGetConnectionFlags(WMConnection * cPtr)
920 return cPtr->uflags;
923 void WMSetConnectionFlags(WMConnection * cPtr, unsigned int flags)
925 cPtr->uflags = flags;
928 WMArray *WMGetConnectionUnsentData(WMConnection * cPtr)
930 return cPtr->outputQueue;
933 void WMSetConnectionDefaultTimeout(unsigned int timeout)
935 if (timeout == 0) {
936 DefaultTimeout = DEF_TIMEOUT;
937 } else {
938 DefaultTimeout = timeout;
942 void WMSetConnectionOpenTimeout(unsigned int timeout)
944 if (timeout == 0) {
945 OpenTimeout = DefaultTimeout;
946 } else {
947 OpenTimeout = timeout;
951 void WMSetConnectionSendTimeout(WMConnection * cPtr, unsigned int timeout)
953 if (timeout == 0) {
954 cPtr->sendTimeout.timeout = DefaultTimeout;
955 } else {
956 cPtr->sendTimeout.timeout = timeout;