Bug Summary

File:src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/lib/abyss/src/socket_unix.c
Location:line 418, column 1
Description:Potential leak of memory pointed to by 'peerName'

Annotated Source Code

1/*=============================================================================
2 socket_unix.c
3===============================================================================
4 This is the implementation of TChanSwitch and TChannel (and
5 obsolete TSocket) for a standard Unix (POSIX)
6 stream socket -- what you create with a socket() C library call.
7=============================================================================*/
8
9#include "xmlrpc_config.h"
10
11#include <stdlib.h>
12#include <assert.h>
13#include <sys/types.h>
14#include <unistd.h>
15#include <stdio.h>
16#include <poll.h>
17#include <string.h>
18#include <sys/socket.h>
19#include <sys/time.h>
20#include <netinet/in.h>
21#include <netinet/tcp.h>
22#include <netdb.h>
23#include <arpa/inet.h>
24#include <errno(*__errno_location ()).h>
25
26#if HAVE_SYS_FILIO_H0
27 #include <sys/filio.h>
28#endif
29
30#include "c_util.h"
31#include "int.h"
32#include "xmlrpc-c/util_int.h"
33#include "xmlrpc-c/string_int.h"
34#include "mallocvar.h"
35#include "trace.h"
36#include "chanswitch.h"
37#include "channel.h"
38#include "socket.h"
39#include "xmlrpc-c/abyss.h"
40
41#include "socket_unix.h"
42
43#define sane_close(_it)do {if (_it > -1) { close(_it) ; _it = -1; }} while (_it >
-1)
do {if (_it > -1) { close(_it) ; _it = -1; }} while (_it > -1)
44
45
46typedef struct {
47 int interruptorFd;
48 int interrupteeFd;
49 int inuse;
50} interruptPipe;
51
52
53
54static void
55initInterruptPipe(interruptPipe * pipeP,
56 const char ** const errorP) {
57
58 int pipeFd[2] = {-1, -1};
59 int rc;
60
61 rc = pipe(pipeFd);
62
63 if (rc != 0) {
64 xmlrpc_asprintf(errorP, "Unable to create a pipe to use to interrupt "
65 "waits. pipe() failed with errno %d (%s)",
66 errno(*__errno_location ()), strerror(errno(*__errno_location ())));
67 pipeP->inuse = 0;
68 } else {
69 *errorP = NULL((void*)0);
70 pipeP->interruptorFd = pipeFd[1];
71 pipeP->interrupteeFd = pipeFd[0];
72 pipeP->inuse = 1;
73 }
74}
75
76
77
78static void
79termInterruptPipe(interruptPipe *pipeP) {
80 if (pipeP->inuse) {
81 int x = 0;
82 write(pipeP->interruptorFd, &x, sizeof(x));
83 usleep(500);
84 shutdown(pipeP->interrupteeFd, 2);
85 sane_close(pipeP->interruptorFd)do {if (pipeP->interruptorFd > -1) { close(pipeP->interruptorFd
) ; pipeP->interruptorFd = -1; }} while (pipeP->interruptorFd
> -1)
;
86 sane_close(pipeP->interrupteeFd)do {if (pipeP->interrupteeFd > -1) { close(pipeP->interrupteeFd
) ; pipeP->interrupteeFd = -1; }} while (pipeP->interrupteeFd
> -1)
;
87 }
88}
89
90
91
92struct socketUnix {
93/*----------------------------------------------------------------------------
94 The properties/state of a TChanSwitch or TChannel unique to the
95 Unix variety.
96-----------------------------------------------------------------------------*/
97 int fd;
98 /* File descriptor of the POSIX socket (such as is created by
99 socket() in the C library) for the socket.
100 */
101 bool userSuppliedFd;
102 /* The file descriptor and associated POSIX socket belong to the
103 user; we did not create it.
104 */
105 interruptPipe interruptPipe;
106};
107
108
109
110static bool
111connected(int const fd) {
112/*----------------------------------------------------------------------------
113 Return TRUE iff the socket on file descriptor 'fd' is in the connected
114 state.
115
116 If 'fd' does not identify a stream socket or we are unable to determine
117 the state of the stream socket, the answer is "false".
118-----------------------------------------------------------------------------*/
119 bool connected;
120 struct sockaddr sockaddr;
121 socklen_t nameLen;
122 int rc;
123
124 nameLen = sizeof(sockaddr);
125
126 rc = getpeername(fd, &sockaddr, &nameLen);
127
128 if (rc == 0)
129 connected = TRUE1;
130 else
131 connected = FALSE0;
132
133 return connected;
134}
135
136
137
138void
139SocketUnixInit(const char ** const errorP) {
140
141 *errorP = NULL((void*)0);
142}
143
144
145
146void
147SocketUnixTerm(void) {
148
149}
150
151
152
153/*=============================================================================
154 TChannel
155=============================================================================*/
156
157static void
158channelDestroy(TChannel * const channelP) {
159
160 struct socketUnix * const socketUnixP = channelP->implP;
161
162 termInterruptPipe(&socketUnixP->interruptPipe);
163
164 if (!socketUnixP->userSuppliedFd)
165 sane_close(socketUnixP->fd)do {if (socketUnixP->fd > -1) { close(socketUnixP->fd
) ; socketUnixP->fd = -1; }} while (socketUnixP->fd >
-1)
;
166
167 free(socketUnixP);
168 channelP->implP = 0;
169}
170
171
172
173static ChannelWriteImpl channelWrite;
174
175static void
176channelWrite(TChannel * const channelP,
177 const unsigned char * const buffer,
178 uint32_t const len,
179 bool * const failedP) {
180
181 struct socketUnix * const socketUnixP = channelP->implP;
182
183 size_t bytesLeft;
184 bool error;
185 int to_count = 0;
186
187 assert(sizeof(size_t) >= sizeof(len))((sizeof(size_t) >= sizeof(len)) ? (void) (0) : __assert_fail
("sizeof(size_t) >= sizeof(len)", "../../../../libs/xmlrpc-c/lib/abyss/src/socket_unix.c"
, 187, __PRETTY_FUNCTION__))
;
188
189 for (bytesLeft = len, error = FALSE0; bytesLeft > 0 && !error; ) {
190 size_t const maxSend = 4096 * 2; /* with respect to resource allocation this might be a better value than 2^31 */
191 ssize_t rc = 0;
192
193 rc = send(socketUnixP->fd, buffer + len - bytesLeft, MIN(maxSend, bytesLeft)((maxSend) < (bytesLeft) ? (maxSend) : (bytesLeft)), 0);
194 if (rc > 0) { /* 0 means connection closed; < 0 means severe error ; > 0 means bytes transferred */
195 to_count = 0;
196 bytesLeft -= rc;
197 if (ChannelTraceIsActive)
198 fprintf(stderrstderr, "Abyss: sent %d bytes: '%.*s'\n", rc, MIN(rc, 4096)((rc) < (4096) ? (rc) : (4096)), buffer + len - bytesLeft);
199 }
200 else if (!rc) {
201 error = TRUE1;
202 if (ChannelTraceIsActive)
203 fprintf(stderrstderr, "\nAbyss: send() failed: socket closed");
204 }
205 else {
206 error = TRUE1;
207 if (errno(*__errno_location ()) == EWOULDBLOCK11) {
208 usleep(20 * 1000); /* give socket another chance after xx millisec) */
209 if (++to_count < 300) {
210 error = FALSE0;
211 }
212 if (ChannelTraceIsActive)
213 fprintf(stderrstderr, "\nAbyss: send() failed with errno %d (%s) cnt %d, will retry\n", errno(*__errno_location ()), strerror(errno(*__errno_location ())), to_count);
214 }
215 if (ChannelTraceIsActive)
216 fprintf(stderrstderr, "Abyss: send() failed with errno=%d (%s)", errno(*__errno_location ()), strerror(errno(*__errno_location ())));
217 }
218 }
219
220 *failedP = error;
221
222
223}
224
225
226
227static ChannelReadImpl channelRead;
228
229static void
230channelRead(TChannel * const channelP,
231 unsigned char * const buffer,
232 uint32_t const bufferSize,
233 uint32_t * const bytesReceivedP,
234 bool * const failedP) {
235
236 struct socketUnix * const socketUnixP = channelP->implP;
237 int retries = 300;
238
239 for (*failedP = TRUE1; *failedP && retries; retries--) {
240 int rc = recv(socketUnixP->fd, buffer, bufferSize, 0);
241 if (rc < 0) {
242 if (errno(*__errno_location ()) == EWOULDBLOCK11) {
243 if (ChannelTraceIsActive)
244 fprintf(stderrstderr, "\nAbyss: recv() failed with errno %d (%s) cnt %d, will retry\n", errno(*__errno_location ()), strerror(errno(*__errno_location ())), retries);
245 usleep(20 * 1000); /* give socket another chance after xx millisec)*/
246 *failedP = FALSE0;
247 } else {
248 if (ChannelTraceIsActive)
249 fprintf(stderrstderr, "\nAbyss: recv() failed with errno %d (%s)\n", errno(*__errno_location ()), strerror(errno(*__errno_location ())));
250 break;
251 }
252 } else {
253 *failedP = FALSE0;
254 *bytesReceivedP = rc;
255
256 if (ChannelTraceIsActive)
257 fprintf(stderrstderr, "Abyss channel: read %u bytes: '%.*s'\n", bytesReceivedP, (int)(*bytesReceivedP), buffer);
258 }
259 }
260}
261
262
263
264static ChannelWaitImpl channelWait;
265
266static void
267channelWait(TChannel * const channelP,
268 bool const waitForRead,
269 bool const waitForWrite,
270 uint32_t const timeoutMs,
271 bool * const readyToReadP,
272 bool * const readyToWriteP,
273 bool * const failedP) {
274/*----------------------------------------------------------------------------
275 Wait for the channel to be immediately readable or writable.
276
277 Readable means there is at least one byte of data to read or the
278 partner has disconnected. Writable means the channel will take at
279 least one byte of data to send or the partner has disconnected.
280
281 'waitForRead' and 'waitForWrite' determine which of these
282 conditions for which to wait; if both are true, we wait for either
283 one.
284
285 We return before the requested condition holds if 'timeoutMs'
286 milliseconds pass. timeoutMs == TIME_INFINITE means infinity.
287
288 We return before the requested condition holds if the process receives
289 (and catches) a signal, but only if it receives that signal a certain
290 time after we start running. (That means this function isn't useful
291 for most purposes).
292
293 Return *readyToReadP == true if the reason for returning is that
294 the channel is immediately readable. *readyToWriteP is analogous
295 for writable. Both may be true.
296
297 Return *failedP true iff we fail to wait for the requested
298 condition because of some unusual problem. Being interrupted by a
299 signal is not a failure.
300
301 If one of these return value pointers is NULL, don't return that
302 value.
303-----------------------------------------------------------------------------*/
304 struct socketUnix * const socketUnixP = channelP->implP;
305
306 /* Design note: some old systems may not have poll(). We're assuming
307 that we don't have to run on any such system. select() is more
308 universal, but can't handle a file descriptor with a high number.
309
310 pselect() and ppoll() would allow us to be properly
311 interruptible by a signal -- we would add a signal mask to our
312 arguments. But ppoll() is fairly rare. pselect() is more
313 common, but in older Linux systems it doesn't actually work.
314 */
315 bool readyToRead, readyToWrite, failed;
316 struct pollfd pollfds[2];
317 int rc;
318
319 pollfds[0].fd = socketUnixP->fd;
320 pollfds[0].events =
321 (waitForRead ? POLLIN0x001 : 0) |
322 (waitForWrite ? POLLOUT0x004 : 0);
323
324 pollfds[1].fd = socketUnixP->interruptPipe.interrupteeFd;
325 pollfds[1].events = POLLIN0x001;
326
327 rc = poll(pollfds, ARRAY_SIZE(pollfds)(sizeof(pollfds)/sizeof(pollfds[0])),
328 timeoutMs == TIME_INFINITE0xffffffff ? -1 : (int)timeoutMs);
329
330 if (rc < 0) {
331 if (errno(*__errno_location ()) == EINTR4) {
332 failed = FALSE0;
333 readyToRead = FALSE0;
334 readyToWrite = FALSE0;
335 } else {
336 failed = TRUE1;
337 readyToRead = FALSE0; /* quiet compiler warning */
338 readyToWrite = FALSE0; /* quiet compiler warning */
339 }
340 } else {
341 failed = FALSE0;
342 readyToRead = !!(pollfds[0].revents & POLLIN0x001);
343 readyToWrite = !!(pollfds[0].revents & POLLOUT0x004);
344 }
345
346 if (failedP)
347 *failedP = failed;
348 if (readyToReadP)
349 *readyToReadP = readyToRead;
350 if (readyToWriteP)
351 *readyToWriteP = readyToWrite;
352}
353
354
355
356static ChannelInterruptImpl channelInterrupt;
357
358static void
359channelInterrupt(TChannel * const channelP) {
360/*----------------------------------------------------------------------------
361 Interrupt any waiting that a thread might be doing in channelWait()
362 now or in the future.
363
364 TODO: Make a way to reset this so that future channelWait()s can once
365 again wait.
366-----------------------------------------------------------------------------*/
367 struct socketUnix * const socketUnixP = channelP->implP;
368 unsigned char const zero[1] = {0u};
369
370 write(socketUnixP->interruptPipe.interruptorFd, &zero, sizeof(zero));
371}
372
373
374
375void
376ChannelUnixGetPeerName(TChannel * const channelP,
377 struct sockaddr ** const sockaddrPP,
378 size_t * const sockaddrLenP,
379 const char ** const errorP) {
380
381 struct socketUnix * const socketUnixP = channelP->implP;
382
383 unsigned char * peerName;
384 socklen_t nameSize;
385
386 nameSize = sizeof(struct sockaddr) + 1;
387
388 peerName = malloc(nameSize);
1
Memory is allocated
389
390 if (peerName == NULL((void*)0))
2
Assuming 'peerName' is not equal to null
3
Taking false branch
391 xmlrpc_asprintf(errorP, "Unable to allocate space for peer name");
392 else {
393 int rc;
394 socklen_t nameLen;
395 nameLen = nameSize; /* initial value */
396 rc = getpeername(socketUnixP->fd, (struct sockaddr *)peerName,
397 &nameLen);
398
399 if (rc < 0)
4
Assuming 'rc' is >= 0
5
Taking false branch
400 xmlrpc_asprintf(errorP, "getpeername() failed. errno=%d (%s)",
401 errno(*__errno_location ()), strerror(errno(*__errno_location ())));
402 else {
403 if (nameLen > nameSize-1)
6
Taking true branch
404 xmlrpc_asprintf(errorP,
405 "getpeername() says the socket name is "
406 "larger than %u bytes, which means it is "
407 "not in the expected format.",
408 nameSize-1);
409 else {
410 *sockaddrPP = (struct sockaddr *)peerName;
411 *sockaddrLenP = nameLen;
412 *errorP = NULL((void*)0);
413 }
414 }
415 if (*errorP)
7
Taking false branch
416 free(peerName);
417 }
418}
8
Potential leak of memory pointed to by 'peerName'
419
420
421
422static ChannelFormatPeerInfoImpl channelFormatPeerInfo;
423
424static void
425channelFormatPeerInfo(TChannel * const channelP,
426 const char ** const peerStringP) {
427
428 struct socketUnix * const socketUnixP = channelP->implP;
429
430 struct sockaddr sockaddr;
431 socklen_t sockaddrLen;
432 int rc;
433
434 sockaddrLen = sizeof(sockaddr);
435
436 rc = getpeername(socketUnixP->fd, &sockaddr, &sockaddrLen);
437
438 if (rc < 0)
439 xmlrpc_asprintf(peerStringP, "?? getpeername() failed. errno=%d (%s)",
440 errno(*__errno_location ()), strerror(errno(*__errno_location ())));
441 else {
442 switch (sockaddr.sa_family) {
443 case AF_INET2: {
444 struct sockaddr_in * const sockaddrInP =
445 (struct sockaddr_in *) &sockaddr;
446 if (sockaddrLen < sizeof(*sockaddrInP))
447 xmlrpc_asprintf(peerStringP, "??? getpeername() returned "
448 "the wrong size");
449 else {
450 unsigned char * const ipaddr = (unsigned char *)
451 &sockaddrInP->sin_addr.s_addr;
452 xmlrpc_asprintf(peerStringP, "%u.%u.%u.%u:%hu",
453 ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3],
454 sockaddrInP->sin_port);
455 }
456 } break;
457 default:
458 xmlrpc_asprintf(peerStringP, "??? AF=%u", sockaddr.sa_family);
459 }
460 }
461}
462
463
464
465static struct TChannelVtbl const channelVtbl = {
466 &channelDestroy,
467 &channelWrite,
468 &channelRead,
469 &channelWait,
470 &channelInterrupt,
471 &channelFormatPeerInfo,
472};
473
474
475
476static void
477makeChannelInfo(struct abyss_unix_chaninfo ** const channelInfoPP,
478 struct sockaddr const peerAddr,
479 socklen_t const peerAddrLen,
480 const char ** const errorP) {
481
482 struct abyss_unix_chaninfo * channelInfoP;
483
484 MALLOCVAR(channelInfoP)channelInfoP = malloc(sizeof(*channelInfoP));
485
486 if (channelInfoP == NULL((void*)0))
487 xmlrpc_asprintf(errorP, "Unable to allocate memory");
488 else {
489 channelInfoP->peerAddrLen = peerAddrLen;
490 channelInfoP->peerAddr = peerAddr;
491
492 *errorP = NULL((void*)0);
493 }
494 *channelInfoPP = channelInfoP;
495}
496
497
498
499static void
500makeChannelFromFd(int const fd,
501 TChannel ** const channelPP,
502 const char ** const errorP) {
503
504 struct socketUnix * socketUnixP;
505
506 MALLOCVAR(socketUnixP)socketUnixP = malloc(sizeof(*socketUnixP));
507
508 if (socketUnixP == NULL((void*)0))
509 xmlrpc_asprintf(errorP, "Unable to allocate memory for Unix "
510 "channel descriptor");
511 else {
512 TChannel * channelP;
513
514 socketUnixP->fd = fd;
515 socketUnixP->userSuppliedFd = TRUE1;
516
517 initInterruptPipe(&socketUnixP->interruptPipe, errorP);
518
519 if (!*errorP) {
520 ChannelCreate(&channelVtbl, socketUnixP, &channelP);
521
522 if (channelP == NULL((void*)0))
523 xmlrpc_asprintf(errorP, "Unable to allocate memory for "
524 "channel descriptor.");
525 else {
526 *channelPP = channelP;
527 *errorP = NULL((void*)0);
528 }
529 if (*errorP)
530 termInterruptPipe(&socketUnixP->interruptPipe);
531 }
532 if (*errorP)
533 free(socketUnixP);
534 }
535}
536
537
538
539void
540ChannelUnixCreateFd(int const fd,
541 TChannel ** const channelPP,
542 struct abyss_unix_chaninfo ** const channelInfoPP,
543 const char ** const errorP) {
544
545 struct sockaddr peerAddr;
546 socklen_t peerAddrLen;
547 int rc;
548
549 peerAddrLen = sizeof(peerAddrLen);
550
551 rc = getpeername(fd, &peerAddr, &peerAddrLen);
552
553 if (rc != 0) {
554 if (errno(*__errno_location ()) == ENOTCONN107)
555 xmlrpc_asprintf(errorP, "Socket on file descriptor %d is not in "
556 "connected state.", fd);
557 else
558 xmlrpc_asprintf(errorP, "getpeername() failed on fd %d. "
559 "errno=%d (%s)", fd, errno(*__errno_location ()), strerror(errno(*__errno_location ())));
560 } else {
561 makeChannelInfo(channelInfoPP, peerAddr, peerAddrLen, errorP);
562 if (!*errorP) {
563 makeChannelFromFd(fd, channelPP, errorP);
564
565 if (*errorP)
566 free(*channelInfoPP);
567 }
568 }
569}
570
571
572
573/*=============================================================================
574 TChanSwitch
575=============================================================================*/
576
577static SwitchDestroyImpl chanSwitchDestroy;
578
579static void
580chanSwitchDestroy(TChanSwitch * const chanSwitchP) {
581
582 struct socketUnix * const socketUnixP = chanSwitchP->implP;
583
584 termInterruptPipe(&socketUnixP->interruptPipe);
585
586 if (!socketUnixP->userSuppliedFd)
587 sane_close(socketUnixP->fd)do {if (socketUnixP->fd > -1) { close(socketUnixP->fd
) ; socketUnixP->fd = -1; }} while (socketUnixP->fd >
-1)
;
588
589 free(socketUnixP);
590}
591
592
593
594static SwitchListenImpl chanSwitchListen;
595
596static void
597chanSwitchListen(TChanSwitch * const chanSwitchP,
598 uint32_t const backlog,
599 const char ** const errorP) {
600
601 struct socketUnix * const socketUnixP = chanSwitchP->implP;
602
603 int32_t const minus1 = -1;
604
605 int rc;
606
607 /* Disable the Nagle algorithm to make persistant connections faster */
608
609 setsockopt(socketUnixP->fd, IPPROTO_TCPIPPROTO_TCP, TCP_NODELAY1,
610 &minus1, sizeof(minus1));
611
612 rc = listen(socketUnixP->fd, backlog);
613
614 if (rc == -1)
615 xmlrpc_asprintf(errorP, "listen() failed with errno %d (%s)",
616 errno(*__errno_location ()), strerror(errno(*__errno_location ())));
617 else
618 *errorP = NULL((void*)0);
619}
620
621
622
623static void
624waitForConnection(struct socketUnix * const listenSocketP,
625 bool * const interruptedP,
626 const char ** const errorP) {
627/*----------------------------------------------------------------------------
628 Wait for the listening socket to have a connection ready to accept.
629
630 We return before the requested condition holds if the process receives
631 (and catches) a signal, but only if it receives that signal a certain
632 time after we start running. (That means this behavior isn't useful
633 for most purposes).
634
635 We furthermore return before the requested condition holds if someone sends
636 a byte through the listening socket's interrupt pipe (or has sent one
637 previously since the most recent time the pipe was drained).
638
639 Return *interruptedP == true if we return before there is a connection
640 ready to accept.
641-----------------------------------------------------------------------------*/
642 struct pollfd pollfds[2];
643 int rc;
644
645 pollfds[0].fd = listenSocketP->fd;
646 pollfds[0].events = POLLIN0x001;
647
648 pollfds[1].fd = listenSocketP->interruptPipe.interrupteeFd;
649 pollfds[1].events = POLLIN0x001;
650
651 rc = poll(pollfds, ARRAY_SIZE(pollfds)(sizeof(pollfds)/sizeof(pollfds[0])), -1);
652
653 if (rc < 0) {
654 if (errno(*__errno_location ()) == EINTR4) {
655 *errorP = NULL((void*)0);
656 *interruptedP = TRUE1;
657 } else {
658 xmlrpc_asprintf(errorP, "poll() failed, errno = %d (%s)",
659 errno(*__errno_location ()), strerror(errno(*__errno_location ())));
660 *interruptedP = FALSE0; /* quiet compiler warning */
661 }
662 } else {
663 *errorP = NULL((void*)0);
664 *interruptedP = !(pollfds[0].revents & POLLIN0x001);
665 }
666}
667
668
669
670static void
671createChannelForAccept(int const acceptedFd,
672 struct sockaddr const peerAddr,
673 TChannel ** const channelPP,
674 void ** const channelInfoPP,
675 const char ** const errorP) {
676/*----------------------------------------------------------------------------
677 Make a channel object (TChannel) out of a socket just created by
678 accept() on a listening socket -- i.e. a socket for a client connection.
679
680 'acceptedFd' is the file descriptor of the socket.
681
682 'peerAddr' is the address of the client, from accept().
683-----------------------------------------------------------------------------*/
684 struct abyss_unix_chaninfo * channelInfoP;
685
686 makeChannelInfo(&channelInfoP, peerAddr, sizeof(peerAddr), errorP);
687 if (!*errorP) {
688 struct socketUnix * acceptedSocketP;
689
690 MALLOCVAR(acceptedSocketP)acceptedSocketP = malloc(sizeof(*acceptedSocketP));
691
692 if (!acceptedSocketP)
693 xmlrpc_asprintf(errorP, "Unable to allocate memory");
694 else {
695 acceptedSocketP->fd = acceptedFd;
696 acceptedSocketP->userSuppliedFd = FALSE0;
697
698 initInterruptPipe(&acceptedSocketP->interruptPipe, errorP);
699
700 if (!*errorP) {
701 TChannel * channelP;
702
703 ChannelCreate(&channelVtbl, acceptedSocketP, &channelP);
704 if (!channelP)
705 xmlrpc_asprintf(errorP,
706 "Failed to create TChannel object.");
707 else {
708 *errorP = NULL((void*)0);
709 *channelPP = channelP;
710 *channelInfoPP = channelInfoP;
711 }
712 if (*errorP)
713 termInterruptPipe(&acceptedSocketP->interruptPipe);
714 }
715 if (*errorP)
716 free(acceptedSocketP);
717 }
718 if (*errorP)
719 free(channelInfoP);
720 }
721}
722
723
724
725static SwitchAcceptImpl chanSwitchAccept;
726
727static void
728chanSwitchAccept(TChanSwitch * const chanSwitchP,
729 TChannel ** const channelPP,
730 void ** const channelInfoPP,
731 const char ** const errorP) {
732/*----------------------------------------------------------------------------
733 Accept a connection via the channel switch *chanSwitchP. Return as
734 *channelPP the channel for the accepted connection.
735
736 If no connection is waiting at *chanSwitchP, wait until one is.
737
738 If we receive a signal while waiting, return immediately with
739 *channelPP == NULL.
740-----------------------------------------------------------------------------*/
741 struct socketUnix * const listenSocketP = chanSwitchP->implP;
742
743 bool interrupted;
744 TChannel * channelP;
745
746 interrupted = FALSE0; /* Haven't been interrupted yet */
747 channelP = NULL((void*)0); /* No connection yet */
748 *errorP = NULL((void*)0); /* No error yet */
749
750 while (!channelP && !*errorP && !interrupted) {
751
752 waitForConnection(listenSocketP, &interrupted, errorP);
753
754 if (!*errorP && !interrupted) {
755 struct sockaddr peerAddr;
756 socklen_t size = sizeof(peerAddr);
757 int rc;
758
759 rc = accept(listenSocketP->fd, &peerAddr, &size);
760
761 if (rc >= 0) {
762 int acceptedFd = rc;
763
764 createChannelForAccept(acceptedFd, peerAddr,
765 &channelP, channelInfoPP, errorP);
766
767 if (*errorP)
768 sane_close(acceptedFd)do {if (acceptedFd > -1) { close(acceptedFd) ; acceptedFd =
-1; }} while (acceptedFd > -1)
;
769 } else if (errno(*__errno_location ()) == EINTR4)
770 interrupted = TRUE1;
771 else
772 xmlrpc_asprintf(errorP, "accept() failed, errno = %d (%s)",
773 errno(*__errno_location ()), strerror(errno(*__errno_location ())));
774 }
775 }
776 *channelPP = channelP;
777}
778
779
780
781static SwitchInterruptImpl chanSwitchInterrupt;
782
783static void
784chanSwitchInterrupt(TChanSwitch * const chanSwitchP) {
785/*----------------------------------------------------------------------------
786 Interrupt any waiting that a thread might be doing in chanSwitchAccept()
787 now or in the future.
788
789 TODO: Make a way to reset this so that future chanSwitchAccept()s can once
790 again wait.
791-----------------------------------------------------------------------------*/
792 struct socketUnix * const listenSocketP = chanSwitchP->implP;
793
794 unsigned char const zero[1] = {0u};
795
796 write(listenSocketP->interruptPipe.interruptorFd, &zero, sizeof(zero));
797}
798
799
800
801static struct TChanSwitchVtbl const chanSwitchVtbl = {
802 &chanSwitchDestroy,
803 &chanSwitchListen,
804 &chanSwitchAccept,
805 &chanSwitchInterrupt,
806};
807
808
809
810static void
811createChanSwitch(int const fd,
812 bool const userSuppliedFd,
813 TChanSwitch ** const chanSwitchPP,
814 const char ** const errorP) {
815
816 struct socketUnix * socketUnixP;
817
818 assert(!connected(fd))((!connected(fd)) ? (void) (0) : __assert_fail ("!connected(fd)"
, "../../../../libs/xmlrpc-c/lib/abyss/src/socket_unix.c", 818
, __PRETTY_FUNCTION__))
;
819
820 MALLOCVAR(socketUnixP)socketUnixP = malloc(sizeof(*socketUnixP));
821
822 if (socketUnixP == NULL((void*)0))
823 xmlrpc_asprintf(errorP, "unable to allocate memory for Unix "
824 "channel switch descriptor.");
825 else {
826 TChanSwitch * chanSwitchP;
827
828 socketUnixP->fd = fd;
829 socketUnixP->userSuppliedFd = userSuppliedFd;
830
831 initInterruptPipe(&socketUnixP->interruptPipe, errorP);
832
833 if (!*errorP) {
834 ChanSwitchCreate(&chanSwitchVtbl, socketUnixP, &chanSwitchP);
835 if (*errorP)
836 termInterruptPipe(&socketUnixP->interruptPipe);
837
838 if (chanSwitchP == NULL((void*)0))
839 xmlrpc_asprintf(errorP, "Unable to allocate memory for "
840 "channel switch descriptor");
841 else {
842 *chanSwitchPP = chanSwitchP;
843 *errorP = NULL((void*)0);
844 }
845 }
846 if (*errorP)
847 free(socketUnixP);
848 }
849}
850
851
852
853static void
854setSocketOptions(int const fd,
855 const char ** const errorP) {
856
857 int32_t n = 1;
858 int rc;
859
860 rc = setsockopt(fd, SOL_SOCKET1, SO_REUSEADDR2, (char*)&n, sizeof(n));
861
862 if (rc < 0)
863 xmlrpc_asprintf(errorP, "Failed to set socket options. "
864 "setsockopt() failed with errno %d (%s)",
865 errno(*__errno_location ()), strerror(errno(*__errno_location ())));
866 else
867 *errorP = NULL((void*)0);
868}
869
870
871
872static void
873bindSocketToPort(int const fd,
874 struct in_addr * const addrP,
875 uint16_t const portNumber,
876 const char ** const errorP) {
877
878 struct sockaddr_in name;
879 int rc;
880 int one = 1;
881
882 name.sin_family = AF_INET2;
883 name.sin_port = htons(portNumber)(__extension__ ({ unsigned short int __v, __x = (unsigned short
int) (portNumber); if (__builtin_constant_p (__x)) __v = ((unsigned
short int) ((((__x) >> 8) & 0xff) | (((__x) & 0xff
) << 8))); else __asm__ ("rorw $8, %w0" : "=r" (__v) : "0"
(__x) : "cc"); __v; }))
;
884 if (addrP)
885 name.sin_addr = *addrP;
886 else
887 name.sin_addr.s_addr = INADDR_ANY((in_addr_t) 0x00000000);
888
889 setsockopt(fd, SOL_SOCKET1, SO_REUSEADDR2, (void *)&one, sizeof(int));
890 rc = bind(fd, (struct sockaddr *)&name, sizeof(name));
891
892 if (rc == -1)
893 xmlrpc_asprintf(errorP, "Unable to bind socket to port number %hu. "
894 "bind() failed with errno %d (%s)",
895 portNumber, errno(*__errno_location ()), strerror(errno(*__errno_location ())));
896 else
897 *errorP = NULL((void*)0);
898}
899
900
901
902void
903ChanSwitchUnixCreate(unsigned short const portNumber,
904 TChanSwitch ** const chanSwitchPP,
905 const char ** const errorP) {
906/*----------------------------------------------------------------------------
907 Create a POSIX-socket-based channel switch.
908
909 Use an IP socket.
910
911 Set the socket's local address so that a subsequent "listen" will listen
912 on all IP addresses, port number 'portNumber'.
913-----------------------------------------------------------------------------*/
914 int rc;
915 rc = socket(AF_INET2, SOCK_STREAMSOCK_STREAM, 0);
916 if (rc < 0)
917 xmlrpc_asprintf(errorP, "socket() failed with errno %d (%s)",
918 errno(*__errno_location ()), strerror(errno(*__errno_location ())));
919 else {
920 int socketFd = rc;
921
922 setSocketOptions(socketFd, errorP);
923 if (!*errorP) {
924 bindSocketToPort(socketFd, NULL((void*)0), portNumber, errorP);
925
926 if (!*errorP) {
927 bool const userSupplied = false;
928 createChanSwitch(socketFd, userSupplied, chanSwitchPP, errorP);
929 }
930 }
931 if (*errorP)
932 sane_close(socketFd)do {if (socketFd > -1) { close(socketFd) ; socketFd = -1; }
} while (socketFd > -1)
;
933 }
934}
935
936
937
938void
939ChanSwitchUnixCreateFd(int const fd,
940 TChanSwitch ** const chanSwitchPP,
941 const char ** const errorP) {
942
943 if (connected(fd))
944 xmlrpc_asprintf(errorP,
945 "Socket (file descriptor %d) is in connected "
946 "state.", fd);
947 else {
948 bool const userSupplied = true;
949 createChanSwitch(fd, userSupplied, chanSwitchPP, errorP);
950 }
951}
952
953
954
955/*=============================================================================
956 obsolete TSocket interface
957=============================================================================*/
958
959
960void
961SocketUnixCreateFd(int const fd,
962 TSocket ** const socketPP) {
963
964 TSocket * socketP;
965 const char * error;
966
967 if (connected(fd)) {
968 TChannel * channelP;
969 struct abyss_unix_chaninfo * channelInfoP;
970 ChannelUnixCreateFd(fd, &channelP, &channelInfoP, &error);
971 if (!error)
972 SocketCreateChannel(channelP, channelInfoP, &socketP);
973 } else {
974 TChanSwitch * chanSwitchP;
975 ChanSwitchUnixCreateFd(fd, &chanSwitchP, &error);
976 if (!error)
977 SocketCreateChanSwitch(chanSwitchP, &socketP);
978 }
979 if (error) {
980 *socketPP = NULL((void*)0);
981 xmlrpc_strfree(error);
982 } else
983 *socketPP = socketP;
984}