Fix for non-gcc compilers
[wmaker-crm.git] / WINGs / connection.c
blob1fdf3b382e68e8fae60ea9aa299a1b154c2b01b5
1 /*
2 * WINGs WMConnection function library
3 *
4 * Copyright (c) 1999 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 /* Stuff for setting the sockets into non-blocking mode. */
62 /*#ifdef __POSIX_SOURCE
63 # define NONBLOCK_OPT O_NONBLOCK
64 #else
65 # define NONBLOCK_OPT FNDELAY
66 #endif*/
68 #define NONBLOCK_OPT O_NONBLOCK
71 #define NETBUF_SIZE 4096
74 #define DEF_TIMEOUT 600 /* 600 seconds == 10 minutes */
77 int WCErrorCode = 0;
81 static Bool SigInitialized = False;
85 typedef struct TimeoutData {
86 unsigned timeout;
87 WMHandlerID *handler;
88 } 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 int result;
169 int len = sizeof(result);
171 if (getsockopt(cPtr->sock, SOL_SOCKET, SO_ERROR,
172 (void*)&result, &len) == 0 && result != 0) {
173 cPtr->state = WCFailed;
174 WCErrorCode = result;
175 /* should call wsyserrorwithcode(result, ...) here? */
176 } else {
177 cPtr->state = WCConnected;
180 if (cPtr->handler.write) {
181 WMDeleteInputHandler(cPtr->handler.write);
182 cPtr->handler.write = NULL;
185 if (cPtr->delegate && cPtr->delegate->didInitialize)
186 (*cPtr->delegate->didInitialize)(cPtr->delegate, cPtr);
188 if (cPtr->state == WCFailed)
189 return;
190 } else if (cPtr->state == WCConnected) {
191 WMFlushConnection(cPtr);
195 if (!cPtr->delegate)
196 return;
198 /* if the connection died, may get destroyed in the delegate, so retain */
199 wretain(cPtr);
201 if ((mask & WIReadMask) && cPtr->delegate->didReceiveInput)
202 (*cPtr->delegate->didReceiveInput)(cPtr->delegate, cPtr);
204 if ((mask & WIExceptMask) && cPtr->delegate->didCatchException)
205 (*cPtr->delegate->didCatchException)(cPtr->delegate, cPtr);
207 wrelease(cPtr);
211 static Bool
212 setSocketNonBlocking(int sock, Bool flag) /*FOLD00*/
214 int state;
215 Bool isNonBlock;
217 state = fcntl(sock, F_GETFL, 0);
219 if (state < 0) {
220 wsyserror("Failed to get socket flags with fcntl.");
221 return False;
224 isNonBlock = (state & NONBLOCK_OPT) != 0;
226 if (flag) {
227 if (isNonBlock)
228 return True;
229 state |= NONBLOCK_OPT;
230 } else {
231 if (!isNonBlock)
232 return True;
233 state &= ~NONBLOCK_OPT;
236 if (fcntl(sock, F_SETFL, state) < 0) {
237 wsyserror("Failed to set socket flags with fcntl.");
238 return False;
241 return True;
245 static void
246 setConnectionAddress(WMConnection *cPtr, struct sockaddr_in *socketaddr) /*FOLD00*/
248 wassertr(cPtr->address==NULL);
250 cPtr->address = wstrdup(inet_ntoa(socketaddr->sin_addr));
251 cPtr->service = wmalloc(16);
252 sprintf(cPtr->service, "%hu", ntohs(socketaddr->sin_port));
253 cPtr->protocol = wstrdup("tcp");
257 static struct sockaddr_in*
258 getSocketAddress(char* name, char* service, char* protocol) /*FOLD00*/
260 static struct sockaddr_in socketaddr;
261 struct servent *sp;
263 if (!protocol || protocol[0]=='\0')
264 protocol = "tcp";
266 memset(&socketaddr, 0, sizeof(struct sockaddr_in));
267 socketaddr.sin_family = AF_INET;
270 * If we were given a hostname, we use any address for that host.
271 * Otherwise we expect the given name to be an address unless it is
272 * NULL (any address).
274 if (name && name[0]!='\0') {
275 WMHost *host = WMGetHostWithName(name);
277 if (!host)
278 return NULL; /* name is not a hostname nor a number and dot adr */
280 name = WMGetHostAddress(host);
281 #ifndef HAVE_INET_ATON
282 if ((socketaddr.sin_addr.s_addr = inet_addr(name)) == INADDR_NONE) {
283 #else
284 if (inet_aton(name, &socketaddr.sin_addr) == 0) {
285 #endif
286 WMReleaseHost(host);
287 return NULL;
289 WMReleaseHost(host);
290 } else {
291 socketaddr.sin_addr.s_addr = htonl(INADDR_ANY);
294 if (!service || service[0]=='\0') {
295 socketaddr.sin_port = 0;
296 } else if ((sp = getservbyname(service, protocol))==0) {
297 char *endptr;
298 unsigned portNumber;
300 portNumber = strtoul(service, &endptr, 10);
302 if (service[0]!='\0' && *endptr=='\0' && portNumber<65536) {
303 socketaddr.sin_port = htons(portNumber);
304 } else {
305 return NULL;
307 } else {
308 socketaddr.sin_port = sp->s_port;
311 return &socketaddr;
315 static WMConnection*
316 createConnectionWithSocket(int sock, Bool closeOnRelease) /*FOLD00*/
318 WMConnection *cPtr;
319 struct sigaction sig_action;
321 cPtr = wmalloc(sizeof(WMConnection));
322 wretain(cPtr);
323 memset(cPtr, 0, sizeof(WMConnection));
325 cPtr->sock = sock;
326 cPtr->sendTimeout.timeout = DEF_TIMEOUT;
327 cPtr->sendTimeout.handler = NULL;
328 cPtr->closeOnRelease = closeOnRelease;
329 cPtr->outputQueue = WMCreateBag(16);
330 cPtr->state = WCNotConnected;
332 /* ignore dead pipe */
333 if (!SigInitialized) {
334 sig_action.sa_handler = SIG_IGN;
335 sig_action.sa_flags = SA_RESTART;
336 sigaction(SIGPIPE, &sig_action, NULL);
337 SigInitialized = True;
340 return cPtr;
344 #if 0
345 WMConnection*
346 WMCreateConnectionWithSocket(int sock, Bool closeOnRelease) /*FOLD00*/
348 WMConnection *cPtr;
349 struct sockaddr_in clientname;
350 int size, n;
352 cPtr = createConnectionWithSocket(sock, closeOnRelease);
353 cPtr->wasNonBlocking = WMIsConnectionNonBlocking(cPtr);
354 cPtr->isNonBlocking = cPtr->wasNonBlocking;
356 /* some way to find out if it is connected, and binded. can't find
357 if it listens though!!!
360 size = sizeof(clientname);
361 n = getpeername(sock, (struct sockaddr*) &clientname, &size);
362 if (n==0) {
363 /* Since we have a peer, it means we are connected */
364 cPtr->state = WCConnected;
365 } else {
366 size = sizeof(clientname);
367 n = getsockname(sock, (struct sockaddr*) &clientname, &size);
368 if (n==0) {
369 /* We don't have a peer, but we are binded to an address.
370 * Assume we are listening on it (we don't know that for sure!)
372 cPtr->state = WCListening;
373 } else {
374 cPtr->state = WCNotConnected;
378 return cPtr;
380 #endif
384 * host is the name on which we want to listen for incoming connections,
385 * and it must be a name of this host, or NULL if we want to listen
386 * on any incoming address.
387 * service is either a service name as present in /etc/services, or the port
388 * number we want to listen on. If NULL, a random port between
389 * 1024 and 65535 will be assigned to us.
390 * protocol is one of "tcp" or "udp". If NULL, "tcp" will be used by default.
391 * currently only "tcp" is supported.
393 WMConnection*
394 WMCreateConnectionAsServerAtAddress(char *host, char *service, char *protocol) /*FOLD00*/
396 WMConnection *cPtr;
397 struct sockaddr_in *socketaddr;
398 int sock, size, on;
400 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
401 WCErrorCode = 0;
402 wwarning("Bad address-service-protocol combination");
403 return NULL;
406 /* Create the actual socket */
407 sock = socket(PF_INET, SOCK_STREAM, 0);
408 if (sock<0) {
409 WCErrorCode = errno;
410 wsyserror("Unable to create socket");
411 return NULL;
415 * Set socket options. We try to make the port reusable and have it
416 * close as fast as possible without waiting in unnecessary wait states
417 * on close.
419 on = 1;
420 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
422 if (bind(sock, (struct sockaddr *)socketaddr, sizeof(*socketaddr)) < 0) {
423 WCErrorCode = errno;
424 wsyserror("Unable to bind to address '%s:%hu'",
425 inet_ntoa(socketaddr->sin_addr),
426 ntohs(socketaddr->sin_port));
427 close(sock);
428 return NULL;
431 if (listen(sock, 10) < 0) {
432 WCErrorCode = errno;
433 wsyserror("Unable to listen on port '%hu'",
434 ntohs(socketaddr->sin_port));
435 close(sock);
436 return NULL;
439 /* Find out what is the address/service/protocol we get */
440 /* In case some of address/service/protocol were NULL */
441 size = sizeof(*socketaddr);
442 if (getsockname(sock, (struct sockaddr*)socketaddr, &size) < 0) {
443 WCErrorCode = errno;
444 wsyserror("Unable to get socket address");
445 close(sock);
446 return NULL;
449 cPtr = createConnectionWithSocket(sock, True);
450 cPtr->state = WCListening;
451 WMSetConnectionNonBlocking(cPtr, True);
453 setConnectionAddress(cPtr, socketaddr);
455 return cPtr;
459 WMConnection*
460 WMCreateConnectionToAddress(char *host, char *service, char *protocol) /*FOLD00*/
462 WMConnection *cPtr;
463 struct sockaddr_in *socketaddr;
464 int sock;
466 if (service==NULL || service[0]=='\0') {
467 WCErrorCode = 0;
468 wwarning("Bad argument - service is not specified");
469 return NULL;
472 if (host==NULL || host[0]=='\0')
473 host = "localhost";
475 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
476 WCErrorCode = 0;
477 wwarning("Bad address-service-protocol combination");
478 return NULL;
481 /* Create the actual socket */
482 sock = socket(PF_INET, SOCK_STREAM, 0);
483 if (sock<0) {
484 WCErrorCode = errno;
485 wsyserror("Unable to create socket");
486 return NULL;
488 /* make socket blocking while we connect. */
489 setSocketNonBlocking(sock, False);
490 if (connect(sock, (struct sockaddr*)socketaddr, sizeof(*socketaddr)) < 0) {
491 WCErrorCode = errno;
492 wsyserror("Unable to make connection to address '%s:%hu'",
493 inet_ntoa(socketaddr->sin_addr),
494 ntohs(socketaddr->sin_port));
495 close(sock);
496 return NULL;
499 cPtr = createConnectionWithSocket(sock, True);
500 cPtr->state = WCConnected;
501 WMSetConnectionNonBlocking(cPtr, True);
502 setConnectionAddress(cPtr, socketaddr);
504 return cPtr;
508 WMConnection*
509 WMCreateConnectionToAddressAndNotify(char *host, char *service, char *protocol) /*FOLD00*/
511 WMConnection *cPtr;
512 /*TimeoutData *tPtr;*/
513 struct sockaddr_in *socketaddr;
514 int sock;
515 Bool isNonBlocking;
517 if (service==NULL || service[0]=='\0') {
518 WCErrorCode = 0;
519 wwarning("Bad argument - service is not specified");
520 return NULL;
523 if (host==NULL || host[0]=='\0')
524 host = "localhost";
526 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
527 WCErrorCode = 0;
528 wwarning("Bad address-service-protocol combination");
529 return NULL;
532 /* Create the actual socket */
533 sock = socket(PF_INET, SOCK_STREAM, 0);
534 if (sock<0) {
535 WCErrorCode = errno;
536 wsyserror("Unable to create socket");
537 return NULL;
539 isNonBlocking = setSocketNonBlocking(sock, True);
540 if (connect(sock, (struct sockaddr*)socketaddr, sizeof(*socketaddr)) < 0) {
541 if (errno!=EINPROGRESS) {
542 WCErrorCode = errno;
543 wsyserror("Unable to make connection to address '%s:%hu'",
544 inet_ntoa(socketaddr->sin_addr),
545 ntohs(socketaddr->sin_port));
546 close(sock);
547 return NULL;
551 cPtr = createConnectionWithSocket(sock, True);
552 cPtr->state = WCInProgress;
553 cPtr->isNonBlocking = isNonBlocking;
555 /*tPtr = &cPtr->sendTimeout;
556 tPtr->handler = WMAddTimerHandler(tPtr->timeout*1000, connectTimeout, cPtr);
558 cPtr->handler.write = WMAddInputHandler(cPtr->sock, WIWriteMask,
559 inputHandler, cPtr);
561 setConnectionAddress(cPtr, socketaddr);
563 return cPtr;
567 static void
568 removeAllHandlers(WMConnection *cPtr) /*FOLD00*/
570 if (cPtr->handler.read)
571 WMDeleteInputHandler(cPtr->handler.read);
572 if (cPtr->handler.write)
573 WMDeleteInputHandler(cPtr->handler.write);
574 if (cPtr->handler.exception)
575 WMDeleteInputHandler(cPtr->handler.exception);
576 if (cPtr->sendTimeout.handler)
577 WMDeleteTimerHandler(cPtr->sendTimeout.handler);
579 cPtr->handler.read = NULL;
580 cPtr->handler.write = NULL;
581 cPtr->handler.exception = NULL;
582 cPtr->sendTimeout.handler = NULL;
586 void
587 WMDestroyConnection(WMConnection *cPtr) /*FOLD00*/
589 if (cPtr->closeOnRelease && cPtr->sock>=0) {
590 shutdown(cPtr->sock, SHUT_RDWR);
591 close(cPtr->sock);
594 removeAllHandlers(cPtr);
595 clearOutputQueue(cPtr);
596 WMFreeBag(cPtr->outputQueue);
598 if (cPtr->address) {
599 wfree(cPtr->address);
600 wfree(cPtr->service);
601 wfree(cPtr->protocol);
604 wrelease(cPtr);
608 void
609 WMCloseConnection(WMConnection *cPtr) /*FOLD00*/
611 if (cPtr->sock>=0) {
612 shutdown(cPtr->sock, SHUT_RDWR);
613 close(cPtr->sock);
614 cPtr->sock = -1;
617 removeAllHandlers(cPtr);
618 clearOutputQueue(cPtr);
620 cPtr->state = WCClosed;
624 WMConnection*
625 WMAcceptConnection(WMConnection *listener) /*FOLD00*/
627 struct sockaddr_in clientname;
628 int size;
629 int newSock;
630 WMConnection *newConnection;
632 if (listener->state!=WCListening) {
633 wwarning("Called 'WMAcceptConnection()' on a non-listening connection");
634 WCErrorCode = 0;
635 return NULL;
638 size = sizeof(clientname);
639 newSock = accept(listener->sock, (struct sockaddr*) &clientname, &size);
640 if (newSock<0) {
641 if (errno!=EAGAIN && errno!=EWOULDBLOCK) {
642 WCErrorCode = errno;
643 wsyserror("Could not accept connection");
644 } else {
645 WCErrorCode = 0;
647 return NULL;
650 newConnection = createConnectionWithSocket(newSock, True);
651 WMSetConnectionNonBlocking(newConnection, True);
652 newConnection->state = WCConnected;
653 setConnectionAddress(newConnection, &clientname);
655 return newConnection;
659 char*
660 WMGetConnectionAddress(WMConnection *cPtr) /*FOLD00*/
662 return cPtr->address;
666 char*
667 WMGetConnectionService(WMConnection *cPtr) /*FOLD00*/
669 return cPtr->service;
673 char*
674 WMGetConnectionProtocol(WMConnection *cPtr)
676 return cPtr->protocol;
681 WMGetConnectionSocket(WMConnection *cPtr) /*FOLD00*/
683 return cPtr->sock;
687 WMConnectionState
688 WMGetConnectionState(WMConnection *cPtr) /*FOLD00*/
690 return cPtr->state;
694 Bool
695 WMEnqueueConnectionData(WMConnection *cPtr, WMData *data) /*FOLD00*/
697 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, False);
698 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, False);
700 if (cPtr->state!=WCConnected)
701 return False;
703 WMPutInBag(cPtr->outputQueue, WMRetainData(data));
704 return True;
709 WMSendConnectionData(WMConnection *cPtr, WMData *data) /*FOLD00*/
711 int bytes, pos, len, totalTransfer;
712 TimeoutData *tPtr = &cPtr->sendTimeout;
713 const unsigned char *dataBytes;
715 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, -1);
716 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, -1);
718 if (cPtr->state!=WCConnected)
719 return -1;
721 /* If we have no data just flush the queue, else try to send data */
722 if (data && WMGetDataLength(data)>0) {
723 WMPutInBag(cPtr->outputQueue, WMRetainData(data));
724 /* If there already was something in queue, and also a write input
725 * handler is established, it means we were unable to send, so
726 * return and let the write handler notify us when we can send.
728 if (WMGetBagItemCount(cPtr->outputQueue)>1 && cPtr->handler.write)
729 return 0;
732 totalTransfer = 0;
734 while (WMGetBagItemCount(cPtr->outputQueue) > 0) {
735 data = WMGetFromBag(cPtr->outputQueue, 0);
736 dataBytes = (const unsigned char *)WMDataBytes(data);
737 len = WMGetDataLength(data);
738 pos = cPtr->bufPos; /* where we're left last time */
739 while(pos < len) {
740 again:
741 bytes = write(cPtr->sock, dataBytes+pos, len - pos);
742 if(bytes<0) {
743 switch (errno) {
744 case EINTR:
745 goto again;
746 case EWOULDBLOCK:
747 /* save the position where we're left and add a timeout */
748 cPtr->bufPos = pos;
749 if (!tPtr->handler) {
750 tPtr->handler = WMAddTimerHandler(tPtr->timeout*1000,
751 sendTimeout, cPtr);
753 if (!cPtr->handler.write) {
754 cPtr->handler.write =
755 WMAddInputHandler(cPtr->sock, WIWriteMask,
756 inputHandler, cPtr);
758 return totalTransfer;
759 default:
760 WCErrorCode = errno;
761 cPtr->state = WCDied;
762 /*clearOutputQueue(cPtr);*/
763 removeAllHandlers(cPtr);
764 if (cPtr->delegate && cPtr->delegate->didDie)
765 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
766 return -1;
769 pos += bytes;
770 totalTransfer += bytes;
772 WMReleaseData(data);
773 WMDeleteFromBag(cPtr->outputQueue, 0);
774 cPtr->bufPos = 0;
775 if (tPtr->handler) {
776 WMDeleteTimerHandler(tPtr->handler);
777 tPtr->handler = NULL;
779 if (cPtr->handler.write) {
780 WMDeleteInputHandler(cPtr->handler.write);
781 cPtr->handler.write = NULL;
785 return totalTransfer;
790 * WMGetConnectionAvailableData(connection):
792 * will return a WMData structure containing the available data on the
793 * specified connection. If connection is non-blocking (default) and no data
794 * is available when this function is called, an empty WMData is returned.
796 * If an error occurs while reading or the other side closed connection,
797 * it will return NULL.
798 * Also trying to read from an already died or closed connection is
799 * considered to be an error condition, and will return NULL.
801 WMData*
802 WMGetConnectionAvailableData(WMConnection *cPtr) /*FOLD00*/
804 char buffer[NETBUF_SIZE];
805 int nbytes;
806 WMData *aData;
808 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, NULL);
809 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, NULL);
811 if (cPtr->state!=WCConnected)
812 return NULL;
814 aData = NULL;
816 again:
817 nbytes = read(cPtr->sock, buffer, NETBUF_SIZE);
818 if (nbytes<0) {
819 switch (errno) {
820 case EINTR:
821 goto again;
822 case EWOULDBLOCK:
823 aData = WMCreateDataWithCapacity(0);
824 break;
825 default:
826 WCErrorCode = errno;
827 cPtr->state = WCDied;
828 removeAllHandlers(cPtr);
829 if (cPtr->delegate && cPtr->delegate->didDie)
830 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
831 break;
833 } else if (nbytes==0) { /* the other side has closed connection */
834 cPtr->state = WCClosed;
835 removeAllHandlers(cPtr);
836 if (cPtr->delegate && cPtr->delegate->didDie)
837 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
838 } else {
839 aData = WMCreateDataWithBytes(buffer, nbytes);
842 return aData;
846 void
847 WMSetConnectionDelegate(WMConnection *cPtr, ConnectionDelegate *delegate) /*FOLD00*/
849 wassertr(cPtr->sock >= 0);
850 /* Don't try to set the delegate multiple times */
851 wassertr(cPtr->delegate == NULL);
853 cPtr->delegate = delegate;
854 if (delegate && delegate->didReceiveInput && !cPtr->handler.read)
855 cPtr->handler.read = WMAddInputHandler(cPtr->sock, WIReadMask,
856 inputHandler, cPtr);
857 if (delegate && delegate->didCatchException && !cPtr->handler.exception)
858 cPtr->handler.exception = WMAddInputHandler(cPtr->sock, WIExceptMask,
859 inputHandler, cPtr);
863 #if 0
864 Bool
865 WMIsConnectionNonBlocking(WMConnection *cPtr) /*FOLD00*/
867 #if 1
868 int state;
870 state = fcntl(cPtr->sock, F_GETFL, 0);
872 if (state < 0) {
873 wsyserror("Failed to get socket flags with fcntl.");
874 /* If we can't use fcntl on socket, this probably also means we could
875 * not use fcntl to set non-blocking mode, and since a socket defaults
876 * to blocking when created, return False as the best assumption */
877 return False;
880 return ((state & NONBLOCK_OPT)!=0);
881 #else
882 return cPtr->isNonBlocking;
883 #endif
885 #endif
888 void
889 WMSetConnectionNonBlocking(WMConnection *cPtr, Bool flag) /*FOLD00*/
891 if (cPtr->sock < 0)
892 return;
894 if (cPtr->isNonBlocking == flag)
895 return;
897 if (setSocketNonBlocking(cPtr->sock, flag)==True)
898 cPtr->isNonBlocking = flag;
902 void*
903 WMGetConnectionClientData(WMConnection *cPtr) /*FOLD00*/
905 return cPtr->clientData;
909 void
910 WMSetConnectionClientData(WMConnection *cPtr, void *data) /*FOLD00*/
912 cPtr->clientData = data;
916 unsigned int
917 WMGetConnectionFlags(WMConnection *cPtr) /*FOLD00*/
919 return cPtr->uflags;
923 void
924 WMSetConnectionFlags(WMConnection *cPtr, unsigned int flags) /*FOLD00*/
926 cPtr->uflags = flags;
930 void
931 WMSetConnectionSendTimeout(WMConnection *cPtr, unsigned int timeout) /*FOLD00*/
933 if (timeout == 0)
934 timeout = DEF_TIMEOUT;
936 cPtr->sendTimeout.timeout = timeout;