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 }