Fixed a platform dependant problem.
[wmaker-crm.git] / WINGs / connection.c
blobbcf2a6827ea768721339f9701c730c1e4a70abea
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*/
65 #define NONBLOCK_OPT O_NONBLOCK
68 #define NETBUF_SIZE 4096
71 #define DEF_TIMEOUT 600 /* 600 seconds == 10 minutes */
74 int WCErrorCode = 0;
78 static Bool SigInitialized = False;
82 typedef struct TimeoutData {
83 unsigned timeout;
84 WMHandlerID *handler;
85 } TimeoutData;
89 typedef struct W_Connection {
90 int sock; /* the socket we speak through */
92 struct {
93 WMHandlerID *read; /* the input read handler */
94 WMHandlerID *write; /* the input write handler */
95 WMHandlerID *exception; /* the input exception handler */
96 } handler;
98 ConnectionDelegate *delegate; /* client delegates */
99 void *clientData; /* client data */
100 unsigned int uflags; /* flags for the client */
102 WMBag *outputQueue;
103 unsigned bufPos;
105 TimeoutData sendTimeout;
107 WMConnectionState state;
109 char *address;
110 char *service;
111 char *protocol;
113 Bool closeOnRelease;
114 Bool wasNonBlocking;
115 Bool isNonBlocking;
117 } W_Connection;
122 static void
123 clearOutputQueue(WMConnection *cPtr) /*FOLD00*/
125 int i;
127 cPtr->bufPos = 0;
129 for (i=0; i<WMGetBagItemCount(cPtr->outputQueue); i++)
130 WMReleaseData(WMGetFromBag(cPtr->outputQueue, i));
132 WMEmptyBag(cPtr->outputQueue);
136 static void
137 sendTimeout(void *cdata) /*FOLD00*/
139 WMConnection *cPtr = (WMConnection*) cdata;
140 TimeoutData *tPtr = &cPtr->sendTimeout;
142 tPtr->handler = NULL;
143 if (cPtr->handler.write) {
144 WMDeleteInputHandler(cPtr->handler.write);
145 cPtr->handler.write = NULL;
147 if (WMGetBagItemCount(cPtr->outputQueue)>0) {
148 clearOutputQueue(cPtr);
149 if (cPtr->delegate && cPtr->delegate->didTimeout)
150 (*cPtr->delegate->didTimeout)(cPtr->delegate, cPtr);
155 static void
156 inputHandler(int fd, int mask, void *clientData) /*FOLD00*/
158 WMConnection *cPtr = (WMConnection*)clientData;
160 if (cPtr->state==WCClosed || cPtr->state==WCDied)
161 return;
163 if ((mask & WIWriteMask)) {
164 if (cPtr->state == WCInProgress) {
165 int result;
166 int len = sizeof(result);
168 if (getsockopt(cPtr->sock, SOL_SOCKET, SO_ERROR,
169 (void*)&result, &len) == 0 && result != 0) {
170 cPtr->state = WCFailed;
171 WCErrorCode = result;
172 } else {
173 cPtr->state = WCConnected;
176 if (cPtr->handler.write) {
177 WMDeleteInputHandler(cPtr->handler.write);
178 cPtr->handler.write = NULL;
181 if (cPtr->delegate && cPtr->delegate->didInitialize)
182 (*cPtr->delegate->didInitialize)(cPtr->delegate, cPtr);
184 if (cPtr->state == WCFailed)
185 return;
186 } else if (cPtr->state == WCConnected) {
187 WMFlushConnection(cPtr);
191 if (!cPtr->delegate)
192 return;
194 /* if the connection died, may get destroyed in the delegate, so retain */
195 wretain(cPtr);
197 if ((mask & WIReadMask) && cPtr->delegate->didReceiveInput)
198 (*cPtr->delegate->didReceiveInput)(cPtr->delegate, cPtr);
200 if ((mask & WIExceptMask) && cPtr->delegate->didCatchException)
201 (*cPtr->delegate->didCatchException)(cPtr->delegate, cPtr);
203 wrelease(cPtr);
207 static Bool
208 setSocketNonBlocking(int sock, Bool flag) /*FOLD00*/
210 int state;
211 Bool isNonBlock;
213 state = fcntl(sock, F_GETFL, 0);
215 if (state < 0) {
216 wsyserror("Failed to get socket flags with fcntl.");
217 return False;
220 isNonBlock = (state & NONBLOCK_OPT) != 0;
222 if (flag) {
223 if (isNonBlock)
224 return True;
225 state |= NONBLOCK_OPT;
226 } else {
227 if (!isNonBlock)
228 return True;
229 state &= ~NONBLOCK_OPT;
232 if (fcntl(sock, F_SETFL, state) < 0) {
233 wsyserror("Failed to set socket flags with fcntl.");
234 return False;
237 return True;
241 static void
242 setConnectionAddress(WMConnection *cPtr, struct sockaddr_in *socketaddr) /*FOLD00*/
244 wassertr(cPtr->address==NULL);
246 cPtr->address = wstrdup(inet_ntoa(socketaddr->sin_addr));
247 cPtr->service = wmalloc(16);
248 sprintf(cPtr->service, "%hu", ntohs(socketaddr->sin_port));
249 cPtr->protocol = wstrdup("tcp");
253 static struct sockaddr_in*
254 getSocketAddress(char* name, char* service, char* protocol) /*FOLD00*/
256 static struct sockaddr_in socketaddr;
257 struct servent *sp;
259 if (!protocol || protocol[0]=='\0')
260 protocol = "tcp";
262 memset(&socketaddr, 0, sizeof(struct sockaddr_in));
263 socketaddr.sin_family = AF_INET;
266 * If we were given a hostname, we use any address for that host.
267 * Otherwise we expect the given name to be an address unless it is
268 * NULL (any address).
270 if (name && name[0]!='\0') {
271 WMHost *host = WMGetHostWithName(name);
273 if (!host)
274 return NULL; /* name is not a hostname nor a number and dot adr */
276 name = WMGetHostAddress(host);
277 if (inet_aton(name, &socketaddr.sin_addr) == 0) {
278 WMReleaseHost(host);
279 return NULL;
281 WMReleaseHost(host);
282 } else {
283 socketaddr.sin_addr.s_addr = htonl(INADDR_ANY);
286 if (!service || service[0]=='\0') {
287 socketaddr.sin_port = 0;
288 } else if ((sp = getservbyname(service, protocol))==0) {
289 char *endptr;
290 unsigned portNumber;
292 portNumber = strtoul(service, &endptr, 10);
294 if (service[0]!='\0' && *endptr=='\0' && portNumber<65536) {
295 socketaddr.sin_port = htons(portNumber);
296 } else {
297 return NULL;
299 } else {
300 socketaddr.sin_port = sp->s_port;
303 return &socketaddr;
307 static WMConnection*
308 createConnectionWithSocket(int sock, Bool closeOnRelease) /*FOLD00*/
310 WMConnection *cPtr;
311 struct sigaction sig_action;
313 cPtr = wmalloc(sizeof(WMConnection));
314 wretain(cPtr);
315 memset(cPtr, 0, sizeof(WMConnection));
317 cPtr->sock = sock;
318 cPtr->sendTimeout.timeout = DEF_TIMEOUT;
319 cPtr->sendTimeout.handler = NULL;
320 cPtr->closeOnRelease = closeOnRelease;
321 cPtr->outputQueue = WMCreateBag(16);
322 cPtr->state = WCNotConnected;
324 /* ignore dead pipe */
325 if (!SigInitialized) {
326 sig_action.sa_handler = SIG_IGN;
327 sig_action.sa_flags = SA_RESTART;
328 sigaction(SIGPIPE, &sig_action, NULL);
329 SigInitialized = True;
332 return cPtr;
336 #if 0
337 WMConnection*
338 WMCreateConnectionWithSocket(int sock, Bool closeOnRelease) /*FOLD00*/
340 WMConnection *cPtr;
341 struct sockaddr_in clientname;
342 int size, n;
344 cPtr = createConnectionWithSocket(sock, closeOnRelease);
345 cPtr->wasNonBlocking = WMIsConnectionNonBlocking(cPtr);
346 cPtr->isNonBlocking = cPtr->wasNonBlocking;
348 // some way to find out if it is connected, and binded. can't find
349 // if it listens though!!!
351 size = sizeof(clientname);
352 n = getpeername(sock, (struct sockaddr*) &clientname, &size);
353 if (n==0) {
354 /* Since we have a peer, it means we are connected */
355 cPtr->state = WCConnected;
356 } else {
357 size = sizeof(clientname);
358 n = getsockname(sock, (struct sockaddr*) &clientname, &size);
359 if (n==0) {
360 /* We don't have a peer, but we are binded to an address.
361 * Assume we are listening on it (we don't know that for sure!)
363 cPtr->state = WCListening;
364 } else {
365 cPtr->state = WCNotConnected;
369 return cPtr;
371 #endif
375 * host is the name on which we want to listen for incoming connections,
376 * and it must be a name of this host, or NULL if we want to listen
377 * on any incoming address.
378 * service is either a service name as present in /etc/services, or the port
379 * number we want to listen on. If NULL, a random port between
380 * 1024 and 65535 will be assigned to us.
381 * protocol is one of "tcp" or "udp". If NULL, "tcp" will be used by default.
382 * currently only "tcp" is supported.
384 WMConnection*
385 WMCreateConnectionAsServerAtAddress(char *host, char *service, char *protocol) /*FOLD00*/
387 WMConnection *cPtr;
388 struct sockaddr_in *socketaddr;
389 int sock, size, on;
391 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
392 WCErrorCode = 0;
393 wwarning("Bad address-service-protocol combination");
394 return NULL;
397 /* Create the actual socket */
398 sock = socket(PF_INET, SOCK_STREAM, 0);
399 if (sock<0) {
400 WCErrorCode = errno;
401 wsyserror("Unable to create socket");
402 return NULL;
406 * Set socket options. We try to make the port reusable and have it
407 * close as fast as possible without waiting in unnecessary wait states
408 * on close.
410 on = 1;
411 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
413 if (bind(sock, (struct sockaddr *)socketaddr, sizeof(*socketaddr)) < 0) {
414 WCErrorCode = errno;
415 wsyserror("Unable to bind to address '%s:%hu'",
416 inet_ntoa(socketaddr->sin_addr),
417 ntohs(socketaddr->sin_port));
418 close(sock);
419 return NULL;
422 if (listen(sock, 10) < 0) {
423 WCErrorCode = errno;
424 wsyserror("Unable to listen on port '%hu'",
425 ntohs(socketaddr->sin_port));
426 close(sock);
427 return NULL;
430 /* Find out what is the address/service/protocol we get */
431 /* In case some of address/service/protocol were NULL */
432 size = sizeof(*socketaddr);
433 if (getsockname(sock, (struct sockaddr*)socketaddr, &size) < 0) {
434 WCErrorCode = errno;
435 wsyserror("Unable to get socket address");
436 close(sock);
437 return NULL;
440 cPtr = createConnectionWithSocket(sock, True);
441 cPtr->state = WCListening;
442 WMSetConnectionNonBlocking(cPtr, True);
444 setConnectionAddress(cPtr, socketaddr);
446 return cPtr;
450 WMConnection*
451 WMCreateConnectionToAddress(char *host, char *service, char *protocol) /*FOLD00*/
453 WMConnection *cPtr;
454 struct sockaddr_in *socketaddr;
455 int sock;
457 if (service==NULL || service[0]=='\0') {
458 WCErrorCode = 0;
459 wwarning("Bad argument - service is not specified");
460 return NULL;
463 if (host==NULL || host[0]=='\0')
464 host = "localhost";
466 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
467 WCErrorCode = 0;
468 wwarning("Bad address-service-protocol combination");
469 return NULL;
472 /* Create the actual socket */
473 sock = socket(PF_INET, SOCK_STREAM, 0);
474 if (sock<0) {
475 WCErrorCode = errno;
476 wsyserror("Unable to create socket");
477 return NULL;
479 /* make socket blocking while we connect. */
480 setSocketNonBlocking(sock, False);
481 if (connect(sock, (struct sockaddr*)socketaddr, sizeof(*socketaddr)) < 0) {
482 WCErrorCode = errno;
483 wsyserror("Unable to make connection to address '%s:%hu'",
484 inet_ntoa(socketaddr->sin_addr),
485 ntohs(socketaddr->sin_port));
486 close(sock);
487 return NULL;
490 cPtr = createConnectionWithSocket(sock, True);
491 cPtr->state = WCConnected;
492 WMSetConnectionNonBlocking(cPtr, True);
493 setConnectionAddress(cPtr, socketaddr);
495 return cPtr;
499 WMConnection*
500 WMCreateConnectionToAddressAndNotify(char *host, char *service, char *protocol) /*FOLD00*/
502 WMConnection *cPtr;
503 /*TimeoutData *tPtr;*/
504 struct sockaddr_in *socketaddr;
505 int sock;
506 Bool isNonBlocking;
508 if (service==NULL || service[0]=='\0') {
509 WCErrorCode = 0;
510 wwarning("Bad argument - service is not specified");
511 return NULL;
514 if (host==NULL || host[0]=='\0')
515 host = "localhost";
517 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
518 WCErrorCode = 0;
519 wwarning("Bad address-service-protocol combination");
520 return NULL;
523 /* Create the actual socket */
524 sock = socket(PF_INET, SOCK_STREAM, 0);
525 if (sock<0) {
526 WCErrorCode = errno;
527 wsyserror("Unable to create socket");
528 return NULL;
530 isNonBlocking = setSocketNonBlocking(sock, True);
531 if (connect(sock, (struct sockaddr*)socketaddr, sizeof(*socketaddr)) < 0) {
532 if (errno!=EINPROGRESS) {
533 WCErrorCode = errno;
534 wsyserror("Unable to make connection to address '%s:%hu'",
535 inet_ntoa(socketaddr->sin_addr),
536 ntohs(socketaddr->sin_port));
537 close(sock);
538 return NULL;
542 cPtr = createConnectionWithSocket(sock, True);
543 cPtr->state = WCInProgress;
544 cPtr->isNonBlocking = isNonBlocking;
546 /*tPtr = &cPtr->sendTimeout;
547 tPtr->handler = WMAddTimerHandler(tPtr->timeout*1000, connectTimeout, cPtr);
549 cPtr->handler.write = WMAddInputHandler(cPtr->sock, WIWriteMask,
550 inputHandler, cPtr);
552 setConnectionAddress(cPtr, socketaddr);
554 return cPtr;
558 static void
559 removeAllHandlers(WMConnection *cPtr) /*FOLD00*/
561 if (cPtr->handler.read)
562 WMDeleteInputHandler(cPtr->handler.read);
563 if (cPtr->handler.write)
564 WMDeleteInputHandler(cPtr->handler.write);
565 if (cPtr->handler.exception)
566 WMDeleteInputHandler(cPtr->handler.exception);
567 if (cPtr->sendTimeout.handler)
568 WMDeleteTimerHandler(cPtr->sendTimeout.handler);
570 cPtr->handler.read = NULL;
571 cPtr->handler.write = NULL;
572 cPtr->handler.exception = NULL;
573 cPtr->sendTimeout.handler = NULL;
577 void
578 WMDestroyConnection(WMConnection *cPtr) /*FOLD00*/
580 if (cPtr->closeOnRelease && cPtr->sock>=0) {
581 shutdown(cPtr->sock, SHUT_RDWR);
582 close(cPtr->sock);
585 removeAllHandlers(cPtr);
586 clearOutputQueue(cPtr);
587 WMFreeBag(cPtr->outputQueue);
589 if (cPtr->address) {
590 wfree(cPtr->address);
591 wfree(cPtr->service);
592 wfree(cPtr->protocol);
595 wrelease(cPtr);
599 void
600 WMCloseConnection(WMConnection *cPtr) /*FOLD00*/
602 if (cPtr->sock>=0) {
603 shutdown(cPtr->sock, SHUT_RDWR);
604 close(cPtr->sock);
605 cPtr->sock = -1;
608 removeAllHandlers(cPtr);
609 clearOutputQueue(cPtr);
611 cPtr->state = WCClosed;
615 WMConnection*
616 WMAcceptConnection(WMConnection *listener) /*FOLD00*/
618 struct sockaddr_in clientname;
619 int size;
620 int newSock;
621 WMConnection *newConnection;
623 if (listener->state!=WCListening) {
624 wwarning("Called 'WMAcceptConnection()' on a non-listening connection");
625 WCErrorCode = 0;
626 return NULL;
629 size = sizeof(clientname);
630 newSock = accept(listener->sock, (struct sockaddr*) &clientname, &size);
631 if (newSock<0) {
632 if (errno!=EAGAIN && errno!=EWOULDBLOCK) {
633 WCErrorCode = errno;
634 wsyserror("Could not accept connection");
635 } else {
636 WCErrorCode = 0;
638 return NULL;
641 newConnection = createConnectionWithSocket(newSock, True);
642 WMSetConnectionNonBlocking(newConnection, True);
643 newConnection->state = WCConnected;
644 setConnectionAddress(newConnection, &clientname);
646 return newConnection;
650 char*
651 WMGetConnectionAddress(WMConnection *cPtr) /*FOLD00*/
653 return cPtr->address;
657 char*
658 WMGetConnectionService(WMConnection *cPtr) /*FOLD00*/
660 return cPtr->service;
664 char*
665 WMGetConnectionProtocol(WMConnection *cPtr)
667 return cPtr->protocol;
672 WMGetConnectionSocket(WMConnection *cPtr) /*FOLD00*/
674 return cPtr->sock;
678 WMConnectionState
679 WMGetConnectionState(WMConnection *cPtr) /*FOLD00*/
681 return cPtr->state;
685 Bool
686 WMEnqueueConnectionData(WMConnection *cPtr, WMData *data) /*FOLD00*/
688 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, False);
689 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, False);
691 if (cPtr->state!=WCConnected)
692 return False;
694 WMPutInBag(cPtr->outputQueue, WMRetainData(data));
695 return True;
700 WMSendConnectionData(WMConnection *cPtr, WMData *data) /*FOLD00*/
702 int bytes, pos, len, totalTransfer;
703 TimeoutData *tPtr = &cPtr->sendTimeout;
704 const void *dataBytes;
706 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, -1);
707 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, -1);
709 if (cPtr->state!=WCConnected)
710 return -1;
712 /* If we have no data just flush the queue, else try to send data */
713 if (data && WMGetDataLength(data)>0) {
714 WMPutInBag(cPtr->outputQueue, WMRetainData(data));
715 /* If there already was something in queue, and also a write input
716 * handler is established, it means we were unable to send, so
717 * return and let the write handler notify us when we can send.
719 if (WMGetBagItemCount(cPtr->outputQueue)>1 && cPtr->handler.write)
720 return 0;
723 totalTransfer = 0;
725 while (WMGetBagItemCount(cPtr->outputQueue) > 0) {
726 data = WMGetFromBag(cPtr->outputQueue, 0);
727 dataBytes = WMDataBytes(data);
728 len = WMGetDataLength(data);
729 pos = cPtr->bufPos; /* where we're left last time */
730 while(pos < len) {
731 again:
732 bytes = write(cPtr->sock, dataBytes+pos, len - pos);
733 if(bytes<0) {
734 switch (errno) {
735 case EINTR:
736 goto again;
737 case EWOULDBLOCK:
738 /* save the position where we're left and add a timeout */
739 cPtr->bufPos = pos;
740 if (!tPtr->handler) {
741 tPtr->handler = WMAddTimerHandler(tPtr->timeout*1000,
742 sendTimeout, cPtr);
744 if (!cPtr->handler.write) {
745 cPtr->handler.write =
746 WMAddInputHandler(cPtr->sock, WIWriteMask,
747 inputHandler, cPtr);
749 return totalTransfer;
750 default:
751 WCErrorCode = errno;
752 cPtr->state = WCDied;
753 /*clearOutputQueue(cPtr);*/
754 removeAllHandlers(cPtr);
755 if (cPtr->delegate && cPtr->delegate->didDie)
756 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
757 return -1;
760 pos += bytes;
761 totalTransfer += bytes;
763 WMReleaseData(data);
764 WMDeleteFromBag(cPtr->outputQueue, 0);
765 cPtr->bufPos = 0;
766 if (tPtr->handler) {
767 WMDeleteTimerHandler(tPtr->handler);
768 tPtr->handler = NULL;
770 if (cPtr->handler.write) {
771 WMDeleteInputHandler(cPtr->handler.write);
772 cPtr->handler.write = NULL;
776 return totalTransfer;
781 * WMGetConnectionAvailableData(connection):
783 * will return a WMData structure containing the available data on the
784 * specified connection. If connection is non-blocking (default) and no data
785 * is available when this function is called, an empty WMData is returned.
787 * If an error occurs while reading or the other side closed connection,
788 * it will return NULL.
789 * Also trying to read from an already died or closed connection is
790 * considered to be an error condition, and will return NULL.
792 WMData*
793 WMGetConnectionAvailableData(WMConnection *cPtr) /*FOLD00*/
795 char buffer[NETBUF_SIZE];
796 int nbytes;
797 WMData *aData;
799 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, NULL);
800 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, NULL);
802 if (cPtr->state!=WCConnected)
803 return NULL;
805 aData = NULL;
807 again:
808 nbytes = read(cPtr->sock, buffer, NETBUF_SIZE);
809 if (nbytes<0) {
810 switch (errno) {
811 case EINTR:
812 goto again;
813 case EWOULDBLOCK:
814 aData = WMCreateDataWithCapacity(0);
815 break;
816 default:
817 WCErrorCode = errno;
818 cPtr->state = WCDied;
819 removeAllHandlers(cPtr);
820 if (cPtr->delegate && cPtr->delegate->didDie)
821 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
822 break;
824 } else if (nbytes==0) { /* the other side has closed connection */
825 cPtr->state = WCClosed;
826 removeAllHandlers(cPtr);
827 if (cPtr->delegate && cPtr->delegate->didDie)
828 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
829 } else {
830 aData = WMCreateDataWithBytes(buffer, nbytes);
833 return aData;
837 void
838 WMSetConnectionDelegate(WMConnection *cPtr, ConnectionDelegate *delegate) /*FOLD00*/
840 wassertr(cPtr->sock >= 0);
841 /* Don't try to set the delegate multiple times */
842 wassertr(cPtr->delegate == NULL);
844 cPtr->delegate = delegate;
845 if (delegate && delegate->didReceiveInput && !cPtr->handler.read)
846 cPtr->handler.read = WMAddInputHandler(cPtr->sock, WIReadMask,
847 inputHandler, cPtr);
848 if (delegate && delegate->didCatchException && !cPtr->handler.exception)
849 cPtr->handler.exception = WMAddInputHandler(cPtr->sock, WIExceptMask,
850 inputHandler, cPtr);
854 #if 0
855 Bool
856 WMIsConnectionNonBlocking(WMConnection *cPtr) /*FOLD00*/
858 #if 1
859 int state;
861 state = fcntl(cPtr->sock, F_GETFL, 0);
863 if (state < 0) {
864 wsyserror("Failed to get socket flags with fcntl.");
865 /* If we can't use fcntl on socket, this probably also means we could
866 * not use fcntl to set non-blocking mode, and since a socket defaults
867 * to blocking when created, return False as the best assumption */
868 return False;
871 return ((state & NONBLOCK_OPT)!=0);
872 #else
873 return cPtr->isNonBlocking;
874 #endif
876 #endif
879 void
880 WMSetConnectionNonBlocking(WMConnection *cPtr, Bool flag) /*FOLD00*/
882 if (cPtr->sock < 0)
883 return;
885 if (cPtr->isNonBlocking == flag)
886 return;
888 if (setSocketNonBlocking(cPtr->sock, flag)==True)
889 cPtr->isNonBlocking = flag;
893 void*
894 WMGetConnectionClientData(WMConnection *cPtr) /*FOLD00*/
896 return cPtr->clientData;
900 void
901 WMSetConnectionClientData(WMConnection *cPtr, void *data) /*FOLD00*/
903 cPtr->clientData = data;
907 unsigned int
908 WMGetConnectionFlags(WMConnection *cPtr) /*FOLD00*/
910 return cPtr->uflags;
914 void
915 WMSetConnectionFlags(WMConnection *cPtr, unsigned int flags) /*FOLD00*/
917 cPtr->uflags = flags;
921 void
922 WMSetConnectionSendTimeout(WMConnection *cPtr, unsigned int timeout) /*FOLD00*/
924 if (timeout == 0)
925 timeout = DEF_TIMEOUT;
927 cPtr->sendTimeout.timeout = timeout;