Added 3 new classes: WMData, WMHost, WMConnection
[wmaker-crm.git] / WINGs / connection.c
blob1bd76d5d49e2ccaa07961e7fd09822dba3242786
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.
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <stdarg.h>
35 #include <errno.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
39 #include <netdb.h>
40 #include <signal.h>
41 #ifdef __FreeBSD__
42 #include <sys/signal.h>
43 #endif
45 #include "WINGs.h"
48 /* Some older systems does not define this (linux libc5, maybe others too) */
49 #ifndef SHUT_RDWR
50 # define SHUT_RDWR 2
51 #endif
53 /* for SunOS */
54 #ifndef SA_RESTART
55 # define SA_RESTART 0
56 #endif
58 /* Stuff for setting the sockets into non-blocking mode. */
59 #ifdef __POSIX_SOURCE
60 # define NONBLOCK_OPT O_NONBLOCK
61 #else
62 # define NONBLOCK_OPT FNDELAY
63 #endif
66 #define NETBUF_SIZE 4096
69 #define DEF_TIMEOUT 600 /* 600 seconds == 10 minutes */
72 int WCErrorCode = 0;
76 static Bool SigInitialized = False;
80 typedef struct TimeoutData {
81 unsigned timeout;
82 WMHandlerID *handler;
83 } TimeoutData;
87 typedef struct W_Connection {
88 int sock; /* the socket we speak through */
90 struct {
91 WMHandlerID *read; /* the input read handler */
92 WMHandlerID *write; /* the input write handler */
93 WMHandlerID *exception; /* the input exception handler */
94 } handler;
96 ConnectionDelegate *delegate; /* client delegates */
97 void *clientData; /* client data */
98 unsigned int uflags; /* flags for the client */
100 WMBag *outputQueue;
101 unsigned bufPos;
103 TimeoutData sendTimeout;
105 WMConnectionState state;
107 char *address;
108 char *service;
109 char *protocol;
111 Bool closeOnRelease;
112 Bool wasNonBlocking;
113 Bool isNonBlocking;
115 } W_Connection;
120 static void
121 clearOutputQueue(WMConnection *cPtr) /*FOLD00*/
123 int i;
125 cPtr->bufPos = 0;
127 for (i=0; i<WMGetBagItemCount(cPtr->outputQueue); i++)
128 WMReleaseData(WMGetFromBag(cPtr->outputQueue, i));
130 WMEmptyBag(cPtr->outputQueue);
134 static void
135 sendTimeout(void *cdata) /*FOLD00*/
137 WMConnection *cPtr = (WMConnection*) cdata;
138 TimeoutData *tPtr = &cPtr->sendTimeout;
140 tPtr->handler = NULL;
141 if (cPtr->handler.write) {
142 WMDeleteInputHandler(cPtr->handler.write);
143 cPtr->handler.write = NULL;
145 if (WMGetBagItemCount(cPtr->outputQueue)>0) {
146 clearOutputQueue(cPtr);
147 if (cPtr->delegate && cPtr->delegate->didTimeout)
148 (*cPtr->delegate->didTimeout)(cPtr->delegate, cPtr);
153 static void
154 inputHandler(int fd, int mask, void *clientData) /*FOLD00*/
156 WMConnection *cPtr = (WMConnection*)clientData;
158 if (cPtr->state==WCClosed || cPtr->state==WCDied)
159 return;
161 if ((mask & WIWriteMask)) {
162 if (cPtr->state == WCInProgress) {
163 int result;
164 int len = sizeof(result);
166 if (getsockopt(cPtr->sock, SOL_SOCKET, SO_ERROR,
167 (void*)&result, &len) == 0 && result != 0) {
168 cPtr->state = WCFailed;
169 WCErrorCode = result;
170 } else {
171 cPtr->state = WCConnected;
174 if (cPtr->handler.write) {
175 WMDeleteInputHandler(cPtr->handler.write);
176 cPtr->handler.write = NULL;
179 if (cPtr->delegate && cPtr->delegate->didInitialize)
180 (*cPtr->delegate->didInitialize)(cPtr->delegate, cPtr);
182 if (cPtr->state == WCFailed)
183 return;
184 } else if (cPtr->state == WCConnected) {
185 WMFlushConnection(cPtr);
189 if (!cPtr->delegate)
190 return;
192 /* if the connection died, may get destroyed in the delegate, so retain */
193 wretain(cPtr);
195 if ((mask & WIReadMask) && cPtr->delegate->didReceiveInput)
196 (*cPtr->delegate->didReceiveInput)(cPtr->delegate, cPtr);
198 if ((mask & WIExceptMask) && cPtr->delegate->didCatchException)
199 (*cPtr->delegate->didCatchException)(cPtr->delegate, cPtr);
201 wrelease(cPtr);
205 static Bool
206 setSocketNonBlocking(int sock, Bool flag) /*FOLD00*/
208 int state;
209 Bool isNonBlock;
211 state = fcntl(sock, F_GETFL, 0);
213 if (state < 0) {
214 wsyserror("Failed to get socket flags with fcntl.");
215 return False;
218 isNonBlock = (state & NONBLOCK_OPT) != 0;
220 if (flag) {
221 if (isNonBlock)
222 return True;
223 state |= NONBLOCK_OPT;
224 } else {
225 if (!isNonBlock)
226 return True;
227 state &= ~NONBLOCK_OPT;
230 if (fcntl(sock, F_SETFL, state) < 0) {
231 wsyserror("Failed to set socket flags with fcntl.");
232 return False;
235 return True;
239 static void
240 setConnectionAddress(WMConnection *cPtr, struct sockaddr_in *socketaddr) /*FOLD00*/
242 wassertr(cPtr->address==NULL);
244 cPtr->address = wstrdup(inet_ntoa(socketaddr->sin_addr));
245 cPtr->service = wmalloc(16);
246 sprintf(cPtr->service, "%hu", ntohs(socketaddr->sin_port));
247 cPtr->protocol = wstrdup("tcp");
251 static struct sockaddr_in*
252 getSocketAddress(char* name, char* service, char* protocol) /*FOLD00*/
254 static struct sockaddr_in socketaddr;
255 struct servent *sp;
257 if (!protocol || protocol[0]=='\0')
258 protocol = "tcp";
260 memset(&socketaddr, 0, sizeof(struct sockaddr_in));
261 socketaddr.sin_family = AF_INET;
264 * If we were given a hostname, we use any address for that host.
265 * Otherwise we expect the given name to be an address unless it is
266 * NULL (any address).
268 if (name && name[0]!='\0') {
269 WMHost *host = WMGetHostWithName(name);
271 if (!host)
272 return NULL; /* name is not a hostname nor a number and dot adr */
274 name = WMGetHostAddress(host);
275 if (inet_aton(name, &socketaddr.sin_addr) == 0) {
276 WMReleaseHost(host);
277 return NULL;
279 WMReleaseHost(host);
280 } else {
281 socketaddr.sin_addr.s_addr = htonl(INADDR_ANY);
284 if (!service || service[0]=='\0') {
285 socketaddr.sin_port = 0;
286 } else if ((sp = getservbyname(service, protocol))==0) {
287 char *endptr;
288 unsigned portNumber;
290 portNumber = strtoul(service, &endptr, 10);
292 if (service[0]!='\0' && *endptr=='\0' && portNumber<65536) {
293 socketaddr.sin_port = htons(portNumber);
294 } else {
295 return NULL;
297 } else {
298 socketaddr.sin_port = sp->s_port;
301 return &socketaddr;
305 static WMConnection*
306 createConnectionWithSocket(int sock, Bool closeOnRelease) /*FOLD00*/
308 WMConnection *cPtr;
309 struct sigaction sig_action;
311 cPtr = wmalloc(sizeof(WMConnection));
312 wretain(cPtr);
313 memset(cPtr, 0, sizeof(WMConnection));
315 cPtr->sock = sock;
316 cPtr->sendTimeout.timeout = DEF_TIMEOUT;
317 cPtr->sendTimeout.handler = NULL;
318 cPtr->closeOnRelease = closeOnRelease;
319 cPtr->outputQueue = WMCreateBag(16);
320 cPtr->state = WCNotConnected;
322 /* ignore dead pipe */
323 if (!SigInitialized) {
324 sig_action.sa_handler = SIG_IGN;
325 sig_action.sa_flags = SA_RESTART;
326 sigaction(SIGPIPE, &sig_action, NULL);
327 SigInitialized = True;
330 return cPtr;
334 #if 0
335 WMConnection*
336 WMCreateConnectionWithSocket(int sock, Bool closeOnRelease) /*FOLD00*/
338 WMConnection *cPtr;
339 struct sockaddr_in clientname;
340 int size, n;
342 cPtr = createConnectionWithSocket(sock, closeOnRelease);
343 cPtr->wasNonBlocking = WMIsConnectionNonBlocking(cPtr);
344 cPtr->isNonBlocking = cPtr->wasNonBlocking;
346 // some way to find out if it is connected, and binded. can't find
347 // if it listens though!!!
349 size = sizeof(clientname);
350 n = getpeername(sock, (struct sockaddr*) &clientname, &size);
351 if (n==0) {
352 /* Since we have a peer, it means we are connected */
353 cPtr->state = WCConnected;
354 } else {
355 size = sizeof(clientname);
356 n = getsockname(sock, (struct sockaddr*) &clientname, &size);
357 if (n==0) {
358 /* We don't have a peer, but we are binded to an address.
359 * Assume we are listening on it (we don't know that for sure!)
361 cPtr->state = WCListening;
362 } else {
363 cPtr->state = WCNotConnected;
367 return cPtr;
369 #endif
373 * host is the name on which we want to listen for incoming connections,
374 * and it must be a name of this host, or NULL if we want to listen
375 * on any incoming address.
376 * service is either a service name as present in /etc/services, or the port
377 * number we want to listen on. If NULL, a random port between
378 * 1024 and 65535 will be assigned to us.
379 * protocol is one of "tcp" or "udp". If NULL, "tcp" will be used by default.
380 * currently only "tcp" is supported.
382 WMConnection*
383 WMCreateConnectionAsServerAtAddress(char *host, char *service, char *protocol) /*FOLD00*/
385 WMConnection *cPtr;
386 struct sockaddr_in *socketaddr;
387 int sock, size, on;
389 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
390 WCErrorCode = 0;
391 wwarning("Bad address-service-protocol combination");
392 return NULL;
395 /* Create the actual socket */
396 sock = socket(PF_INET, SOCK_STREAM, 0);
397 if (sock<0) {
398 WCErrorCode = errno;
399 wsyserror("Unable to create socket");
400 return NULL;
404 * Set socket options. We try to make the port reusable and have it
405 * close as fast as possible without waiting in unnecessary wait states
406 * on close.
408 on = 1;
409 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
411 if (bind(sock, (struct sockaddr *)socketaddr, sizeof(*socketaddr)) < 0) {
412 WCErrorCode = errno;
413 wsyserror("Unable to bind to address '%s:%hu'",
414 inet_ntoa(socketaddr->sin_addr),
415 ntohs(socketaddr->sin_port));
416 close(sock);
417 return NULL;
420 if (listen(sock, 10) < 0) {
421 WCErrorCode = errno;
422 wsyserror("Unable to listen on port '%hu'",
423 ntohs(socketaddr->sin_port));
424 close(sock);
425 return NULL;
428 /* Find out what is the address/service/protocol we get */
429 /* In case some of address/service/protocol were NULL */
430 size = sizeof(*socketaddr);
431 if (getsockname(sock, (struct sockaddr*)socketaddr, &size) < 0) {
432 WCErrorCode = errno;
433 wsyserror("Unable to get socket address");
434 close(sock);
435 return NULL;
438 cPtr = createConnectionWithSocket(sock, True);
439 cPtr->state = WCListening;
440 WMSetConnectionNonBlocking(cPtr, True);
442 setConnectionAddress(cPtr, socketaddr);
444 return cPtr;
448 WMConnection*
449 WMCreateConnectionToAddress(char *host, char *service, char *protocol) /*FOLD00*/
451 WMConnection *cPtr;
452 struct sockaddr_in *socketaddr;
453 int sock;
455 if (service==NULL || service[0]=='\0') {
456 WCErrorCode = 0;
457 wwarning("Bad argument - service is not specified");
458 return NULL;
461 if (host==NULL || host[0]=='\0')
462 host = "localhost";
464 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
465 WCErrorCode = 0;
466 wwarning("Bad address-service-protocol combination");
467 return NULL;
470 /* Create the actual socket */
471 sock = socket(PF_INET, SOCK_STREAM, 0);
472 if (sock<0) {
473 WCErrorCode = errno;
474 wsyserror("Unable to create socket");
475 return NULL;
477 /* make socket blocking while we connect. */
478 setSocketNonBlocking(sock, False);
479 if (connect(sock, (struct sockaddr*)socketaddr, sizeof(*socketaddr)) < 0) {
480 WCErrorCode = errno;
481 wsyserror("Unable to make connection to address '%s:%hu'",
482 inet_ntoa(socketaddr->sin_addr),
483 ntohs(socketaddr->sin_port));
484 close(sock);
485 return NULL;
488 cPtr = createConnectionWithSocket(sock, True);
489 cPtr->state = WCConnected;
490 WMSetConnectionNonBlocking(cPtr, True);
491 setConnectionAddress(cPtr, socketaddr);
493 return cPtr;
497 WMConnection*
498 WMCreateConnectionToAddressAndNotify(char *host, char *service, char *protocol) /*FOLD00*/
500 WMConnection *cPtr;
501 /*TimeoutData *tPtr;*/
502 struct sockaddr_in *socketaddr;
503 int sock;
504 Bool isNonBlocking;
506 if (service==NULL || service[0]=='\0') {
507 WCErrorCode = 0;
508 wwarning("Bad argument - service is not specified");
509 return NULL;
512 if (host==NULL || host[0]=='\0')
513 host = "localhost";
515 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
516 WCErrorCode = 0;
517 wwarning("Bad address-service-protocol combination");
518 return NULL;
521 /* Create the actual socket */
522 sock = socket(PF_INET, SOCK_STREAM, 0);
523 if (sock<0) {
524 WCErrorCode = errno;
525 wsyserror("Unable to create socket");
526 return NULL;
528 isNonBlocking = setSocketNonBlocking(sock, True);
529 if (connect(sock, (struct sockaddr*)socketaddr, sizeof(*socketaddr)) < 0) {
530 if (errno!=EINPROGRESS) {
531 WCErrorCode = errno;
532 wsyserror("Unable to make connection to address '%s:%hu'",
533 inet_ntoa(socketaddr->sin_addr),
534 ntohs(socketaddr->sin_port));
535 close(sock);
536 return NULL;
540 cPtr = createConnectionWithSocket(sock, True);
541 cPtr->state = WCInProgress;
542 cPtr->isNonBlocking = isNonBlocking;
544 /*tPtr = &cPtr->sendTimeout;
545 tPtr->handler = WMAddTimerHandler(tPtr->timeout*1000, connectTimeout, cPtr);
547 cPtr->handler.write = WMAddInputHandler(cPtr->sock, WIWriteMask,
548 inputHandler, cPtr);
550 setConnectionAddress(cPtr, socketaddr);
552 return cPtr;
556 static void
557 removeAllHandlers(WMConnection *cPtr) /*FOLD00*/
559 if (cPtr->handler.read)
560 WMDeleteInputHandler(cPtr->handler.read);
561 if (cPtr->handler.write)
562 WMDeleteInputHandler(cPtr->handler.write);
563 if (cPtr->handler.exception)
564 WMDeleteInputHandler(cPtr->handler.exception);
565 if (cPtr->sendTimeout.handler)
566 WMDeleteTimerHandler(cPtr->sendTimeout.handler);
568 cPtr->handler.read = NULL;
569 cPtr->handler.write = NULL;
570 cPtr->handler.exception = NULL;
571 cPtr->sendTimeout.handler = NULL;
575 void
576 WMDestroyConnection(WMConnection *cPtr) /*FOLD00*/
578 if (cPtr->closeOnRelease && cPtr->sock>=0) {
579 shutdown(cPtr->sock, SHUT_RDWR);
580 close(cPtr->sock);
583 removeAllHandlers(cPtr);
584 clearOutputQueue(cPtr);
585 WMFreeBag(cPtr->outputQueue);
587 if (cPtr->address) {
588 wfree(cPtr->address);
589 wfree(cPtr->service);
590 wfree(cPtr->protocol);
593 wrelease(cPtr);
597 void
598 WMCloseConnection(WMConnection *cPtr) /*FOLD00*/
600 if (cPtr->sock>=0) {
601 shutdown(cPtr->sock, SHUT_RDWR);
602 close(cPtr->sock);
603 cPtr->sock = -1;
606 removeAllHandlers(cPtr);
607 clearOutputQueue(cPtr);
609 cPtr->state = WCClosed;
613 WMConnection*
614 WMAcceptConnection(WMConnection *listener) /*FOLD00*/
616 struct sockaddr_in clientname;
617 int size;
618 int newSock;
619 WMConnection *newConnection;
621 if (listener->state!=WCListening) {
622 wwarning("Called 'WMAcceptConnection()' on a non-listening connection");
623 WCErrorCode = 0;
624 return NULL;
627 size = sizeof(clientname);
628 newSock = accept(listener->sock, (struct sockaddr*) &clientname, &size);
629 if (newSock<0) {
630 if (errno!=EAGAIN && errno!=EWOULDBLOCK) {
631 WCErrorCode = errno;
632 wsyserror("Could not accept connection");
633 } else {
634 WCErrorCode = 0;
636 return NULL;
639 newConnection = createConnectionWithSocket(newSock, True);
640 WMSetConnectionNonBlocking(newConnection, True);
641 newConnection->state = WCConnected;
642 setConnectionAddress(newConnection, &clientname);
644 return newConnection;
648 char*
649 WMGetConnectionAddress(WMConnection *cPtr) /*FOLD00*/
651 return cPtr->address;
655 char*
656 WMGetConnectionService(WMConnection *cPtr) /*FOLD00*/
658 return cPtr->service;
662 char*
663 WMGetConnectionProtocol(WMConnection *cPtr)
665 return cPtr->protocol;
670 WMGetConnectionSocket(WMConnection *cPtr) /*FOLD00*/
672 return cPtr->sock;
676 WMConnectionState
677 WMGetConnectionState(WMConnection *cPtr) /*FOLD00*/
679 return cPtr->state;
683 Bool
684 WMEnqueueConnectionData(WMConnection *cPtr, WMData *data) /*FOLD00*/
686 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, False);
687 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, False);
689 if (cPtr->state!=WCConnected)
690 return False;
692 WMPutInBag(cPtr->outputQueue, WMRetainData(data));
693 return True;
698 WMSendConnectionData(WMConnection *cPtr, WMData *data) /*FOLD00*/
700 int bytes, pos, len, totalTransfer;
701 TimeoutData *tPtr = &cPtr->sendTimeout;
702 const void *dataBytes;
704 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, -1);
705 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, -1);
707 if (cPtr->state!=WCConnected)
708 return -1;
710 /* If we have no data just flush the queue, else try to send data */
711 if (data && WMGetDataLength(data)>0) {
712 WMPutInBag(cPtr->outputQueue, WMRetainData(data));
713 /* If there already was something in queue, and also a write input
714 * handler is established, it means we were unable to send, so
715 * return and let the write handler notify us when we can send.
717 if (WMGetBagItemCount(cPtr->outputQueue)>1 && cPtr->handler.write)
718 return 0;
721 totalTransfer = 0;
723 while (WMGetBagItemCount(cPtr->outputQueue) > 0) {
724 data = WMGetFromBag(cPtr->outputQueue, 0);
725 dataBytes = WMDataBytes(data);
726 len = WMGetDataLength(data);
727 pos = cPtr->bufPos; /* where we're left last time */
728 while(pos < len) {
729 again:
730 bytes = write(cPtr->sock, dataBytes+pos, len - pos);
731 if(bytes<0) {
732 switch (errno) {
733 case EINTR:
734 goto again;
735 case EWOULDBLOCK:
736 /* save the position where we're left and add a timeout */
737 cPtr->bufPos = pos;
738 if (!tPtr->handler) {
739 tPtr->handler = WMAddTimerHandler(tPtr->timeout*1000,
740 sendTimeout, cPtr);
742 if (!cPtr->handler.write) {
743 cPtr->handler.write =
744 WMAddInputHandler(cPtr->sock, WIWriteMask,
745 inputHandler, cPtr);
747 return totalTransfer;
748 default:
749 WCErrorCode = errno;
750 cPtr->state = WCDied;
751 /*clearOutputQueue(cPtr);*/
752 removeAllHandlers(cPtr);
753 if (cPtr->delegate && cPtr->delegate->didDie)
754 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
755 return -1;
758 pos += bytes;
759 totalTransfer += bytes;
761 WMReleaseData(data);
762 WMDeleteFromBag(cPtr->outputQueue, 0);
763 cPtr->bufPos = 0;
764 if (tPtr->handler) {
765 WMDeleteTimerHandler(tPtr->handler);
766 tPtr->handler = NULL;
768 if (cPtr->handler.write) {
769 WMDeleteInputHandler(cPtr->handler.write);
770 cPtr->handler.write = NULL;
774 return totalTransfer;
779 * WMGetConnectionAvailableData(connection):
781 * will return a WMData structure containing the available data on the
782 * specified connection. If connection is non-blocking (default) and no data
783 * is available when this function is called, an empty WMData is returned.
785 * If an error occurs while reading or the other side closed connection,
786 * it will return NULL.
787 * Also trying to read from an already died or closed connection is
788 * considered to be an error condition, and will return NULL.
790 WMData*
791 WMGetConnectionAvailableData(WMConnection *cPtr) /*FOLD00*/
793 char buffer[NETBUF_SIZE];
794 int nbytes;
795 WMData *aData;
797 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, NULL);
798 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, NULL);
800 if (cPtr->state!=WCConnected)
801 return NULL;
803 aData = NULL;
805 again:
806 nbytes = read(cPtr->sock, buffer, NETBUF_SIZE);
807 if (nbytes<0) {
808 switch (errno) {
809 case EINTR:
810 goto again;
811 case EWOULDBLOCK:
812 aData = WMCreateDataWithCapacity(0);
813 break;
814 default:
815 WCErrorCode = errno;
816 cPtr->state = WCDied;
817 removeAllHandlers(cPtr);
818 if (cPtr->delegate && cPtr->delegate->didDie)
819 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
820 break;
822 } else if (nbytes==0) { /* the other side has closed connection */
823 cPtr->state = WCClosed;
824 removeAllHandlers(cPtr);
825 if (cPtr->delegate && cPtr->delegate->didDie)
826 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
827 } else {
828 aData = WMCreateDataWithBytes(buffer, nbytes);
831 return aData;
835 void
836 WMSetConnectionDelegate(WMConnection *cPtr, ConnectionDelegate *delegate) /*FOLD00*/
838 wassertr(cPtr->sock >= 0);
839 /* Don't try to set the delegate multiple times */
840 wassertr(cPtr->delegate == NULL);
842 cPtr->delegate = delegate;
843 if (delegate && delegate->didReceiveInput && !cPtr->handler.read)
844 cPtr->handler.read = WMAddInputHandler(cPtr->sock, WIReadMask,
845 inputHandler, cPtr);
846 if (delegate && delegate->didCatchException && !cPtr->handler.exception)
847 cPtr->handler.exception = WMAddInputHandler(cPtr->sock, WIExceptMask,
848 inputHandler, cPtr);
852 #if 0
853 Bool
854 WMIsConnectionNonBlocking(WMConnection *cPtr) /*FOLD00*/
856 #if 1
857 int state;
859 state = fcntl(cPtr->sock, F_GETFL, 0);
861 if (state < 0) {
862 wsyserror("Failed to get socket flags with fcntl.");
863 /* If we can't use fcntl on socket, this probably also means we could
864 * not use fcntl to set non-blocking mode, and since a socket defaults
865 * to blocking when created, return False as the best assumption */
866 return False;
869 return ((state & NONBLOCK_OPT)!=0);
870 #else
871 return cPtr->isNonBlocking;
872 #endif
874 #endif
877 void
878 WMSetConnectionNonBlocking(WMConnection *cPtr, Bool flag) /*FOLD00*/
880 if (cPtr->sock < 0)
881 return;
883 if (cPtr->isNonBlocking == flag)
884 return;
886 if (setSocketNonBlocking(cPtr->sock, flag)==True)
887 cPtr->isNonBlocking = flag;
891 void*
892 WMGetConnectionClientData(WMConnection *cPtr) /*FOLD00*/
894 return cPtr->clientData;
898 void
899 WMSetConnectionClientData(WMConnection *cPtr, void *data) /*FOLD00*/
901 cPtr->clientData = data;
905 unsigned int
906 WMGetConnectionFlags(WMConnection *cPtr) /*FOLD00*/
908 return cPtr->uflags;
912 void
913 WMSetConnectionFlags(WMConnection *cPtr, unsigned int flags) /*FOLD00*/
915 cPtr->uflags = flags;
919 void
920 WMSetConnectionSendTimeout(WMConnection *cPtr, unsigned int timeout) /*FOLD00*/
922 if (timeout == 0)
923 timeout = DEF_TIMEOUT;
925 cPtr->sendTimeout.timeout = timeout;