Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / connection.c
1 /*
2  *  WINGs WMConnection function library
3  *
4  *  Copyright (c) 1999-2003 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.
10  *
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.
15  *
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.
19  */
20
21 /*
22  * TODO:
23  * - decide if we want to support connections with external sockets, else
24  *   clean up the structure of the unneeded members.
25  * - decide what to do with all wwarning() calls that are still there.
26  *
27  */
28
29 #include "wconfig.h"
30
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <stdarg.h>
37 #include <errno.h>
38 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41 #include <netdb.h>
42 #include <signal.h>
43 #ifdef __FreeBSD__
44 #include <sys/signal.h>
45 #endif
46
47 #include "WINGs.h"
48
49 /* Some older systems does not define this (linux libc5, maybe others too) */
50 #ifndef SHUT_RDWR
51 # define SHUT_RDWR              2
52 #endif
53
54 /* For SunOS */
55 #ifndef SA_RESTART
56 # define SA_RESTART             0
57 #endif
58
59 /* For Solaris */
60 #ifndef INADDR_NONE
61 # define INADDR_NONE           -1
62 #endif
63
64 /* Stuff for setting the sockets into non-blocking mode. */
65 /*
66 #ifdef  __POSIX_SOURCE
67 # define NONBLOCK_OPT           O_NONBLOCK
68 #else
69 # define NONBLOCK_OPT           FNDELAY
70 #endif
71 */
72
73 #define NONBLOCK_OPT            O_NONBLOCK
74
75 #define NETBUF_SIZE             4096
76
77 #define DEF_TIMEOUT             600     /* 600 seconds == 10 minutes */
78
79 int WCErrorCode = 0;
80
81 static Bool SigInitialized = False;
82
83 static unsigned int DefaultTimeout = DEF_TIMEOUT;
84 static unsigned int OpenTimeout = DEF_TIMEOUT;
85
86 typedef struct TimeoutData {
87         unsigned timeout;
88         WMHandlerID *handler;
89 } TimeoutData;
90
91 typedef struct W_Connection {
92         int sock;               /* the socket we speak through */
93
94         struct {
95                 WMHandlerID *read;      /* the input read handler */
96                 WMHandlerID *write;     /* the input write handler */
97                 WMHandlerID *exception; /* the input exception handler */
98         } handler;
99
100         ConnectionDelegate *delegate;   /* client delegates */
101         void *clientData;       /* client data */
102         unsigned int uflags;    /* flags for the client */
103
104         WMArray *outputQueue;
105         unsigned bufPos;
106
107         TimeoutData sendTimeout;
108         TimeoutData openTimeout;
109
110         WMConnectionState state;
111         WMConnectionTimeoutState timeoutState;
112
113         char *address;
114         char *service;
115         char *protocol;
116
117         Bool closeOnRelease;
118         Bool shutdownOnClose;
119         Bool wasNonBlocking;
120         Bool isNonBlocking;
121
122 } W_Connection;
123
124 static void clearOutputQueue(WMConnection * cPtr)
125 {
126         cPtr->bufPos = 0;
127         WMEmptyArray(cPtr->outputQueue);
128 }
129
130 static void openTimeout(void *cdata)
131 {
132         WMConnection *cPtr = (WMConnection *) cdata;
133
134         cPtr->openTimeout.handler = NULL;
135         if (cPtr->handler.write) {
136                 WMDeleteInputHandler(cPtr->handler.write);
137                 cPtr->handler.write = NULL;
138         }
139         if (cPtr->state != WCConnected) {
140                 cPtr->state = WCTimedOut;
141                 cPtr->timeoutState = WCTWhileOpening;
142                 if (cPtr->delegate && cPtr->delegate->didTimeout) {
143                         (*cPtr->delegate->didTimeout) (cPtr->delegate, cPtr);
144                 } else {
145                         WMCloseConnection(cPtr);
146                         cPtr->state = WCTimedOut;       /* the above set state to WCClosed */
147                 }
148         }
149 }
150
151 static void sendTimeout(void *cdata)
152 {
153         WMConnection *cPtr = (WMConnection *) cdata;
154
155         cPtr->sendTimeout.handler = NULL;
156         if (cPtr->handler.write) {
157                 WMDeleteInputHandler(cPtr->handler.write);
158                 cPtr->handler.write = NULL;
159         }
160         if (WMGetArrayItemCount(cPtr->outputQueue) > 0) {
161                 clearOutputQueue(cPtr);
162                 cPtr->state = WCTimedOut;
163                 cPtr->timeoutState = WCTWhileSending;
164                 /* // should we close it no matter what (after calling the didTimeout
165                    // delegate)? -Dan */
166                 if (cPtr->delegate && cPtr->delegate->didTimeout) {
167                         (*cPtr->delegate->didTimeout) (cPtr->delegate, cPtr);
168                 } else {
169                         WMCloseConnection(cPtr);
170                         cPtr->state = WCTimedOut;       /* the above set state to WCClosed */
171                 }
172         }
173 }
174
175 static void inputHandler(int fd, int mask, void *clientData)
176 {
177         WMConnection *cPtr = (WMConnection *) clientData;
178
179         if (cPtr->state == WCClosed || cPtr->state == WCDied)
180                 return;
181
182         if ((mask & WIWriteMask)) {
183                 int result;
184
185                 if (cPtr->state == WCInProgress) {
186                         Bool failed;
187                         socklen_t len = sizeof(result);
188
189                         WCErrorCode = 0;
190                         if (getsockopt(cPtr->sock, SOL_SOCKET, SO_ERROR,
191                                        (void *)&result, &len) == 0 && result != 0) {
192                                 cPtr->state = WCFailed;
193                                 WCErrorCode = result;
194                                 failed = True;
195                                 /* should call wsyserrorwithcode(result, ...) here? */
196                         } else {
197                                 cPtr->state = WCConnected;
198                                 failed = False;
199                         }
200
201                         if (cPtr->handler.write) {
202                                 WMDeleteInputHandler(cPtr->handler.write);
203                                 cPtr->handler.write = NULL;
204                         }
205
206                         if (cPtr->openTimeout.handler) {
207                                 WMDeleteTimerHandler(cPtr->openTimeout.handler);
208                                 cPtr->openTimeout.handler = NULL;
209                         }
210
211                         if (cPtr->delegate && cPtr->delegate->didInitialize)
212                                 (*cPtr->delegate->didInitialize) (cPtr->delegate, cPtr);
213
214                         /* we use failed and not cPtr->state here, because cPtr may be
215                          * destroyed by the delegate called above if the connection failed
216                          */
217                         if (failed)
218                                 return;
219                 } else if (cPtr->state == WCConnected) {
220                         result = WMFlushConnection(cPtr);
221                         if (result > 0 && cPtr->delegate && cPtr->delegate->canResumeSending) {
222                                 (*cPtr->delegate->canResumeSending) (cPtr->delegate, cPtr);
223                         }
224                 }
225         }
226
227         if (!cPtr->delegate)
228                 return;
229
230         /* if the connection died, may get destroyed in the delegate, so retain */
231         wretain(cPtr);
232
233         if ((mask & WIReadMask) && cPtr->delegate->didReceiveInput)
234                 (*cPtr->delegate->didReceiveInput) (cPtr->delegate, cPtr);
235
236         if ((mask & WIExceptMask) && cPtr->delegate->didCatchException)
237                 (*cPtr->delegate->didCatchException) (cPtr->delegate, cPtr);
238
239         wrelease(cPtr);
240 }
241
242 static Bool setSocketNonBlocking(int sock, Bool flag)
243 {
244         int state;
245         Bool isNonBlock;
246
247         state = fcntl(sock, F_GETFL, 0);
248
249         if (state < 0) {
250                 /* set WCErrorCode here? -Dan */
251                 return False;
252         }
253
254         isNonBlock = (state & NONBLOCK_OPT) != 0;
255
256         if (flag) {
257                 if (isNonBlock)
258                         return True;
259                 state |= NONBLOCK_OPT;
260         } else {
261                 if (!isNonBlock)
262                         return True;
263                 state &= ~NONBLOCK_OPT;
264         }
265
266         if (fcntl(sock, F_SETFL, state) < 0) {
267                 /* set WCErrorCode here? -Dan */
268                 return False;
269         }
270
271         return True;
272 }
273
274 static void setConnectionAddress(WMConnection * cPtr, struct sockaddr_in *socketaddr)
275 {
276         wassertr(cPtr->address == NULL);
277
278         cPtr->address = wstrdup(inet_ntoa(socketaddr->sin_addr));
279         cPtr->service = wmalloc(16);
280         sprintf(cPtr->service, "%hu", ntohs(socketaddr->sin_port));
281         cPtr->protocol = wstrdup("tcp");
282 }
283
284 static struct sockaddr_in *getSocketAddress(char *name, char *service, char *protocol)
285 {
286         static struct sockaddr_in socketaddr;
287         struct servent *sp;
288
289         if (!protocol || protocol[0] == 0)
290                 protocol = "tcp";
291
292         memset(&socketaddr, 0, sizeof(struct sockaddr_in));
293         socketaddr.sin_family = AF_INET;
294
295         /*
296          * If we were given a hostname, we use any address for that host.
297          * Otherwise we expect the given name to be an address unless it is
298          * NULL (any address).
299          */
300         if (name && name[0] != 0) {
301                 WMHost *host = WMGetHostWithName(name);
302
303                 if (!host)
304                         return NULL;    /* name is not a hostname nor a number and dot adr */
305
306                 name = WMGetHostAddress(host);
307 #ifndef HAVE_INET_ATON
308                 if ((socketaddr.sin_addr.s_addr = inet_addr(name)) == INADDR_NONE) {
309 #else
310                 if (inet_aton(name, &socketaddr.sin_addr) == 0) {
311 #endif
312                         WMReleaseHost(host);
313                         return NULL;
314                 }
315                 WMReleaseHost(host);
316         } else {
317                 socketaddr.sin_addr.s_addr = htonl(INADDR_ANY);
318         }
319
320         if (!service || service[0] == 0) {
321                 socketaddr.sin_port = 0;
322         } else if ((sp = getservbyname(service, protocol)) == 0) {
323                 char *endptr;
324                 unsigned portNumber;
325
326                 portNumber = strtoul(service, &endptr, 10);
327
328                 if (service[0] != 0 && *endptr == 0 && portNumber < 65536) {
329                         socketaddr.sin_port = htons(portNumber);
330                 } else {
331                         return NULL;
332                 }
333         } else {
334                 socketaddr.sin_port = sp->s_port;
335         }
336
337         return &socketaddr;
338 }
339
340 static void dummyHandler(int signum)
341 {
342 }
343
344 static WMConnection *createConnectionWithSocket(int sock, Bool closeOnRelease)
345 {
346         WMConnection *cPtr;
347         struct sigaction sig_action;
348
349         cPtr = wmalloc(sizeof(WMConnection));
350         wretain(cPtr);
351         memset(cPtr, 0, sizeof(WMConnection));
352
353         fcntl(sock, F_SETFD, FD_CLOEXEC);       /* by default close on exec */
354
355         cPtr->sock = sock;
356         cPtr->openTimeout.timeout = OpenTimeout;
357         cPtr->openTimeout.handler = NULL;
358         cPtr->sendTimeout.timeout = DefaultTimeout;
359         cPtr->sendTimeout.handler = NULL;
360         cPtr->closeOnRelease = closeOnRelease;
361         cPtr->shutdownOnClose = 1;
362         cPtr->outputQueue = WMCreateArrayWithDestructor(16, (WMFreeDataProc *) WMReleaseData);
363         cPtr->state = WCNotConnected;
364         cPtr->timeoutState = WCTNone;
365
366         /* ignore dead pipe */
367         if (!SigInitialized) {
368                 /* Because POSIX mandates that only signal with handlers are reset
369                  * accross an exec*(), we do not want to propagate ignoring SIGPIPEs
370                  * to children. Hence the dummy handler. Philippe Troin <phil@fifi.org>
371                  */
372                 sig_action.sa_handler = &dummyHandler;
373                 sig_action.sa_flags = SA_RESTART;
374                 sigaction(SIGPIPE, &sig_action, NULL);
375                 SigInitialized = True;
376         }
377
378         return cPtr;
379 }
380
381 #if 0
382 WMConnection *WMCreateConnectionWithSocket(int sock, Bool closeOnRelease)
383 {
384         WMConnection *cPtr;
385         struct sockaddr_in clientname;
386         int size;
387         int n;
388
389         cPtr = createConnectionWithSocket(sock, closeOnRelease);
390         cPtr->wasNonBlocking = WMIsConnectionNonBlocking(cPtr);
391         cPtr->isNonBlocking = cPtr->wasNonBlocking;
392
393         /* some way to find out if it is connected, and binded. can't find
394            if it listens though!!!
395          */
396
397         size = sizeof(clientname);
398         n = getpeername(sock, (struct sockaddr *)&clientname, &size);
399         if (n == 0) {
400                 /* Since we have a peer, it means we are connected */
401                 cPtr->state = WCConnected;
402         } else {
403                 size = sizeof(clientname);
404                 n = getsockname(sock, (struct sockaddr *)&clientname, &size);
405                 if (n == 0) {
406                         /* We don't have a peer, but we are binded to an address.
407                          * Assume we are listening on it (we don't know that for sure!)
408                          */
409                         cPtr->state = WCListening;
410                 } else {
411                         cPtr->state = WCNotConnected;
412                 }
413         }
414
415         return cPtr;
416 }
417 #endif
418
419 /*
420  * host     is the name on which we want to listen for incoming connections,
421  *          and it must be a name of this host, or NULL if we want to listen
422  *          on any incoming address.
423  * service  is either a service name as present in /etc/services, or the port
424  *          number we want to listen on. If NULL, a random port between
425  *          1024 and 65535 will be assigned to us.
426  * protocol is one of "tcp" or "udp". If NULL, "tcp" will be used by default.
427  *          currently only "tcp" is supported.
428  */
429 WMConnection *WMCreateConnectionAsServerAtAddress(char *host, char *service, char *protocol)
430 {
431         WMConnection *cPtr;
432         struct sockaddr_in *socketaddr;
433         socklen_t size;
434         int sock, on;
435
436         WCErrorCode = 0;
437
438         if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
439                 wwarning(_("Bad address-service-protocol combination"));
440                 return NULL;
441         }
442
443         /* Create the actual socket */
444         sock = socket(PF_INET, SOCK_STREAM, 0);
445         if (sock < 0) {
446                 WCErrorCode = errno;
447                 return NULL;
448         }
449
450         /*
451          * Set socket options. We try to make the port reusable and have it
452          * close as fast as possible without waiting in unnecessary wait states
453          * on close.
454          */
455         on = 1;
456         setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
457
458         if (bind(sock, (struct sockaddr *)socketaddr, sizeof(*socketaddr)) < 0) {
459                 WCErrorCode = errno;
460                 close(sock);
461                 return NULL;
462         }
463
464         if (listen(sock, 10) < 0) {
465                 WCErrorCode = errno;
466                 close(sock);
467                 return NULL;
468         }
469
470         /* Find out what is the address/service/protocol we get */
471         /* In case some of address/service/protocol were NULL */
472         size = sizeof(*socketaddr);
473         if (getsockname(sock, (struct sockaddr *)socketaddr, &size) < 0) {
474                 WCErrorCode = errno;
475                 close(sock);
476                 return NULL;
477         }
478
479         cPtr = createConnectionWithSocket(sock, True);
480         cPtr->state = WCListening;
481         WMSetConnectionNonBlocking(cPtr, True);
482
483         setConnectionAddress(cPtr, socketaddr);
484
485         return cPtr;
486 }
487
488 WMConnection *WMCreateConnectionToAddress(char *host, char *service, char *protocol)
489 {
490         WMConnection *cPtr;
491         struct sockaddr_in *socketaddr;
492         int sock;
493
494         WCErrorCode = 0;
495
496         wassertrv(service != NULL && service[0] != 0, NULL);
497
498         if (host == NULL || host[0] == 0)
499                 host = "localhost";
500
501         if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
502                 wwarning(_("Bad address-service-protocol combination"));
503                 return NULL;
504         }
505
506         /* Create the actual socket */
507         sock = socket(PF_INET, SOCK_STREAM, 0);
508         if (sock < 0) {
509                 WCErrorCode = errno;
510                 return NULL;
511         }
512         /* make socket blocking while we connect. */
513         setSocketNonBlocking(sock, False);
514         if (connect(sock, (struct sockaddr *)socketaddr, sizeof(*socketaddr)) < 0) {
515                 WCErrorCode = errno;
516                 close(sock);
517                 return NULL;
518         }
519
520         cPtr = createConnectionWithSocket(sock, True);
521         cPtr->state = WCConnected;
522         WMSetConnectionNonBlocking(cPtr, True);
523         setConnectionAddress(cPtr, socketaddr);
524
525         return cPtr;
526 }
527
528 WMConnection *WMCreateConnectionToAddressAndNotify(char *host, char *service, char *protocol)
529 {
530         WMConnection *cPtr;
531         struct sockaddr_in *socketaddr;
532         int sock;
533         Bool isNonBlocking;
534
535         WCErrorCode = 0;
536
537         wassertrv(service != NULL && service[0] != 0, NULL);
538
539         if (host == NULL || host[0] == 0)
540                 host = "localhost";
541
542         if ((socketaddr = getSocketAddress(host, service, protocol)) == NULL) {
543                 wwarning(_("Bad address-service-protocol combination"));
544                 return NULL;
545         }
546
547         /* Create the actual socket */
548         sock = socket(PF_INET, SOCK_STREAM, 0);
549         if (sock < 0) {
550                 WCErrorCode = errno;
551                 return NULL;
552         }
553         isNonBlocking = setSocketNonBlocking(sock, True);
554         if (connect(sock, (struct sockaddr *)socketaddr, sizeof(*socketaddr)) < 0) {
555                 if (errno != EINPROGRESS) {
556                         WCErrorCode = errno;
557                         close(sock);
558                         return NULL;
559                 }
560         }
561
562         cPtr = createConnectionWithSocket(sock, True);
563         cPtr->state = WCInProgress;
564         cPtr->isNonBlocking = isNonBlocking;
565
566         cPtr->handler.write = WMAddInputHandler(cPtr->sock, WIWriteMask, inputHandler, cPtr);
567
568         cPtr->openTimeout.handler = WMAddTimerHandler(cPtr->openTimeout.timeout * 1000, openTimeout, cPtr);
569
570         setConnectionAddress(cPtr, socketaddr);
571
572         return cPtr;
573 }
574
575 static void removeAllHandlers(WMConnection * cPtr)
576 {
577         if (cPtr->handler.read)
578                 WMDeleteInputHandler(cPtr->handler.read);
579         if (cPtr->handler.write)
580                 WMDeleteInputHandler(cPtr->handler.write);
581         if (cPtr->handler.exception)
582                 WMDeleteInputHandler(cPtr->handler.exception);
583         if (cPtr->openTimeout.handler)
584                 WMDeleteTimerHandler(cPtr->openTimeout.handler);
585         if (cPtr->sendTimeout.handler)
586                 WMDeleteTimerHandler(cPtr->sendTimeout.handler);
587
588         cPtr->handler.read = NULL;
589         cPtr->handler.write = NULL;
590         cPtr->handler.exception = NULL;
591         cPtr->openTimeout.handler = NULL;
592         cPtr->sendTimeout.handler = NULL;
593 }
594
595 void WMDestroyConnection(WMConnection * cPtr)
596 {
597         if (cPtr->closeOnRelease && cPtr->sock >= 0) {
598                 if (cPtr->shutdownOnClose) {
599                         shutdown(cPtr->sock, SHUT_RDWR);
600                 }
601                 close(cPtr->sock);
602         }
603
604         removeAllHandlers(cPtr);
605         WMFreeArray(cPtr->outputQueue); /* will also free the items with the destructor */
606
607         if (cPtr->address) {
608                 wfree(cPtr->address);
609                 wfree(cPtr->service);
610                 wfree(cPtr->protocol);
611         }
612
613         wrelease(cPtr);
614 }
615
616 void WMCloseConnection(WMConnection * cPtr)
617 {
618         if (cPtr->sock >= 0) {
619                 if (cPtr->shutdownOnClose) {
620                         shutdown(cPtr->sock, SHUT_RDWR);
621                 }
622                 close(cPtr->sock);
623                 cPtr->sock = -1;
624         }
625
626         removeAllHandlers(cPtr);
627         clearOutputQueue(cPtr);
628
629         cPtr->state = WCClosed;
630 }
631
632 WMConnection *WMAcceptConnection(WMConnection * listener)
633 {
634         struct sockaddr_in clientname;
635         socklen_t size;
636         int newSock;
637         WMConnection *newConnection;
638
639         WCErrorCode = 0;
640         wassertrv(listener && listener->state == WCListening, NULL);
641
642         size = sizeof(clientname);
643         newSock = accept(listener->sock, (struct sockaddr *)&clientname, &size);
644         if (newSock < 0) {
645                 WCErrorCode = ((errno != EAGAIN && errno != EWOULDBLOCK) ? errno : 0);
646                 return NULL;
647         }
648
649         newConnection = createConnectionWithSocket(newSock, True);
650         WMSetConnectionNonBlocking(newConnection, True);
651         newConnection->state = WCConnected;
652         setConnectionAddress(newConnection, &clientname);
653
654         return newConnection;
655 }
656
657 char *WMGetConnectionAddress(WMConnection * cPtr)
658 {
659         return cPtr->address;
660 }
661
662 char *WMGetConnectionService(WMConnection * cPtr)
663 {
664         return cPtr->service;
665 }
666
667 char *WMGetConnectionProtocol(WMConnection * cPtr)
668 {
669         return cPtr->protocol;
670 }
671
672 int WMGetConnectionSocket(WMConnection * cPtr)
673 {
674         return cPtr->sock;
675 }
676
677 WMConnectionState WMGetConnectionState(WMConnection * cPtr)
678 {
679         return cPtr->state;
680 }
681
682 WMConnectionTimeoutState WMGetConnectionTimeoutState(WMConnection * cPtr)
683 {
684         return cPtr->timeoutState;
685 }
686
687 Bool WMEnqueueConnectionData(WMConnection * cPtr, WMData * data)
688 {
689         wassertrv(cPtr->state != WCNotConnected && cPtr->state != WCListening, False);
690         wassertrv(cPtr->state != WCInProgress && cPtr->state != WCFailed, False);
691
692         if (cPtr->state != WCConnected)
693                 return False;
694
695         WMAddToArray(cPtr->outputQueue, WMRetainData(data));
696         return True;
697 }
698
699 /*
700  * Return value:
701  * -1 - not connected or connection died while sending
702  *  0 - couldn't send the data (or part of it). data is saved in a queue
703  *      and will be sent when possible. after it is sent the canResumeSending
704  *      callback will be called.
705  *  1 - data was succesfully sent
706  */
707 int WMSendConnectionData(WMConnection * cPtr, WMData * data)
708 {
709         int bytes, pos, len;
710         TimeoutData *tPtr = &cPtr->sendTimeout;
711         const unsigned char *dataBytes;
712
713         wassertrv(cPtr->state != WCNotConnected && cPtr->state != WCListening, -1);
714         wassertrv(cPtr->state != WCInProgress && cPtr->state != WCFailed, -1);
715
716         if (cPtr->state != WCConnected)
717                 return -1;
718
719         /* If we have no data just flush the queue, else try to send data */
720         if (data && WMGetDataLength(data) > 0) {
721                 WMAddToArray(cPtr->outputQueue, WMRetainData(data));
722                 /* If there already was something in queue, and also a write input
723                  * handler is established, it means we were unable to send, so
724                  * return and let the write handler notify us when we can send.
725                  */
726                 if (WMGetArrayItemCount(cPtr->outputQueue) > 1 && cPtr->handler.write)
727                         return 0;
728         }
729
730         while (WMGetArrayItemCount(cPtr->outputQueue) > 0) {
731                 data = WMGetFromArray(cPtr->outputQueue, 0);
732                 dataBytes = (const unsigned char *)WMDataBytes(data);
733                 len = WMGetDataLength(data);
734                 pos = cPtr->bufPos;     /* where we're left last time */
735                 while (pos < len) {
736  again:
737                         bytes = write(cPtr->sock, dataBytes + pos, len - pos);
738                         if (bytes < 0) {
739                                 switch (errno) {
740                                 case EINTR:
741                                         goto again;
742                                 case EWOULDBLOCK:
743                                         /* save the position where we're left and add a timeout */
744                                         cPtr->bufPos = pos;
745                                         if (!tPtr->handler) {
746                                                 tPtr->handler = WMAddTimerHandler(tPtr->timeout * 1000,
747                                                                                   sendTimeout, cPtr);
748                                         }
749                                         if (!cPtr->handler.write) {
750                                                 cPtr->handler.write =
751                                                     WMAddInputHandler(cPtr->sock, WIWriteMask, inputHandler, cPtr);
752                                         }
753                                         return 0;
754                                 default:
755                                         WCErrorCode = errno;
756                                         cPtr->state = WCDied;
757                                         removeAllHandlers(cPtr);
758                                         if (cPtr->delegate && cPtr->delegate->didDie)
759                                                 (*cPtr->delegate->didDie) (cPtr->delegate, cPtr);
760                                         return -1;
761                                 }
762                         }
763                         pos += bytes;
764                 }
765                 WMDeleteFromArray(cPtr->outputQueue, 0);
766                 cPtr->bufPos = 0;
767                 if (tPtr->handler) {
768                         WMDeleteTimerHandler(tPtr->handler);
769                         tPtr->handler = NULL;
770                 }
771                 /*if (cPtr->handler.write) {
772                    WMDeleteInputHandler(cPtr->handler.write);
773                    cPtr->handler.write = NULL;
774                    } */
775         }
776
777         if (cPtr->handler.write) {
778                 WMDeleteInputHandler(cPtr->handler.write);
779                 cPtr->handler.write = NULL;
780         }
781
782         return 1;
783 }
784
785 /*
786  * WMGetConnectionAvailableData(connection):
787  *
788  * will return a WMData structure containing the available data on the
789  * specified connection. If connection is non-blocking (default) and no data
790  * is available when this function is called, an empty WMData is returned.
791  *
792  * If an error occurs while reading or the other side closed connection,
793  * it will return NULL.
794  * Also trying to read from an already died or closed connection is
795  * considered to be an error condition, and will return NULL.
796  */
797 WMData *WMGetConnectionAvailableData(WMConnection * cPtr)
798 {
799         char buffer[NETBUF_SIZE];
800         int nbytes;
801         WMData *aData;
802
803         wassertrv(cPtr->state != WCNotConnected && cPtr->state != WCListening, NULL);
804         wassertrv(cPtr->state != WCInProgress && cPtr->state != WCFailed, NULL);
805
806         if (cPtr->state != WCConnected)
807                 return NULL;
808
809         aData = NULL;
810
811  again:
812         nbytes = read(cPtr->sock, buffer, NETBUF_SIZE);
813         if (nbytes < 0) {
814                 switch (errno) {
815                 case EINTR:
816                         goto again;
817                 case EWOULDBLOCK:
818                         aData = WMCreateDataWithCapacity(0);
819                         break;
820                 default:
821                         WCErrorCode = errno;
822                         cPtr->state = WCDied;
823                         removeAllHandlers(cPtr);
824                         if (cPtr->delegate && cPtr->delegate->didDie)
825                                 (*cPtr->delegate->didDie) (cPtr->delegate, cPtr);
826                         break;
827                 }
828         } else if (nbytes == 0) {       /* the other side has closed connection */
829                 cPtr->state = WCClosed;
830                 removeAllHandlers(cPtr);
831                 if (cPtr->delegate && cPtr->delegate->didDie)
832                         (*cPtr->delegate->didDie) (cPtr->delegate, cPtr);
833         } else {
834                 aData = WMCreateDataWithBytes(buffer, nbytes);
835         }
836
837         return aData;
838 }
839
840 void WMSetConnectionDelegate(WMConnection * cPtr, ConnectionDelegate * delegate)
841 {
842         wassertr(cPtr->sock >= 0);
843         /* Don't try to set the delegate multiple times */
844         wassertr(cPtr->delegate == NULL);
845
846         cPtr->delegate = delegate;
847         if (delegate && delegate->didReceiveInput && !cPtr->handler.read)
848                 cPtr->handler.read = WMAddInputHandler(cPtr->sock, WIReadMask, inputHandler, cPtr);
849         if (delegate && delegate->didCatchException && !cPtr->handler.exception)
850                 cPtr->handler.exception = WMAddInputHandler(cPtr->sock, WIExceptMask, inputHandler, cPtr);
851 }
852
853 #if 0
854 Bool WMIsConnectionNonBlocking(WMConnection * cPtr)
855 {
856 #if 1
857         int state;
858
859         state = fcntl(cPtr->sock, F_GETFL, 0);
860
861         if (state < 0) {
862                 /* If we can't use fcntl on socket, this probably also means we could
863                  * not use fcntl to set non-blocking mode, and since a socket defaults
864                  * to blocking when created, return False as the best assumption */
865                 return False;
866         }
867
868         return ((state & NONBLOCK_OPT) != 0);
869 #else
870         return cPtr->isNonBlocking;
871 #endif
872 }
873 #endif
874
875 Bool WMSetConnectionNonBlocking(WMConnection * cPtr, Bool flag)
876 {
877         wassertrv(cPtr != NULL && cPtr->sock >= 0, False);
878
879         flag = ((flag == 0) ? 0 : 1);
880
881         if (cPtr->isNonBlocking == flag)
882                 return True;
883
884         if (setSocketNonBlocking(cPtr->sock, flag) == True) {
885                 cPtr->isNonBlocking = flag;
886                 return True;
887         }
888
889         return False;
890 }
891
892 Bool WMSetConnectionCloseOnExec(WMConnection * cPtr, Bool flag)
893 {
894         wassertrv(cPtr != NULL && cPtr->sock >= 0, False);
895
896         if (fcntl(cPtr->sock, F_SETFD, ((flag == 0) ? 0 : FD_CLOEXEC)) < 0) {
897                 return False;
898         }
899
900         return True;
901 }
902
903 void WMSetConnectionShutdownOnClose(WMConnection * cPtr, Bool flag)
904 {
905         cPtr->shutdownOnClose = ((flag == 0) ? 0 : 1);
906 }
907
908 void *WMGetConnectionClientData(WMConnection * cPtr)
909 {
910         return cPtr->clientData;
911 }
912
913 void WMSetConnectionClientData(WMConnection * cPtr, void *data)
914 {
915         cPtr->clientData = data;
916 }
917
918 unsigned int WMGetConnectionFlags(WMConnection * cPtr)
919 {
920         return cPtr->uflags;
921 }
922
923 void WMSetConnectionFlags(WMConnection * cPtr, unsigned int flags)
924 {
925         cPtr->uflags = flags;
926 }
927
928 WMArray *WMGetConnectionUnsentData(WMConnection * cPtr)
929 {
930         return cPtr->outputQueue;
931 }
932
933 void WMSetConnectionDefaultTimeout(unsigned int timeout)
934 {
935         if (timeout == 0) {
936                 DefaultTimeout = DEF_TIMEOUT;
937         } else {
938                 DefaultTimeout = timeout;
939         }
940 }
941
942 void WMSetConnectionOpenTimeout(unsigned int timeout)
943 {
944         if (timeout == 0) {
945                 OpenTimeout = DefaultTimeout;
946         } else {
947                 OpenTimeout = timeout;
948         }
949 }
950
951 void WMSetConnectionSendTimeout(WMConnection * cPtr, unsigned int timeout)
952 {
953         if (timeout == 0) {
954                 cPtr->sendTimeout.timeout = DefaultTimeout;
955         } else {
956                 cPtr->sendTimeout.timeout = timeout;
957         }
958 }