Bug fix in the networking code
[wmaker-crm.git] / WINGs / connection.c
blob941ed98cbdb34eb54a8df7d999fdb84f86d49097
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.
30 #include "../src/config.h"
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <stdarg.h>
38 #include <errno.h>
39 #include <sys/socket.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
42 #include <netdb.h>
43 #include <signal.h>
44 #ifdef __FreeBSD__
45 #include <sys/signal.h>
46 #endif
48 #include "WINGs.h"
51 /* Some older systems does not define this (linux libc5, maybe others too) */
52 #ifndef SHUT_RDWR
53 # define SHUT_RDWR 2
54 #endif
56 /* for SunOS */
57 #ifndef SA_RESTART
58 # define SA_RESTART 0
59 #endif
61 /* For some Solaris systems */
62 #if !defined(HAVE_INET_ATON) && !defined(INADDR_NONE)
63 # define INADDR_NONE (-1)
64 #endif
66 /* Stuff for setting the sockets into non-blocking mode. */
67 /*#ifdef __POSIX_SOURCE
68 # define NONBLOCK_OPT O_NONBLOCK
69 #else
70 # define NONBLOCK_OPT FNDELAY
71 #endif*/
73 #define NONBLOCK_OPT O_NONBLOCK
75 #define NETBUF_SIZE 4096
77 #define DEF_TIMEOUT 600 /* 600 seconds == 10 minutes */
80 int WCErrorCode = 0;
84 static Bool SigInitialized = False;
88 typedef struct TimeoutData {
89 unsigned timeout;
90 WMHandlerID *handler;
91 } TimeoutData;
95 typedef struct W_Connection {
96 int sock; /* the socket we speak through */
98 struct {
99 WMHandlerID *read; /* the input read handler */
100 WMHandlerID *write; /* the input write handler */
101 WMHandlerID *exception; /* the input exception handler */
102 } handler;
104 ConnectionDelegate *delegate; /* client delegates */
105 void *clientData; /* client data */
106 unsigned int uflags; /* flags for the client */
108 WMBag *outputQueue;
109 unsigned bufPos;
111 TimeoutData sendTimeout;
113 WMConnectionState state;
115 char *address;
116 char *service;
117 char *protocol;
119 Bool closeOnRelease;
120 Bool wasNonBlocking;
121 Bool isNonBlocking;
123 } W_Connection;
128 static void
129 clearOutputQueue(WMConnection *cPtr) /*FOLD00*/
131 int i;
133 cPtr->bufPos = 0;
135 for (i=0; i<WMGetBagItemCount(cPtr->outputQueue); i++)
136 WMReleaseData(WMGetFromBag(cPtr->outputQueue, i));
138 WMEmptyBag(cPtr->outputQueue);
142 static void
143 sendTimeout(void *cdata) /*FOLD00*/
145 WMConnection *cPtr = (WMConnection*) cdata;
146 TimeoutData *tPtr = &cPtr->sendTimeout;
148 tPtr->handler = NULL;
149 if (cPtr->handler.write) {
150 WMDeleteInputHandler(cPtr->handler.write);
151 cPtr->handler.write = NULL;
153 if (WMGetBagItemCount(cPtr->outputQueue)>0) {
154 clearOutputQueue(cPtr);
155 if (cPtr->delegate && cPtr->delegate->didTimeout)
156 (*cPtr->delegate->didTimeout)(cPtr->delegate, cPtr);
161 static void
162 inputHandler(int fd, int mask, void *clientData) /*FOLD00*/
164 WMConnection *cPtr = (WMConnection*)clientData;
166 if (cPtr->state==WCClosed || cPtr->state==WCDied)
167 return;
169 if ((mask & WIWriteMask)) {
170 if (cPtr->state == WCInProgress) {
171 int result;
172 int len = sizeof(result);
174 if (getsockopt(cPtr->sock, SOL_SOCKET, SO_ERROR,
175 (void*)&result, &len) == 0 && result != 0) {
176 cPtr->state = WCFailed;
177 WCErrorCode = result;
178 /* should call wsyserrorwithcode(result, ...) here? */
179 } else {
180 cPtr->state = WCConnected;
183 if (cPtr->handler.write) {
184 WMDeleteInputHandler(cPtr->handler.write);
185 cPtr->handler.write = NULL;
188 if (cPtr->delegate && cPtr->delegate->didInitialize)
189 (*cPtr->delegate->didInitialize)(cPtr->delegate, cPtr);
191 if (cPtr->state == WCFailed)
192 return;
193 } else if (cPtr->state == WCConnected) {
194 WMFlushConnection(cPtr);
198 if (!cPtr->delegate)
199 return;
201 /* if the connection died, may get destroyed in the delegate, so retain */
202 wretain(cPtr);
204 if ((mask & WIReadMask) && cPtr->delegate->didReceiveInput)
205 (*cPtr->delegate->didReceiveInput)(cPtr->delegate, cPtr);
207 if ((mask & WIExceptMask) && cPtr->delegate->didCatchException)
208 (*cPtr->delegate->didCatchException)(cPtr->delegate, cPtr);
210 wrelease(cPtr);
214 static Bool
215 setSocketNonBlocking(int sock, Bool flag) /*FOLD00*/
217 int state;
218 Bool isNonBlock;
220 state = fcntl(sock, F_GETFL, 0);
222 if (state < 0) {
223 wsyserror("Failed to get socket flags with fcntl.");
224 return False;
227 isNonBlock = (state & NONBLOCK_OPT) != 0;
229 if (flag) {
230 if (isNonBlock)
231 return True;
232 state |= NONBLOCK_OPT;
233 } else {
234 if (!isNonBlock)
235 return True;
236 state &= ~NONBLOCK_OPT;
239 if (fcntl(sock, F_SETFL, state) < 0) {
240 wsyserror("Failed to set socket flags with fcntl.");
241 return False;
244 return True;
248 static void
249 setConnectionAddress(WMConnection *cPtr, struct sockaddr_in *socketaddr) /*FOLD00*/
251 wassertr(cPtr->address==NULL);
253 cPtr->address = wstrdup(inet_ntoa(socketaddr->sin_addr));
254 cPtr->service = wmalloc(16);
255 sprintf(cPtr->service, "%hu", ntohs(socketaddr->sin_port));
256 cPtr->protocol = wstrdup("tcp");
260 static struct sockaddr_in*
261 getSocketAddress(char* name, char* service, char* protocol) /*FOLD00*/
263 static struct sockaddr_in socketaddr;
264 struct servent *sp;
266 if (!protocol || protocol[0]=='\0')
267 protocol = "tcp";
269 memset(&socketaddr, 0, sizeof(struct sockaddr_in));
270 socketaddr.sin_family = AF_INET;
273 * If we were given a hostname, we use any address for that host.
274 * Otherwise we expect the given name to be an address unless it is
275 * NULL (any address).
277 if (name && name[0]!='\0') {
278 WMHost *host = WMGetHostWithName(name);
280 if (!host)
281 return NULL; /* name is not a hostname nor a number and dot adr */
283 name = WMGetHostAddress(host);
284 #ifndef HAVE_INET_ATON
285 if ((socketaddr.sin_addr.s_addr = inet_addr(name)) == INADDR_NONE) {
286 #else
287 if (inet_aton(name, &socketaddr.sin_addr) == 0) {
288 #endif
289 WMReleaseHost(host);
290 return NULL;
292 WMReleaseHost(host);
293 } else {
294 socketaddr.sin_addr.s_addr = htonl(INADDR_ANY);
297 if (!service || service[0]=='\0') {
298 socketaddr.sin_port = 0;
299 } else if ((sp = getservbyname(service, protocol))==0) {
300 char *endptr;
301 unsigned portNumber;
303 portNumber = strtoul(service, &endptr, 10);
305 if (service[0]!='\0' && *endptr=='\0' && portNumber<65536) {
306 socketaddr.sin_port = htons(portNumber);
307 } else {
308 return NULL;
310 } else {
311 socketaddr.sin_port = sp->s_port;
314 return &socketaddr;
318 static WMConnection*
319 createConnectionWithSocket(int sock, Bool closeOnRelease) /*FOLD00*/
321 WMConnection *cPtr;
322 struct sigaction sig_action;
324 cPtr = wmalloc(sizeof(WMConnection));
325 wretain(cPtr);
326 memset(cPtr, 0, sizeof(WMConnection));
328 cPtr->sock = sock;
329 cPtr->sendTimeout.timeout = DEF_TIMEOUT;
330 cPtr->sendTimeout.handler = NULL;
331 cPtr->closeOnRelease = closeOnRelease;
332 cPtr->outputQueue = WMCreateBag(16);
333 cPtr->state = WCNotConnected;
335 /* ignore dead pipe */
336 if (!SigInitialized) {
337 sig_action.sa_handler = SIG_IGN;
338 sig_action.sa_flags = SA_RESTART;
339 sigaction(SIGPIPE, &sig_action, NULL);
340 SigInitialized = True;
343 return cPtr;
347 #if 0
348 WMConnection*
349 WMCreateConnectionWithSocket(int sock, Bool closeOnRelease) /*FOLD00*/
351 WMConnection *cPtr;
352 struct sockaddr_in clientname;
353 int size, n;
355 cPtr = createConnectionWithSocket(sock, closeOnRelease);
356 cPtr->wasNonBlocking = WMIsConnectionNonBlocking(cPtr);
357 cPtr->isNonBlocking = cPtr->wasNonBlocking;
359 /* some way to find out if it is connected, and binded. can't find
360 if it listens though!!!
363 size = sizeof(clientname);
364 n = getpeername(sock, (struct sockaddr*) &clientname, &size);
365 if (n==0) {
366 /* Since we have a peer, it means we are connected */
367 cPtr->state = WCConnected;
368 } else {
369 size = sizeof(clientname);
370 n = getsockname(sock, (struct sockaddr*) &clientname, &size);
371 if (n==0) {
372 /* We don't have a peer, but we are binded to an address.
373 * Assume we are listening on it (we don't know that for sure!)
375 cPtr->state = WCListening;
376 } else {
377 cPtr->state = WCNotConnected;
381 return cPtr;
383 #endif
387 * host is the name on which we want to listen for incoming connections,
388 * and it must be a name of this host, or NULL if we want to listen
389 * on any incoming address.
390 * service is either a service name as present in /etc/services, or the port
391 * number we want to listen on. If NULL, a random port between
392 * 1024 and 65535 will be assigned to us.
393 * protocol is one of "tcp" or "udp". If NULL, "tcp" will be used by default.
394 * currently only "tcp" is supported.
396 WMConnection*
397 WMCreateConnectionAsServerAtAddress(char *host, char *service, char *protocol) /*FOLD00*/
399 WMConnection *cPtr;
400 struct sockaddr_in *socketaddr;
401 int sock, size, on;
403 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
404 WCErrorCode = 0;
405 wwarning("Bad address-service-protocol combination");
406 return NULL;
409 /* Create the actual socket */
410 sock = socket(PF_INET, SOCK_STREAM, 0);
411 if (sock<0) {
412 WCErrorCode = errno;
413 wsyserror("Unable to create socket");
414 return NULL;
418 * Set socket options. We try to make the port reusable and have it
419 * close as fast as possible without waiting in unnecessary wait states
420 * on close.
422 on = 1;
423 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
425 if (bind(sock, (struct sockaddr *)socketaddr, sizeof(*socketaddr)) < 0) {
426 WCErrorCode = errno;
427 wsyserror("Unable to bind to address '%s:%hu'",
428 inet_ntoa(socketaddr->sin_addr),
429 ntohs(socketaddr->sin_port));
430 close(sock);
431 return NULL;
434 if (listen(sock, 10) < 0) {
435 WCErrorCode = errno;
436 wsyserror("Unable to listen on port '%hu'",
437 ntohs(socketaddr->sin_port));
438 close(sock);
439 return NULL;
442 /* Find out what is the address/service/protocol we get */
443 /* In case some of address/service/protocol were NULL */
444 size = sizeof(*socketaddr);
445 if (getsockname(sock, (struct sockaddr*)socketaddr, &size) < 0) {
446 WCErrorCode = errno;
447 wsyserror("Unable to get socket address");
448 close(sock);
449 return NULL;
452 cPtr = createConnectionWithSocket(sock, True);
453 cPtr->state = WCListening;
454 WMSetConnectionNonBlocking(cPtr, True);
456 setConnectionAddress(cPtr, socketaddr);
458 return cPtr;
462 WMConnection*
463 WMCreateConnectionToAddress(char *host, char *service, char *protocol) /*FOLD00*/
465 WMConnection *cPtr;
466 struct sockaddr_in *socketaddr;
467 int sock;
469 if (service==NULL || service[0]=='\0') {
470 WCErrorCode = 0;
471 wwarning("Bad argument - service is not specified");
472 return NULL;
475 if (host==NULL || host[0]=='\0')
476 host = "localhost";
478 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
479 WCErrorCode = 0;
480 wwarning("Bad address-service-protocol combination");
481 return NULL;
484 /* Create the actual socket */
485 sock = socket(PF_INET, SOCK_STREAM, 0);
486 if (sock<0) {
487 WCErrorCode = errno;
488 wsyserror("Unable to create socket");
489 return NULL;
491 /* make socket blocking while we connect. */
492 setSocketNonBlocking(sock, False);
493 if (connect(sock, (struct sockaddr*)socketaddr, sizeof(*socketaddr)) < 0) {
494 WCErrorCode = errno;
495 wsyserror("Unable to make connection to address '%s:%hu'",
496 inet_ntoa(socketaddr->sin_addr),
497 ntohs(socketaddr->sin_port));
498 close(sock);
499 return NULL;
502 cPtr = createConnectionWithSocket(sock, True);
503 cPtr->state = WCConnected;
504 WMSetConnectionNonBlocking(cPtr, True);
505 setConnectionAddress(cPtr, socketaddr);
507 return cPtr;
511 WMConnection*
512 WMCreateConnectionToAddressAndNotify(char *host, char *service, char *protocol) /*FOLD00*/
514 WMConnection *cPtr;
515 /*TimeoutData *tPtr;*/
516 struct sockaddr_in *socketaddr;
517 int sock;
518 Bool isNonBlocking;
520 if (service==NULL || service[0]=='\0') {
521 WCErrorCode = 0;
522 wwarning("Bad argument - service is not specified");
523 return NULL;
526 if (host==NULL || host[0]=='\0')
527 host = "localhost";
529 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
530 WCErrorCode = 0;
531 wwarning("Bad address-service-protocol combination");
532 return NULL;
535 /* Create the actual socket */
536 sock = socket(PF_INET, SOCK_STREAM, 0);
537 if (sock<0) {
538 WCErrorCode = errno;
539 wsyserror("Unable to create socket");
540 return NULL;
542 isNonBlocking = setSocketNonBlocking(sock, True);
543 if (connect(sock, (struct sockaddr*)socketaddr, sizeof(*socketaddr)) < 0) {
544 if (errno!=EINPROGRESS) {
545 WCErrorCode = errno;
546 wsyserror("Unable to make connection to address '%s:%hu'",
547 inet_ntoa(socketaddr->sin_addr),
548 ntohs(socketaddr->sin_port));
549 close(sock);
550 return NULL;
554 cPtr = createConnectionWithSocket(sock, True);
555 cPtr->state = WCInProgress;
556 cPtr->isNonBlocking = isNonBlocking;
558 /*tPtr = &cPtr->sendTimeout;
559 tPtr->handler = WMAddTimerHandler(tPtr->timeout*1000, connectTimeout, cPtr);
561 cPtr->handler.write = WMAddInputHandler(cPtr->sock, WIWriteMask,
562 inputHandler, cPtr);
564 setConnectionAddress(cPtr, socketaddr);
566 return cPtr;
570 static void
571 removeAllHandlers(WMConnection *cPtr) /*FOLD00*/
573 if (cPtr->handler.read)
574 WMDeleteInputHandler(cPtr->handler.read);
575 if (cPtr->handler.write)
576 WMDeleteInputHandler(cPtr->handler.write);
577 if (cPtr->handler.exception)
578 WMDeleteInputHandler(cPtr->handler.exception);
579 if (cPtr->sendTimeout.handler)
580 WMDeleteTimerHandler(cPtr->sendTimeout.handler);
582 cPtr->handler.read = NULL;
583 cPtr->handler.write = NULL;
584 cPtr->handler.exception = NULL;
585 cPtr->sendTimeout.handler = NULL;
589 void
590 WMDestroyConnection(WMConnection *cPtr) /*FOLD00*/
592 if (cPtr->closeOnRelease && cPtr->sock>=0) {
593 shutdown(cPtr->sock, SHUT_RDWR);
594 close(cPtr->sock);
597 removeAllHandlers(cPtr);
598 clearOutputQueue(cPtr);
599 WMFreeBag(cPtr->outputQueue);
601 if (cPtr->address) {
602 wfree(cPtr->address);
603 wfree(cPtr->service);
604 wfree(cPtr->protocol);
607 wrelease(cPtr);
611 void
612 WMCloseConnection(WMConnection *cPtr) /*FOLD00*/
614 if (cPtr->sock>=0) {
615 shutdown(cPtr->sock, SHUT_RDWR);
616 close(cPtr->sock);
617 cPtr->sock = -1;
620 removeAllHandlers(cPtr);
621 clearOutputQueue(cPtr);
623 cPtr->state = WCClosed;
627 WMConnection*
628 WMAcceptConnection(WMConnection *listener) /*FOLD00*/
630 struct sockaddr_in clientname;
631 int size;
632 int newSock;
633 WMConnection *newConnection;
635 if (listener->state!=WCListening) {
636 wwarning("Called 'WMAcceptConnection()' on a non-listening connection");
637 WCErrorCode = 0;
638 return NULL;
641 size = sizeof(clientname);
642 newSock = accept(listener->sock, (struct sockaddr*) &clientname, &size);
643 if (newSock<0) {
644 if (errno!=EAGAIN && errno!=EWOULDBLOCK) {
645 WCErrorCode = errno;
646 wsyserror("Could not accept connection");
647 } else {
648 WCErrorCode = 0;
650 return NULL;
653 newConnection = createConnectionWithSocket(newSock, True);
654 WMSetConnectionNonBlocking(newConnection, True);
655 newConnection->state = WCConnected;
656 setConnectionAddress(newConnection, &clientname);
658 return newConnection;
662 char*
663 WMGetConnectionAddress(WMConnection *cPtr) /*FOLD00*/
665 return cPtr->address;
669 char*
670 WMGetConnectionService(WMConnection *cPtr) /*FOLD00*/
672 return cPtr->service;
676 char*
677 WMGetConnectionProtocol(WMConnection *cPtr)
679 return cPtr->protocol;
684 WMGetConnectionSocket(WMConnection *cPtr) /*FOLD00*/
686 return cPtr->sock;
690 WMConnectionState
691 WMGetConnectionState(WMConnection *cPtr) /*FOLD00*/
693 return cPtr->state;
697 Bool
698 WMEnqueueConnectionData(WMConnection *cPtr, WMData *data) /*FOLD00*/
700 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, False);
701 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, False);
703 if (cPtr->state!=WCConnected)
704 return False;
706 WMPutInBag(cPtr->outputQueue, WMRetainData(data));
707 return True;
712 WMSendConnectionData(WMConnection *cPtr, WMData *data) /*FOLD00*/
714 int bytes, pos, len, totalTransfer;
715 TimeoutData *tPtr = &cPtr->sendTimeout;
716 const unsigned char *dataBytes;
718 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, -1);
719 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, -1);
721 if (cPtr->state!=WCConnected)
722 return -1;
724 /* If we have no data just flush the queue, else try to send data */
725 if (data && WMGetDataLength(data)>0) {
726 WMPutInBag(cPtr->outputQueue, WMRetainData(data));
727 /* If there already was something in queue, and also a write input
728 * handler is established, it means we were unable to send, so
729 * return and let the write handler notify us when we can send.
731 if (WMGetBagItemCount(cPtr->outputQueue)>1 && cPtr->handler.write)
732 return 0;
735 totalTransfer = 0;
737 while (WMGetBagItemCount(cPtr->outputQueue) > 0) {
738 data = WMGetFromBag(cPtr->outputQueue, 0);
739 dataBytes = (const unsigned char *)WMDataBytes(data);
740 len = WMGetDataLength(data);
741 pos = cPtr->bufPos; /* where we're left last time */
742 while(pos < len) {
743 again:
744 bytes = write(cPtr->sock, dataBytes+pos, len - pos);
745 if(bytes<0) {
746 switch (errno) {
747 case EINTR:
748 goto again;
749 case EWOULDBLOCK:
750 /* save the position where we're left and add a timeout */
751 cPtr->bufPos = pos;
752 if (!tPtr->handler) {
753 tPtr->handler = WMAddTimerHandler(tPtr->timeout*1000,
754 sendTimeout, cPtr);
756 if (!cPtr->handler.write) {
757 cPtr->handler.write =
758 WMAddInputHandler(cPtr->sock, WIWriteMask,
759 inputHandler, cPtr);
761 return totalTransfer;
762 default:
763 WCErrorCode = errno;
764 cPtr->state = WCDied;
765 /*clearOutputQueue(cPtr);*/
766 removeAllHandlers(cPtr);
767 if (cPtr->delegate && cPtr->delegate->didDie)
768 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
769 return -1;
772 pos += bytes;
773 totalTransfer += bytes;
775 WMReleaseData(data);
776 WMDeleteFromBag(cPtr->outputQueue, 0);
777 cPtr->bufPos = 0;
778 if (tPtr->handler) {
779 WMDeleteTimerHandler(tPtr->handler);
780 tPtr->handler = NULL;
782 if (cPtr->handler.write) {
783 WMDeleteInputHandler(cPtr->handler.write);
784 cPtr->handler.write = NULL;
788 return totalTransfer;
793 * WMGetConnectionAvailableData(connection):
795 * will return a WMData structure containing the available data on the
796 * specified connection. If connection is non-blocking (default) and no data
797 * is available when this function is called, an empty WMData is returned.
799 * If an error occurs while reading or the other side closed connection,
800 * it will return NULL.
801 * Also trying to read from an already died or closed connection is
802 * considered to be an error condition, and will return NULL.
804 WMData*
805 WMGetConnectionAvailableData(WMConnection *cPtr) /*FOLD00*/
807 char buffer[NETBUF_SIZE];
808 int nbytes;
809 WMData *aData;
811 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, NULL);
812 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, NULL);
814 if (cPtr->state!=WCConnected)
815 return NULL;
817 aData = NULL;
819 again:
820 nbytes = read(cPtr->sock, buffer, NETBUF_SIZE);
821 if (nbytes<0) {
822 switch (errno) {
823 case EINTR:
824 goto again;
825 case EWOULDBLOCK:
826 aData = WMCreateDataWithCapacity(0);
827 break;
828 default:
829 WCErrorCode = errno;
830 cPtr->state = WCDied;
831 removeAllHandlers(cPtr);
832 if (cPtr->delegate && cPtr->delegate->didDie)
833 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
834 break;
836 } else if (nbytes==0) { /* the other side has closed connection */
837 cPtr->state = WCClosed;
838 removeAllHandlers(cPtr);
839 if (cPtr->delegate && cPtr->delegate->didDie)
840 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
841 } else {
842 aData = WMCreateDataWithBytes(buffer, nbytes);
845 return aData;
849 void
850 WMSetConnectionDelegate(WMConnection *cPtr, ConnectionDelegate *delegate) /*FOLD00*/
852 wassertr(cPtr->sock >= 0);
853 /* Don't try to set the delegate multiple times */
854 wassertr(cPtr->delegate == NULL);
856 cPtr->delegate = delegate;
857 if (delegate && delegate->didReceiveInput && !cPtr->handler.read)
858 cPtr->handler.read = WMAddInputHandler(cPtr->sock, WIReadMask,
859 inputHandler, cPtr);
860 if (delegate && delegate->didCatchException && !cPtr->handler.exception)
861 cPtr->handler.exception = WMAddInputHandler(cPtr->sock, WIExceptMask,
862 inputHandler, cPtr);
866 #if 0
867 Bool
868 WMIsConnectionNonBlocking(WMConnection *cPtr) /*FOLD00*/
870 #if 1
871 int state;
873 state = fcntl(cPtr->sock, F_GETFL, 0);
875 if (state < 0) {
876 wsyserror("Failed to get socket flags with fcntl.");
877 /* If we can't use fcntl on socket, this probably also means we could
878 * not use fcntl to set non-blocking mode, and since a socket defaults
879 * to blocking when created, return False as the best assumption */
880 return False;
883 return ((state & NONBLOCK_OPT)!=0);
884 #else
885 return cPtr->isNonBlocking;
886 #endif
888 #endif
891 void
892 WMSetConnectionNonBlocking(WMConnection *cPtr, Bool flag) /*FOLD00*/
894 if (cPtr->sock < 0)
895 return;
897 if (cPtr->isNonBlocking == flag)
898 return;
900 if (setSocketNonBlocking(cPtr->sock, flag)==True)
901 cPtr->isNonBlocking = flag;
905 void*
906 WMGetConnectionClientData(WMConnection *cPtr) /*FOLD00*/
908 return cPtr->clientData;
912 void
913 WMSetConnectionClientData(WMConnection *cPtr, void *data) /*FOLD00*/
915 cPtr->clientData = data;
919 unsigned int
920 WMGetConnectionFlags(WMConnection *cPtr) /*FOLD00*/
922 return cPtr->uflags;
926 void
927 WMSetConnectionFlags(WMConnection *cPtr, unsigned int flags) /*FOLD00*/
929 cPtr->uflags = flags;
933 void
934 WMSetConnectionSendTimeout(WMConnection *cPtr, unsigned int timeout) /*FOLD00*/
936 if (timeout == 0)
937 timeout = DEF_TIMEOUT;
939 cPtr->sendTimeout.timeout = timeout;