*** empty log message ***
[wmaker-crm.git] / WINGs / connection.c
blob93412ae8916000d0a9ca6857a2ad62a587e5e100
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 Solaris */
62 #ifndef 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;
82 static Bool SigInitialized = False;
86 typedef struct TimeoutData {
87 unsigned timeout;
88 WMHandlerID *handler;
89 } TimeoutData;
92 typedef struct W_Connection {
93 int sock; /* the socket we speak through */
95 struct {
96 WMHandlerID *read; /* the input read handler */
97 WMHandlerID *write; /* the input write handler */
98 WMHandlerID *exception; /* the input exception handler */
99 } handler;
101 ConnectionDelegate *delegate; /* client delegates */
102 void *clientData; /* client data */
103 unsigned int uflags; /* flags for the client */
105 WMBag *outputQueue;
106 unsigned bufPos;
108 TimeoutData sendTimeout;
110 WMConnectionState state;
112 char *address;
113 char *service;
114 char *protocol;
116 Bool closeOnRelease;
117 Bool wasNonBlocking;
118 Bool isNonBlocking;
120 } W_Connection;
125 static void
126 clearOutputQueue(WMConnection *cPtr) /*FOLD00*/
128 int i;
130 cPtr->bufPos = 0;
132 for (i=0; i<WMGetBagItemCount(cPtr->outputQueue); i++)
133 WMReleaseData(WMGetFromBag(cPtr->outputQueue, i));
135 WMEmptyBag(cPtr->outputQueue);
139 static void
140 sendTimeout(void *cdata) /*FOLD00*/
142 WMConnection *cPtr = (WMConnection*) cdata;
143 TimeoutData *tPtr = &cPtr->sendTimeout;
145 tPtr->handler = NULL;
146 if (cPtr->handler.write) {
147 WMDeleteInputHandler(cPtr->handler.write);
148 cPtr->handler.write = NULL;
150 if (WMGetBagItemCount(cPtr->outputQueue)>0) {
151 clearOutputQueue(cPtr);
152 if (cPtr->delegate && cPtr->delegate->didTimeout)
153 (*cPtr->delegate->didTimeout)(cPtr->delegate, cPtr);
158 static void
159 inputHandler(int fd, int mask, void *clientData) /*FOLD00*/
161 WMConnection *cPtr = (WMConnection*)clientData;
163 if (cPtr->state==WCClosed || cPtr->state==WCDied)
164 return;
166 if ((mask & WIWriteMask)) {
167 if (cPtr->state == WCInProgress) {
168 Bool failed;
169 int result;
170 int len = sizeof(result);
172 if (getsockopt(cPtr->sock, SOL_SOCKET, SO_ERROR,
173 (void*)&result, &len) == 0 && result != 0) {
174 cPtr->state = WCFailed;
175 WCErrorCode = result;
176 failed = True;
177 /* should call wsyserrorwithcode(result, ...) here? */
178 } else {
179 cPtr->state = WCConnected;
180 failed = False;
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 /* we use failed and not cPtr->state here, because cPtr may be
192 * destroyed by the delegate called above if the connection failed
194 if (failed)
195 return;
196 } else if (cPtr->state == WCConnected) {
197 WMFlushConnection(cPtr);
201 if (!cPtr->delegate)
202 return;
204 /* if the connection died, may get destroyed in the delegate, so retain */
205 wretain(cPtr);
207 if ((mask & WIReadMask) && cPtr->delegate->didReceiveInput)
208 (*cPtr->delegate->didReceiveInput)(cPtr->delegate, cPtr);
210 if ((mask & WIExceptMask) && cPtr->delegate->didCatchException)
211 (*cPtr->delegate->didCatchException)(cPtr->delegate, cPtr);
213 wrelease(cPtr);
217 static Bool
218 setSocketNonBlocking(int sock, Bool flag) /*FOLD00*/
220 int state;
221 Bool isNonBlock;
223 state = fcntl(sock, F_GETFL, 0);
225 if (state < 0) {
226 wsyserror("Failed to get socket flags with fcntl.");
227 return False;
230 isNonBlock = (state & NONBLOCK_OPT) != 0;
232 if (flag) {
233 if (isNonBlock)
234 return True;
235 state |= NONBLOCK_OPT;
236 } else {
237 if (!isNonBlock)
238 return True;
239 state &= ~NONBLOCK_OPT;
242 if (fcntl(sock, F_SETFL, state) < 0) {
243 wsyserror("Failed to set socket flags with fcntl.");
244 return False;
247 return True;
251 static void
252 setConnectionAddress(WMConnection *cPtr, struct sockaddr_in *socketaddr) /*FOLD00*/
254 wassertr(cPtr->address==NULL);
256 cPtr->address = wstrdup(inet_ntoa(socketaddr->sin_addr));
257 cPtr->service = wmalloc(16);
258 sprintf(cPtr->service, "%hu", ntohs(socketaddr->sin_port));
259 cPtr->protocol = wstrdup("tcp");
263 static struct sockaddr_in*
264 getSocketAddress(char* name, char* service, char* protocol) /*FOLD00*/
266 static struct sockaddr_in socketaddr;
267 struct servent *sp;
269 if (!protocol || protocol[0]=='\0')
270 protocol = "tcp";
272 memset(&socketaddr, 0, sizeof(struct sockaddr_in));
273 socketaddr.sin_family = AF_INET;
276 * If we were given a hostname, we use any address for that host.
277 * Otherwise we expect the given name to be an address unless it is
278 * NULL (any address).
280 if (name && name[0]!='\0') {
281 WMHost *host = WMGetHostWithName(name);
283 if (!host)
284 return NULL; /* name is not a hostname nor a number and dot adr */
286 name = WMGetHostAddress(host);
287 #ifndef HAVE_INET_ATON
288 if ((socketaddr.sin_addr.s_addr = inet_addr(name)) == INADDR_NONE) {
289 #else
290 if (inet_aton(name, &socketaddr.sin_addr) == 0) {
291 #endif
292 WMReleaseHost(host);
293 return NULL;
295 WMReleaseHost(host);
296 } else {
297 socketaddr.sin_addr.s_addr = htonl(INADDR_ANY);
300 if (!service || service[0]=='\0') {
301 socketaddr.sin_port = 0;
302 } else if ((sp = getservbyname(service, protocol))==0) {
303 char *endptr;
304 unsigned portNumber;
306 portNumber = strtoul(service, &endptr, 10);
308 if (service[0]!='\0' && *endptr=='\0' && portNumber<65536) {
309 socketaddr.sin_port = htons(portNumber);
310 } else {
311 return NULL;
313 } else {
314 socketaddr.sin_port = sp->s_port;
317 return &socketaddr;
321 static WMConnection*
322 createConnectionWithSocket(int sock, Bool closeOnRelease) /*FOLD00*/
324 WMConnection *cPtr;
325 struct sigaction sig_action;
327 cPtr = wmalloc(sizeof(WMConnection));
328 wretain(cPtr);
329 memset(cPtr, 0, sizeof(WMConnection));
331 cPtr->sock = sock;
332 cPtr->sendTimeout.timeout = DEF_TIMEOUT;
333 cPtr->sendTimeout.handler = NULL;
334 cPtr->closeOnRelease = closeOnRelease;
335 cPtr->outputQueue = WMCreateBag(16);
336 cPtr->state = WCNotConnected;
338 /* ignore dead pipe */
339 if (!SigInitialized) {
340 sig_action.sa_handler = SIG_IGN;
341 sig_action.sa_flags = SA_RESTART;
342 sigaction(SIGPIPE, &sig_action, NULL);
343 SigInitialized = True;
346 return cPtr;
350 #if 0
351 WMConnection*
352 WMCreateConnectionWithSocket(int sock, Bool closeOnRelease) /*FOLD00*/
354 WMConnection *cPtr;
355 struct sockaddr_in clientname;
356 int size, n;
358 cPtr = createConnectionWithSocket(sock, closeOnRelease);
359 cPtr->wasNonBlocking = WMIsConnectionNonBlocking(cPtr);
360 cPtr->isNonBlocking = cPtr->wasNonBlocking;
362 /* some way to find out if it is connected, and binded. can't find
363 if it listens though!!!
366 size = sizeof(clientname);
367 n = getpeername(sock, (struct sockaddr*) &clientname, &size);
368 if (n==0) {
369 /* Since we have a peer, it means we are connected */
370 cPtr->state = WCConnected;
371 } else {
372 size = sizeof(clientname);
373 n = getsockname(sock, (struct sockaddr*) &clientname, &size);
374 if (n==0) {
375 /* We don't have a peer, but we are binded to an address.
376 * Assume we are listening on it (we don't know that for sure!)
378 cPtr->state = WCListening;
379 } else {
380 cPtr->state = WCNotConnected;
384 return cPtr;
386 #endif
390 * host is the name on which we want to listen for incoming connections,
391 * and it must be a name of this host, or NULL if we want to listen
392 * on any incoming address.
393 * service is either a service name as present in /etc/services, or the port
394 * number we want to listen on. If NULL, a random port between
395 * 1024 and 65535 will be assigned to us.
396 * protocol is one of "tcp" or "udp". If NULL, "tcp" will be used by default.
397 * currently only "tcp" is supported.
399 WMConnection*
400 WMCreateConnectionAsServerAtAddress(char *host, char *service, char *protocol) /*FOLD00*/
402 WMConnection *cPtr;
403 struct sockaddr_in *socketaddr;
404 int sock, size, on;
406 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
407 WCErrorCode = 0;
408 wwarning("Bad address-service-protocol combination");
409 return NULL;
412 /* Create the actual socket */
413 sock = socket(PF_INET, SOCK_STREAM, 0);
414 if (sock<0) {
415 WCErrorCode = errno;
416 wsyserror("Unable to create socket");
417 return NULL;
421 * Set socket options. We try to make the port reusable and have it
422 * close as fast as possible without waiting in unnecessary wait states
423 * on close.
425 on = 1;
426 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
428 if (bind(sock, (struct sockaddr *)socketaddr, sizeof(*socketaddr)) < 0) {
429 WCErrorCode = errno;
430 wsyserror("Unable to bind to address '%s:%hu'",
431 inet_ntoa(socketaddr->sin_addr),
432 ntohs(socketaddr->sin_port));
433 close(sock);
434 return NULL;
437 if (listen(sock, 10) < 0) {
438 WCErrorCode = errno;
439 wsyserror("Unable to listen on port '%hu'",
440 ntohs(socketaddr->sin_port));
441 close(sock);
442 return NULL;
445 /* Find out what is the address/service/protocol we get */
446 /* In case some of address/service/protocol were NULL */
447 size = sizeof(*socketaddr);
448 if (getsockname(sock, (struct sockaddr*)socketaddr, &size) < 0) {
449 WCErrorCode = errno;
450 wsyserror("Unable to get socket address");
451 close(sock);
452 return NULL;
455 cPtr = createConnectionWithSocket(sock, True);
456 cPtr->state = WCListening;
457 WMSetConnectionNonBlocking(cPtr, True);
459 setConnectionAddress(cPtr, socketaddr);
461 return cPtr;
465 WMConnection*
466 WMCreateConnectionToAddress(char *host, char *service, char *protocol) /*FOLD00*/
468 WMConnection *cPtr;
469 struct sockaddr_in *socketaddr;
470 int sock;
472 if (service==NULL || service[0]=='\0') {
473 WCErrorCode = 0;
474 wwarning("Bad argument - service is not specified");
475 return NULL;
478 if (host==NULL || host[0]=='\0')
479 host = "localhost";
481 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
482 WCErrorCode = 0;
483 wwarning("Bad address-service-protocol combination");
484 return NULL;
487 /* Create the actual socket */
488 sock = socket(PF_INET, SOCK_STREAM, 0);
489 if (sock<0) {
490 WCErrorCode = errno;
491 wsyserror("Unable to create socket");
492 return NULL;
494 /* make socket blocking while we connect. */
495 setSocketNonBlocking(sock, False);
496 if (connect(sock, (struct sockaddr*)socketaddr, sizeof(*socketaddr)) < 0) {
497 WCErrorCode = errno;
498 wsyserror("Unable to make connection to address '%s:%hu'",
499 inet_ntoa(socketaddr->sin_addr),
500 ntohs(socketaddr->sin_port));
501 close(sock);
502 return NULL;
505 cPtr = createConnectionWithSocket(sock, True);
506 cPtr->state = WCConnected;
507 WMSetConnectionNonBlocking(cPtr, True);
508 setConnectionAddress(cPtr, socketaddr);
510 return cPtr;
514 WMConnection*
515 WMCreateConnectionToAddressAndNotify(char *host, char *service, char *protocol) /*FOLD00*/
517 WMConnection *cPtr;
518 /*TimeoutData *tPtr;*/
519 struct sockaddr_in *socketaddr;
520 int sock;
521 Bool isNonBlocking;
523 if (service==NULL || service[0]=='\0') {
524 WCErrorCode = 0;
525 wwarning("Bad argument - service is not specified");
526 return NULL;
529 if (host==NULL || host[0]=='\0')
530 host = "localhost";
532 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
533 WCErrorCode = 0;
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 wsyserror("Unable to create socket");
543 return NULL;
545 isNonBlocking = setSocketNonBlocking(sock, True);
546 if (connect(sock, (struct sockaddr*)socketaddr, sizeof(*socketaddr)) < 0) {
547 if (errno!=EINPROGRESS) {
548 WCErrorCode = errno;
549 wsyserror("Unable to make connection to address '%s:%hu'",
550 inet_ntoa(socketaddr->sin_addr),
551 ntohs(socketaddr->sin_port));
552 close(sock);
553 return NULL;
557 cPtr = createConnectionWithSocket(sock, True);
558 cPtr->state = WCInProgress;
559 cPtr->isNonBlocking = isNonBlocking;
561 /*tPtr = &cPtr->sendTimeout;
562 tPtr->handler = WMAddTimerHandler(tPtr->timeout*1000, connectTimeout, cPtr);
564 cPtr->handler.write = WMAddInputHandler(cPtr->sock, WIWriteMask,
565 inputHandler, cPtr);
567 setConnectionAddress(cPtr, socketaddr);
569 return cPtr;
573 static void
574 removeAllHandlers(WMConnection *cPtr) /*FOLD00*/
576 if (cPtr->handler.read)
577 WMDeleteInputHandler(cPtr->handler.read);
578 if (cPtr->handler.write)
579 WMDeleteInputHandler(cPtr->handler.write);
580 if (cPtr->handler.exception)
581 WMDeleteInputHandler(cPtr->handler.exception);
582 if (cPtr->sendTimeout.handler)
583 WMDeleteTimerHandler(cPtr->sendTimeout.handler);
585 cPtr->handler.read = NULL;
586 cPtr->handler.write = NULL;
587 cPtr->handler.exception = NULL;
588 cPtr->sendTimeout.handler = NULL;
592 void
593 WMDestroyConnection(WMConnection *cPtr) /*FOLD00*/
595 if (cPtr->closeOnRelease && cPtr->sock>=0) {
596 shutdown(cPtr->sock, SHUT_RDWR);
597 close(cPtr->sock);
600 removeAllHandlers(cPtr);
601 clearOutputQueue(cPtr);
602 WMFreeBag(cPtr->outputQueue);
604 if (cPtr->address) {
605 wfree(cPtr->address);
606 wfree(cPtr->service);
607 wfree(cPtr->protocol);
610 wrelease(cPtr);
614 void
615 WMCloseConnection(WMConnection *cPtr) /*FOLD00*/
617 if (cPtr->sock>=0) {
618 shutdown(cPtr->sock, SHUT_RDWR);
619 close(cPtr->sock);
620 cPtr->sock = -1;
623 removeAllHandlers(cPtr);
624 clearOutputQueue(cPtr);
626 cPtr->state = WCClosed;
630 WMConnection*
631 WMAcceptConnection(WMConnection *listener) /*FOLD00*/
633 struct sockaddr_in clientname;
634 int size;
635 int newSock;
636 WMConnection *newConnection;
638 if (listener->state!=WCListening) {
639 wwarning("Called 'WMAcceptConnection()' on a non-listening connection");
640 WCErrorCode = 0;
641 return NULL;
644 size = sizeof(clientname);
645 newSock = accept(listener->sock, (struct sockaddr*) &clientname, &size);
646 if (newSock<0) {
647 if (errno!=EAGAIN && errno!=EWOULDBLOCK) {
648 WCErrorCode = errno;
649 wsyserror("Could not accept connection");
650 } else {
651 WCErrorCode = 0;
653 return NULL;
656 newConnection = createConnectionWithSocket(newSock, True);
657 WMSetConnectionNonBlocking(newConnection, True);
658 newConnection->state = WCConnected;
659 setConnectionAddress(newConnection, &clientname);
661 return newConnection;
665 char*
666 WMGetConnectionAddress(WMConnection *cPtr) /*FOLD00*/
668 return cPtr->address;
672 char*
673 WMGetConnectionService(WMConnection *cPtr) /*FOLD00*/
675 return cPtr->service;
679 char*
680 WMGetConnectionProtocol(WMConnection *cPtr)
682 return cPtr->protocol;
687 WMGetConnectionSocket(WMConnection *cPtr) /*FOLD00*/
689 return cPtr->sock;
693 WMConnectionState
694 WMGetConnectionState(WMConnection *cPtr) /*FOLD00*/
696 return cPtr->state;
700 Bool
701 WMEnqueueConnectionData(WMConnection *cPtr, WMData *data) /*FOLD00*/
703 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, False);
704 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, False);
706 if (cPtr->state!=WCConnected)
707 return False;
709 WMPutInBag(cPtr->outputQueue, WMRetainData(data));
710 return True;
715 WMSendConnectionData(WMConnection *cPtr, WMData *data) /*FOLD00*/
717 int bytes, pos, len, totalTransfer;
718 TimeoutData *tPtr = &cPtr->sendTimeout;
719 const unsigned char *dataBytes;
721 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, -1);
722 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, -1);
724 if (cPtr->state!=WCConnected)
725 return -1;
727 /* If we have no data just flush the queue, else try to send data */
728 if (data && WMGetDataLength(data)>0) {
729 WMPutInBag(cPtr->outputQueue, WMRetainData(data));
730 /* If there already was something in queue, and also a write input
731 * handler is established, it means we were unable to send, so
732 * return and let the write handler notify us when we can send.
734 if (WMGetBagItemCount(cPtr->outputQueue)>1 && cPtr->handler.write)
735 return 0;
738 totalTransfer = 0;
740 while (WMGetBagItemCount(cPtr->outputQueue) > 0) {
741 data = WMGetFromBag(cPtr->outputQueue, 0);
742 dataBytes = (const unsigned char *)WMDataBytes(data);
743 len = WMGetDataLength(data);
744 pos = cPtr->bufPos; /* where we're left last time */
745 while(pos < len) {
746 again:
747 bytes = write(cPtr->sock, dataBytes+pos, len - pos);
748 if(bytes<0) {
749 switch (errno) {
750 case EINTR:
751 goto again;
752 case EWOULDBLOCK:
753 /* save the position where we're left and add a timeout */
754 cPtr->bufPos = pos;
755 if (!tPtr->handler) {
756 tPtr->handler = WMAddTimerHandler(tPtr->timeout*1000,
757 sendTimeout, cPtr);
759 if (!cPtr->handler.write) {
760 cPtr->handler.write =
761 WMAddInputHandler(cPtr->sock, WIWriteMask,
762 inputHandler, cPtr);
764 return totalTransfer;
765 default:
766 WCErrorCode = errno;
767 cPtr->state = WCDied;
768 /*clearOutputQueue(cPtr);*/
769 removeAllHandlers(cPtr);
770 if (cPtr->delegate && cPtr->delegate->didDie)
771 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
772 return -1;
775 pos += bytes;
776 totalTransfer += bytes;
778 WMReleaseData(data);
779 WMDeleteFromBag(cPtr->outputQueue, 0);
780 cPtr->bufPos = 0;
781 if (tPtr->handler) {
782 WMDeleteTimerHandler(tPtr->handler);
783 tPtr->handler = NULL;
785 if (cPtr->handler.write) {
786 WMDeleteInputHandler(cPtr->handler.write);
787 cPtr->handler.write = NULL;
791 return totalTransfer;
796 * WMGetConnectionAvailableData(connection):
798 * will return a WMData structure containing the available data on the
799 * specified connection. If connection is non-blocking (default) and no data
800 * is available when this function is called, an empty WMData is returned.
802 * If an error occurs while reading or the other side closed connection,
803 * it will return NULL.
804 * Also trying to read from an already died or closed connection is
805 * considered to be an error condition, and will return NULL.
807 WMData*
808 WMGetConnectionAvailableData(WMConnection *cPtr) /*FOLD00*/
810 char buffer[NETBUF_SIZE];
811 int nbytes;
812 WMData *aData;
814 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, NULL);
815 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, NULL);
817 if (cPtr->state!=WCConnected)
818 return NULL;
820 aData = NULL;
822 again:
823 nbytes = read(cPtr->sock, buffer, NETBUF_SIZE);
824 if (nbytes<0) {
825 switch (errno) {
826 case EINTR:
827 goto again;
828 case EWOULDBLOCK:
829 aData = WMCreateDataWithCapacity(0);
830 break;
831 default:
832 WCErrorCode = errno;
833 cPtr->state = WCDied;
834 removeAllHandlers(cPtr);
835 if (cPtr->delegate && cPtr->delegate->didDie)
836 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
837 break;
839 } else if (nbytes==0) { /* the other side has closed connection */
840 cPtr->state = WCClosed;
841 removeAllHandlers(cPtr);
842 if (cPtr->delegate && cPtr->delegate->didDie)
843 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
844 } else {
845 aData = WMCreateDataWithBytes(buffer, nbytes);
848 return aData;
852 void
853 WMSetConnectionDelegate(WMConnection *cPtr, ConnectionDelegate *delegate) /*FOLD00*/
855 wassertr(cPtr->sock >= 0);
856 /* Don't try to set the delegate multiple times */
857 wassertr(cPtr->delegate == NULL);
859 cPtr->delegate = delegate;
860 if (delegate && delegate->didReceiveInput && !cPtr->handler.read)
861 cPtr->handler.read = WMAddInputHandler(cPtr->sock, WIReadMask,
862 inputHandler, cPtr);
863 if (delegate && delegate->didCatchException && !cPtr->handler.exception)
864 cPtr->handler.exception = WMAddInputHandler(cPtr->sock, WIExceptMask,
865 inputHandler, cPtr);
869 #if 0
870 Bool
871 WMIsConnectionNonBlocking(WMConnection *cPtr) /*FOLD00*/
873 #if 1
874 int state;
876 state = fcntl(cPtr->sock, F_GETFL, 0);
878 if (state < 0) {
879 wsyserror("Failed to get socket flags with fcntl.");
880 /* If we can't use fcntl on socket, this probably also means we could
881 * not use fcntl to set non-blocking mode, and since a socket defaults
882 * to blocking when created, return False as the best assumption */
883 return False;
886 return ((state & NONBLOCK_OPT)!=0);
887 #else
888 return cPtr->isNonBlocking;
889 #endif
891 #endif
894 void
895 WMSetConnectionNonBlocking(WMConnection *cPtr, Bool flag) /*FOLD00*/
897 if (cPtr->sock < 0)
898 return;
900 if (cPtr->isNonBlocking == flag)
901 return;
903 if (setSocketNonBlocking(cPtr->sock, flag)==True)
904 cPtr->isNonBlocking = flag;
908 void*
909 WMGetConnectionClientData(WMConnection *cPtr) /*FOLD00*/
911 return cPtr->clientData;
915 void
916 WMSetConnectionClientData(WMConnection *cPtr, void *data) /*FOLD00*/
918 cPtr->clientData = data;
922 unsigned int
923 WMGetConnectionFlags(WMConnection *cPtr) /*FOLD00*/
925 return cPtr->uflags;
929 void
930 WMSetConnectionFlags(WMConnection *cPtr, unsigned int flags) /*FOLD00*/
932 cPtr->uflags = flags;
936 void
937 WMSetConnectionSendTimeout(WMConnection *cPtr, unsigned int timeout) /*FOLD00*/
939 if (timeout == 0)
940 timeout = DEF_TIMEOUT;
942 cPtr->sendTimeout.timeout = timeout;