- Added WMSetConnectionCloseOnExec() to specify if the socket of a
[wmaker-crm.git] / WINGs / connection.c
blobaaaa9a582b72ed69b7d9fe921f05db360d4952f8
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.
26 * - decide what to do with all wsyserror() and wwarning() calls.
31 #include "../src/config.h"
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <stdarg.h>
39 #include <errno.h>
40 #include <sys/socket.h>
41 #include <netinet/in.h>
42 #include <arpa/inet.h>
43 #include <netdb.h>
44 #include <signal.h>
45 #ifdef __FreeBSD__
46 #include <sys/signal.h>
47 #endif
49 #include "WINGs.h"
52 /* Some older systems does not define this (linux libc5, maybe others too) */
53 #ifndef SHUT_RDWR
54 # define SHUT_RDWR 2
55 #endif
57 /* For SunOS */
58 #ifndef SA_RESTART
59 # define SA_RESTART 0
60 #endif
62 /* For Solaris */
63 #ifndef INADDR_NONE
64 # define INADDR_NONE -1
65 #endif
67 /* Stuff for setting the sockets into non-blocking mode. */
68 /*#ifdef __POSIX_SOURCE
69 # define NONBLOCK_OPT O_NONBLOCK
70 #else
71 # define NONBLOCK_OPT FNDELAY
72 #endif*/
74 #define NONBLOCK_OPT O_NONBLOCK
76 #define NETBUF_SIZE 4096
78 #define DEF_TIMEOUT 600 /* 600 seconds == 10 minutes */
82 int WCErrorCode = 0;
84 static Bool SigInitialized = False;
86 static unsigned int DefaultTimeout = DEF_TIMEOUT;
87 static unsigned int OpenTimeout = DEF_TIMEOUT;
91 typedef struct TimeoutData {
92 unsigned timeout;
93 WMHandlerID *handler;
94 } TimeoutData;
97 typedef struct W_Connection {
98 int sock; /* the socket we speak through */
100 struct {
101 WMHandlerID *read; /* the input read handler */
102 WMHandlerID *write; /* the input write handler */
103 WMHandlerID *exception; /* the input exception handler */
104 } handler;
106 ConnectionDelegate *delegate; /* client delegates */
107 void *clientData; /* client data */
108 unsigned int uflags; /* flags for the client */
110 WMArray *outputQueue;
111 unsigned bufPos;
113 TimeoutData sendTimeout;
114 TimeoutData openTimeout;
116 WMConnectionState state;
117 WMConnectionTimeoutState timeoutState;
119 char *address;
120 char *service;
121 char *protocol;
123 Bool closeOnRelease;
124 Bool wasNonBlocking;
125 Bool isNonBlocking;
127 } W_Connection;
131 static void
132 clearOutputQueue(WMConnection *cPtr) /*FOLD00*/
134 cPtr->bufPos = 0;
135 WMEmptyArray(cPtr->outputQueue);
139 static void
140 openTimeout(void *cdata) /*FOLD00*/
142 WMConnection *cPtr = (WMConnection*) cdata;
144 cPtr->openTimeout.handler = NULL;
145 if (cPtr->handler.write) {
146 WMDeleteInputHandler(cPtr->handler.write);
147 cPtr->handler.write = NULL;
149 if (cPtr->state != WCConnected) {
150 cPtr->state = WCTimedOut;
151 cPtr->timeoutState = WCTWhileOpening;
152 if (cPtr->delegate && cPtr->delegate->didTimeout) {
153 (*cPtr->delegate->didTimeout)(cPtr->delegate, cPtr);
154 } else {
155 WMCloseConnection(cPtr);
156 cPtr->state = WCTimedOut; /* the above set state to WCClosed */
162 static void
163 sendTimeout(void *cdata) /*FOLD00*/
165 WMConnection *cPtr = (WMConnection*) cdata;
167 cPtr->sendTimeout.handler = NULL;
168 if (cPtr->handler.write) {
169 WMDeleteInputHandler(cPtr->handler.write);
170 cPtr->handler.write = NULL;
172 if (WMGetArrayItemCount(cPtr->outputQueue)>0) {
173 clearOutputQueue(cPtr);
174 cPtr->state = WCTimedOut;
175 cPtr->timeoutState = WCTWhileSending;
176 if (cPtr->delegate && cPtr->delegate->didTimeout) {
177 (*cPtr->delegate->didTimeout)(cPtr->delegate, cPtr);
178 } else {
179 WMCloseConnection(cPtr);
180 cPtr->state = WCTimedOut; /* the above set state to WCClosed */
186 static void
187 inputHandler(int fd, int mask, void *clientData) /*FOLD00*/
189 WMConnection *cPtr = (WMConnection*)clientData;
191 if (cPtr->state==WCClosed || cPtr->state==WCDied)
192 return;
194 if ((mask & WIWriteMask)) {
195 if (cPtr->state == WCInProgress) {
196 Bool failed;
197 int result;
198 int len = sizeof(result);
200 if (getsockopt(cPtr->sock, SOL_SOCKET, SO_ERROR,
201 (void*)&result, &len) == 0 && result != 0) {
202 cPtr->state = WCFailed;
203 WCErrorCode = result;
204 failed = True;
205 /* should call wsyserrorwithcode(result, ...) here? */
206 } else {
207 cPtr->state = WCConnected;
208 failed = False;
211 if (cPtr->handler.write) {
212 WMDeleteInputHandler(cPtr->handler.write);
213 cPtr->handler.write = NULL;
216 if (cPtr->openTimeout.handler) {
217 WMDeleteTimerHandler(cPtr->openTimeout.handler);
218 cPtr->openTimeout.handler = NULL;
221 if (cPtr->delegate && cPtr->delegate->didInitialize)
222 (*cPtr->delegate->didInitialize)(cPtr->delegate, cPtr);
224 /* we use failed and not cPtr->state here, because cPtr may be
225 * destroyed by the delegate called above if the connection failed
227 if (failed)
228 return;
229 } else if (cPtr->state == WCConnected) {
230 WMFlushConnection(cPtr);
234 if (!cPtr->delegate)
235 return;
237 /* if the connection died, may get destroyed in the delegate, so retain */
238 wretain(cPtr);
240 if ((mask & WIReadMask) && cPtr->delegate->didReceiveInput)
241 (*cPtr->delegate->didReceiveInput)(cPtr->delegate, cPtr);
243 if ((mask & WIExceptMask) && cPtr->delegate->didCatchException)
244 (*cPtr->delegate->didCatchException)(cPtr->delegate, cPtr);
246 wrelease(cPtr);
250 static Bool
251 setSocketNonBlocking(int sock, Bool flag) /*FOLD00*/
253 int state;
254 Bool isNonBlock;
256 state = fcntl(sock, F_GETFL, 0);
258 if (state < 0) {
259 /*wsyserror("Failed to get socket flags with fcntl."); should we do this? -Dan*/
260 return False;
263 isNonBlock = (state & NONBLOCK_OPT) != 0;
265 if (flag) {
266 if (isNonBlock)
267 return True;
268 state |= NONBLOCK_OPT;
269 } else {
270 if (!isNonBlock)
271 return True;
272 state &= ~NONBLOCK_OPT;
275 if (fcntl(sock, F_SETFL, state) < 0) {
276 /*wsyserror("Failed to set socket flags with fcntl."); should we do this? -Dan */
277 return False;
280 return True;
284 static void
285 setConnectionAddress(WMConnection *cPtr, struct sockaddr_in *socketaddr) /*FOLD00*/
287 wassertr(cPtr->address==NULL);
289 cPtr->address = wstrdup(inet_ntoa(socketaddr->sin_addr));
290 cPtr->service = wmalloc(16);
291 sprintf(cPtr->service, "%hu", ntohs(socketaddr->sin_port));
292 cPtr->protocol = wstrdup("tcp");
296 static struct sockaddr_in*
297 getSocketAddress(char* name, char* service, char* protocol) /*FOLD00*/
299 static struct sockaddr_in socketaddr;
300 struct servent *sp;
302 if (!protocol || protocol[0]=='\0')
303 protocol = "tcp";
305 memset(&socketaddr, 0, sizeof(struct sockaddr_in));
306 socketaddr.sin_family = AF_INET;
309 * If we were given a hostname, we use any address for that host.
310 * Otherwise we expect the given name to be an address unless it is
311 * NULL (any address).
313 if (name && name[0]!='\0') {
314 WMHost *host = WMGetHostWithName(name);
316 if (!host)
317 return NULL; /* name is not a hostname nor a number and dot adr */
319 name = WMGetHostAddress(host);
320 #ifndef HAVE_INET_ATON
321 if ((socketaddr.sin_addr.s_addr = inet_addr(name)) == INADDR_NONE) {
322 #else
323 if (inet_aton(name, &socketaddr.sin_addr) == 0) {
324 #endif
325 WMReleaseHost(host);
326 return NULL;
328 WMReleaseHost(host);
329 } else {
330 socketaddr.sin_addr.s_addr = htonl(INADDR_ANY);
333 if (!service || service[0]=='\0') {
334 socketaddr.sin_port = 0;
335 } else if ((sp = getservbyname(service, protocol))==0) {
336 char *endptr;
337 unsigned portNumber;
339 portNumber = strtoul(service, &endptr, 10);
341 if (service[0]!='\0' && *endptr=='\0' && portNumber<65536) {
342 socketaddr.sin_port = htons(portNumber);
343 } else {
344 return NULL;
346 } else {
347 socketaddr.sin_port = sp->s_port;
350 return &socketaddr;
354 static WMConnection*
355 createConnectionWithSocket(int sock, Bool closeOnRelease) /*FOLD00*/
357 WMConnection *cPtr;
358 struct sigaction sig_action;
360 cPtr = wmalloc(sizeof(WMConnection));
361 wretain(cPtr);
362 memset(cPtr, 0, sizeof(WMConnection));
364 fcntl(sock, F_SETFD, FD_CLOEXEC); /* by default close on exec */
366 cPtr->sock = sock;
367 cPtr->openTimeout.timeout = OpenTimeout;
368 cPtr->openTimeout.handler = NULL;
369 cPtr->sendTimeout.timeout = DefaultTimeout;
370 cPtr->sendTimeout.handler = NULL;
371 cPtr->closeOnRelease = closeOnRelease;
372 cPtr->outputQueue =
373 WMCreateArrayWithDestructor(16, (WMFreeDataProc*)WMReleaseData);
374 cPtr->state = WCNotConnected;
375 cPtr->timeoutState = WCTNone;
377 /* ignore dead pipe */
378 if (!SigInitialized) {
379 sig_action.sa_handler = SIG_IGN;
380 sig_action.sa_flags = SA_RESTART;
381 sigaction(SIGPIPE, &sig_action, NULL);
382 SigInitialized = True;
385 return cPtr;
389 #if 0
390 WMConnection*
391 WMCreateConnectionWithSocket(int sock, Bool closeOnRelease) /*FOLD00*/
393 WMConnection *cPtr;
394 struct sockaddr_in clientname;
395 int size, n;
397 cPtr = createConnectionWithSocket(sock, closeOnRelease);
398 cPtr->wasNonBlocking = WMIsConnectionNonBlocking(cPtr);
399 cPtr->isNonBlocking = cPtr->wasNonBlocking;
401 /* some way to find out if it is connected, and binded. can't find
402 if it listens though!!!
405 size = sizeof(clientname);
406 n = getpeername(sock, (struct sockaddr*) &clientname, &size);
407 if (n==0) {
408 /* Since we have a peer, it means we are connected */
409 cPtr->state = WCConnected;
410 } else {
411 size = sizeof(clientname);
412 n = getsockname(sock, (struct sockaddr*) &clientname, &size);
413 if (n==0) {
414 /* We don't have a peer, but we are binded to an address.
415 * Assume we are listening on it (we don't know that for sure!)
417 cPtr->state = WCListening;
418 } else {
419 cPtr->state = WCNotConnected;
423 return cPtr;
425 #endif
429 * host is the name on which we want to listen for incoming connections,
430 * and it must be a name of this host, or NULL if we want to listen
431 * on any incoming address.
432 * service is either a service name as present in /etc/services, or the port
433 * number we want to listen on. If NULL, a random port between
434 * 1024 and 65535 will be assigned to us.
435 * protocol is one of "tcp" or "udp". If NULL, "tcp" will be used by default.
436 * currently only "tcp" is supported.
438 WMConnection*
439 WMCreateConnectionAsServerAtAddress(char *host, char *service, char *protocol) /*FOLD00*/
441 WMConnection *cPtr;
442 struct sockaddr_in *socketaddr;
443 int sock, size, on;
445 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
446 WCErrorCode = 0;
447 wwarning("Bad address-service-protocol combination");
448 return NULL;
451 /* Create the actual socket */
452 sock = socket(PF_INET, SOCK_STREAM, 0);
453 if (sock<0) {
454 WCErrorCode = errno;
455 wsyserror("Unable to create socket");
456 return NULL;
460 * Set socket options. We try to make the port reusable and have it
461 * close as fast as possible without waiting in unnecessary wait states
462 * on close.
464 on = 1;
465 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
467 if (bind(sock, (struct sockaddr *)socketaddr, sizeof(*socketaddr)) < 0) {
468 WCErrorCode = errno;
469 wsyserror("Unable to bind to address '%s:%hu'",
470 inet_ntoa(socketaddr->sin_addr),
471 ntohs(socketaddr->sin_port));
472 close(sock);
473 return NULL;
476 if (listen(sock, 10) < 0) {
477 WCErrorCode = errno;
478 wsyserror("Unable to listen on port '%hu'",
479 ntohs(socketaddr->sin_port));
480 close(sock);
481 return NULL;
484 /* Find out what is the address/service/protocol we get */
485 /* In case some of address/service/protocol were NULL */
486 size = sizeof(*socketaddr);
487 if (getsockname(sock, (struct sockaddr*)socketaddr, &size) < 0) {
488 WCErrorCode = errno;
489 wsyserror("Unable to get socket address");
490 close(sock);
491 return NULL;
494 cPtr = createConnectionWithSocket(sock, True);
495 cPtr->state = WCListening;
496 WMSetConnectionNonBlocking(cPtr, True);
498 setConnectionAddress(cPtr, socketaddr);
500 return cPtr;
504 WMConnection*
505 WMCreateConnectionToAddress(char *host, char *service, char *protocol) /*FOLD00*/
507 WMConnection *cPtr;
508 struct sockaddr_in *socketaddr;
509 int sock;
511 if (service==NULL || service[0]=='\0') {
512 WCErrorCode = 0;
513 wwarning("Bad argument - service is not specified");
514 return NULL;
517 if (host==NULL || host[0]=='\0')
518 host = "localhost";
520 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
521 WCErrorCode = 0;
522 wwarning("Bad address-service-protocol combination");
523 return NULL;
526 /* Create the actual socket */
527 sock = socket(PF_INET, SOCK_STREAM, 0);
528 if (sock<0) {
529 WCErrorCode = errno;
530 wsyserror("Unable to create socket");
531 return NULL;
533 /* make socket blocking while we connect. */
534 setSocketNonBlocking(sock, False);
535 if (connect(sock, (struct sockaddr*)socketaddr, sizeof(*socketaddr)) < 0) {
536 WCErrorCode = errno;
537 wsyserror("Unable to make connection to address '%s:%hu'",
538 inet_ntoa(socketaddr->sin_addr),
539 ntohs(socketaddr->sin_port));
540 close(sock);
541 return NULL;
544 cPtr = createConnectionWithSocket(sock, True);
545 cPtr->state = WCConnected;
546 WMSetConnectionNonBlocking(cPtr, True);
547 setConnectionAddress(cPtr, socketaddr);
549 return cPtr;
553 WMConnection*
554 WMCreateConnectionToAddressAndNotify(char *host, char *service, char *protocol) /*FOLD00*/
556 WMConnection *cPtr;
557 struct sockaddr_in *socketaddr;
558 int sock;
559 Bool isNonBlocking;
561 if (service==NULL || service[0]=='\0') {
562 WCErrorCode = 0;
563 wwarning("Bad argument - service is not specified");
564 return NULL;
567 if (host==NULL || host[0]=='\0')
568 host = "localhost";
570 if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
571 WCErrorCode = 0;
572 wwarning("Bad address-service-protocol combination");
573 return NULL;
576 /* Create the actual socket */
577 sock = socket(PF_INET, SOCK_STREAM, 0);
578 if (sock<0) {
579 WCErrorCode = errno;
580 wsyserror("Unable to create socket");
581 return NULL;
583 isNonBlocking = setSocketNonBlocking(sock, True);
584 if (connect(sock, (struct sockaddr*)socketaddr, sizeof(*socketaddr)) < 0) {
585 if (errno!=EINPROGRESS) {
586 WCErrorCode = errno;
587 wsyserror("Unable to make connection to address '%s:%hu'",
588 inet_ntoa(socketaddr->sin_addr),
589 ntohs(socketaddr->sin_port));
590 close(sock);
591 return NULL;
595 cPtr = createConnectionWithSocket(sock, True);
596 cPtr->state = WCInProgress;
597 cPtr->isNonBlocking = isNonBlocking;
599 cPtr->handler.write = WMAddInputHandler(cPtr->sock, WIWriteMask,
600 inputHandler, cPtr);
602 cPtr->openTimeout.handler =
603 WMAddTimerHandler(cPtr->openTimeout.timeout*1000, openTimeout, cPtr);
605 setConnectionAddress(cPtr, socketaddr);
607 return cPtr;
611 static void
612 removeAllHandlers(WMConnection *cPtr) /*FOLD00*/
614 if (cPtr->handler.read)
615 WMDeleteInputHandler(cPtr->handler.read);
616 if (cPtr->handler.write)
617 WMDeleteInputHandler(cPtr->handler.write);
618 if (cPtr->handler.exception)
619 WMDeleteInputHandler(cPtr->handler.exception);
620 if (cPtr->openTimeout.handler)
621 WMDeleteTimerHandler(cPtr->openTimeout.handler);
622 if (cPtr->sendTimeout.handler)
623 WMDeleteTimerHandler(cPtr->sendTimeout.handler);
625 cPtr->handler.read = NULL;
626 cPtr->handler.write = NULL;
627 cPtr->handler.exception = NULL;
628 cPtr->openTimeout.handler = NULL;
629 cPtr->sendTimeout.handler = NULL;
633 void
634 WMDestroyConnection(WMConnection *cPtr) /*FOLD00*/
636 if (cPtr->closeOnRelease && cPtr->sock>=0) {
637 shutdown(cPtr->sock, SHUT_RDWR);
638 close(cPtr->sock);
641 removeAllHandlers(cPtr);
642 WMFreeArray(cPtr->outputQueue); /* will also free the items with the destructor */
644 if (cPtr->address) {
645 wfree(cPtr->address);
646 wfree(cPtr->service);
647 wfree(cPtr->protocol);
650 wrelease(cPtr);
654 void
655 WMCloseConnection(WMConnection *cPtr) /*FOLD00*/
657 if (cPtr->sock>=0) {
658 shutdown(cPtr->sock, SHUT_RDWR);
659 close(cPtr->sock);
660 cPtr->sock = -1;
663 removeAllHandlers(cPtr);
664 clearOutputQueue(cPtr);
666 cPtr->state = WCClosed;
670 WMConnection*
671 WMAcceptConnection(WMConnection *listener) /*FOLD00*/
673 struct sockaddr_in clientname;
674 int size;
675 int newSock;
676 WMConnection *newConnection;
678 WCErrorCode = 0;
679 wassertrv(listener && listener->state==WCListening, NULL);
681 size = sizeof(clientname);
682 newSock = accept(listener->sock, (struct sockaddr*) &clientname, &size);
683 if (newSock<0) {
684 if (errno!=EAGAIN && errno!=EWOULDBLOCK) {
685 WCErrorCode = errno;
686 wsyserror("Could not accept connection");
687 } else {
688 WCErrorCode = 0;
690 return NULL;
693 newConnection = createConnectionWithSocket(newSock, True);
694 WMSetConnectionNonBlocking(newConnection, True);
695 newConnection->state = WCConnected;
696 setConnectionAddress(newConnection, &clientname);
698 return newConnection;
702 char*
703 WMGetConnectionAddress(WMConnection *cPtr) /*FOLD00*/
705 return cPtr->address;
709 char*
710 WMGetConnectionService(WMConnection *cPtr) /*FOLD00*/
712 return cPtr->service;
716 char*
717 WMGetConnectionProtocol(WMConnection *cPtr) /*FOLD00*/
719 return cPtr->protocol;
724 WMGetConnectionSocket(WMConnection *cPtr) /*FOLD00*/
726 return cPtr->sock;
730 WMConnectionState
731 WMGetConnectionState(WMConnection *cPtr) /*FOLD00*/
733 return cPtr->state;
737 WMConnectionTimeoutState
738 WMGetConnectionTimeoutState(WMConnection *cPtr) /*FOLD00*/
740 return cPtr->timeoutState;
744 Bool
745 WMEnqueueConnectionData(WMConnection *cPtr, WMData *data) /*FOLD00*/
747 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, False);
748 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, False);
750 if (cPtr->state!=WCConnected)
751 return False;
753 WMAddToArray(cPtr->outputQueue, WMRetainData(data));
754 return True;
759 WMSendConnectionData(WMConnection *cPtr, WMData *data) /*FOLD00*/
761 int bytes, pos, len, totalTransfer;
762 TimeoutData *tPtr = &cPtr->sendTimeout;
763 const unsigned char *dataBytes;
765 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, -1);
766 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, -1);
768 if (cPtr->state!=WCConnected)
769 return -1;
771 /* If we have no data just flush the queue, else try to send data */
772 if (data && WMGetDataLength(data)>0) {
773 WMAddToArray(cPtr->outputQueue, WMRetainData(data));
774 /* If there already was something in queue, and also a write input
775 * handler is established, it means we were unable to send, so
776 * return and let the write handler notify us when we can send.
778 if (WMGetArrayItemCount(cPtr->outputQueue)>1 && cPtr->handler.write)
779 return 0;
782 totalTransfer = 0;
784 while (WMGetArrayItemCount(cPtr->outputQueue) > 0) {
785 data = WMGetFromArray(cPtr->outputQueue, 0);
786 dataBytes = (const unsigned char *)WMDataBytes(data);
787 len = WMGetDataLength(data);
788 pos = cPtr->bufPos; /* where we're left last time */
789 while(pos < len) {
790 again:
791 bytes = write(cPtr->sock, dataBytes+pos, len - pos);
792 if(bytes<0) {
793 switch (errno) {
794 case EINTR:
795 goto again;
796 case EWOULDBLOCK:
797 /* save the position where we're left and add a timeout */
798 cPtr->bufPos = pos;
799 if (!tPtr->handler) {
800 tPtr->handler = WMAddTimerHandler(tPtr->timeout*1000,
801 sendTimeout, cPtr);
803 if (!cPtr->handler.write) {
804 cPtr->handler.write =
805 WMAddInputHandler(cPtr->sock, WIWriteMask,
806 inputHandler, cPtr);
808 return totalTransfer;
809 default:
810 WCErrorCode = errno;
811 cPtr->state = WCDied;
812 removeAllHandlers(cPtr);
813 if (cPtr->delegate && cPtr->delegate->didDie)
814 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
815 return -1;
818 pos += bytes;
819 totalTransfer += bytes;
821 WMDeleteFromArray(cPtr->outputQueue, 0);
822 cPtr->bufPos = 0;
823 if (tPtr->handler) {
824 WMDeleteTimerHandler(tPtr->handler);
825 tPtr->handler = NULL;
827 if (cPtr->handler.write) {
828 WMDeleteInputHandler(cPtr->handler.write);
829 cPtr->handler.write = NULL;
833 return totalTransfer;
838 * WMGetConnectionAvailableData(connection):
840 * will return a WMData structure containing the available data on the
841 * specified connection. If connection is non-blocking (default) and no data
842 * is available when this function is called, an empty WMData is returned.
844 * If an error occurs while reading or the other side closed connection,
845 * it will return NULL.
846 * Also trying to read from an already died or closed connection is
847 * considered to be an error condition, and will return NULL.
849 WMData*
850 WMGetConnectionAvailableData(WMConnection *cPtr) /*FOLD00*/
852 char buffer[NETBUF_SIZE];
853 int nbytes;
854 WMData *aData;
856 wassertrv(cPtr->state!=WCNotConnected && cPtr->state!=WCListening, NULL);
857 wassertrv(cPtr->state!=WCInProgress && cPtr->state!=WCFailed, NULL);
859 if (cPtr->state!=WCConnected)
860 return NULL;
862 aData = NULL;
864 again:
865 nbytes = read(cPtr->sock, buffer, NETBUF_SIZE);
866 if (nbytes<0) {
867 switch (errno) {
868 case EINTR:
869 goto again;
870 case EWOULDBLOCK:
871 aData = WMCreateDataWithCapacity(0);
872 break;
873 default:
874 WCErrorCode = errno;
875 cPtr->state = WCDied;
876 removeAllHandlers(cPtr);
877 if (cPtr->delegate && cPtr->delegate->didDie)
878 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
879 break;
881 } else if (nbytes==0) { /* the other side has closed connection */
882 cPtr->state = WCClosed;
883 removeAllHandlers(cPtr);
884 if (cPtr->delegate && cPtr->delegate->didDie)
885 (*cPtr->delegate->didDie)(cPtr->delegate, cPtr);
886 } else {
887 aData = WMCreateDataWithBytes(buffer, nbytes);
890 return aData;
894 void
895 WMSetConnectionDelegate(WMConnection *cPtr, ConnectionDelegate *delegate) /*FOLD00*/
897 wassertr(cPtr->sock >= 0);
898 /* Don't try to set the delegate multiple times */
899 wassertr(cPtr->delegate == NULL);
901 cPtr->delegate = delegate;
902 if (delegate && delegate->didReceiveInput && !cPtr->handler.read)
903 cPtr->handler.read = WMAddInputHandler(cPtr->sock, WIReadMask,
904 inputHandler, cPtr);
905 if (delegate && delegate->didCatchException && !cPtr->handler.exception)
906 cPtr->handler.exception = WMAddInputHandler(cPtr->sock, WIExceptMask,
907 inputHandler, cPtr);
911 #if 0
912 Bool
913 WMIsConnectionNonBlocking(WMConnection *cPtr) /*FOLD00*/
915 #if 1
916 int state;
918 state = fcntl(cPtr->sock, F_GETFL, 0);
920 if (state < 0) {
921 /*wsyserror("Failed to get socket flags with fcntl.");*/
922 /* If we can't use fcntl on socket, this probably also means we could
923 * not use fcntl to set non-blocking mode, and since a socket defaults
924 * to blocking when created, return False as the best assumption */
925 return False;
928 return ((state & NONBLOCK_OPT)!=0);
929 #else
930 return cPtr->isNonBlocking;
931 #endif
933 #endif
936 Bool
937 WMSetConnectionNonBlocking(WMConnection *cPtr, Bool flag) /*FOLD00*/
939 wassertrv(cPtr!=NULL && cPtr->sock>=0, False);
941 if (cPtr->isNonBlocking == flag)
942 return True;
944 if (setSocketNonBlocking(cPtr->sock, flag)==True) {
945 cPtr->isNonBlocking = flag;
946 return True;
949 return False;
953 Bool
954 WMSetConnectionCloseOnExec(WMConnection *cPtr, Bool flag)
956 wassertrv(cPtr!=NULL && cPtr->sock>=0, False);
958 if (fcntl(cPtr->sock, F_SETFD, (flag ? FD_CLOEXEC : 0)) < 0) {
959 return False;
962 return True;
966 void*
967 WMGetConnectionClientData(WMConnection *cPtr) /*FOLD00*/
969 return cPtr->clientData;
973 void
974 WMSetConnectionClientData(WMConnection *cPtr, void *data) /*FOLD00*/
976 cPtr->clientData = data;
980 unsigned int
981 WMGetConnectionFlags(WMConnection *cPtr) /*FOLD00*/
983 return cPtr->uflags;
987 void
988 WMSetConnectionFlags(WMConnection *cPtr, unsigned int flags) /*FOLD00*/
990 cPtr->uflags = flags;
994 WMArray*
995 WMGetConnectionUnsentData(WMConnection *cPtr)
997 return cPtr->outputQueue;
1001 void
1002 WMSetConnectionDefaultTimeout(unsigned int timeout) /*FOLD00*/
1004 if (timeout == 0) {
1005 DefaultTimeout = DEF_TIMEOUT;
1006 } else {
1007 DefaultTimeout = timeout;
1012 void
1013 WMSetConnectionOpenTimeout(unsigned int timeout) /*FOLD00*/
1015 if (timeout == 0) {
1016 OpenTimeout = DefaultTimeout;
1017 } else {
1018 OpenTimeout = timeout;
1023 void
1024 WMSetConnectionSendTimeout(WMConnection *cPtr, unsigned int timeout) /*FOLD00*/
1026 if (timeout == 0) {
1027 cPtr->sendTimeout.timeout = DefaultTimeout;
1028 } else {
1029 cPtr->sendTimeout.timeout = timeout;