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.h>
25 
26 #if HAVE_SYS_FILIO_H
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 "netinet/in.h"
40 #include "xmlrpc-c/abyss.h"
41 
42 #include "sockutil.h"
43 
44 #include "socket_unix.h"
45 
46 
47 
48 struct socketUnix {
49 /*----------------------------------------------------------------------------
50    The properties/state of a TChanSwitch or TChannel unique to the
51    Unix variety.
52 -----------------------------------------------------------------------------*/
53     int fd;
54         /* File descriptor of the POSIX socket (such as is created by
55            socket() in the C library) for the socket.
56         */
57     bool userSuppliedFd;
58         /* The file descriptor and associated POSIX socket belong to the
59            user; we did not create it.
60         */
61     sockutil_InterruptPipe interruptPipe;
62 
63     bool isListening;
64         /* We've done a 'listen' on the socket */
65 };
66 
67 
68 
69 void
SocketUnixInit(const char ** const errorP)70 SocketUnixInit(const char ** const errorP) {
71 
72     *errorP = NULL;
73 }
74 
75 
76 
77 void
SocketUnixTerm(void)78 SocketUnixTerm(void) {
79 
80 }
81 
82 
83 
84 /*=============================================================================
85       TChannel
86 =============================================================================*/
87 
88 static void
channelDestroy(TChannel * const channelP)89 channelDestroy(TChannel * const channelP) {
90 
91     struct socketUnix * const socketUnixP = channelP->implP;
92 
93     sockutil_interruptPipeTerm(socketUnixP->interruptPipe);
94 
95     if (!socketUnixP->userSuppliedFd)
96         close(socketUnixP->fd);
97 
98     free(socketUnixP);
99 }
100 
101 
102 
103 static ChannelWriteImpl channelWrite;
104 
105 static void
channelWrite(TChannel * const channelP,const unsigned char * const buffer,uint32_t const len,bool * const failedP)106 channelWrite(TChannel *            const channelP,
107              const unsigned char * const buffer,
108              uint32_t              const len,
109              bool *                const failedP) {
110 
111     struct socketUnix * const socketUnixP = channelP->implP;
112 
113     size_t bytesLeft;
114     bool error;
115 
116     assert(sizeof(size_t) >= sizeof(len));
117 
118     for (bytesLeft = len, error = false;
119          bytesLeft > 0 && !error;
120         ) {
121         size_t const maxSend = (size_t)(-1) >> 1;
122 
123         ssize_t rc;
124 
125         // We'd like to use MSG_NOSIGNAL here, to prevent this send() from
126         // causing a SIGPIPE if the other end of the socket is closed, but
127         // MSG_NOSIGNAL is not standard enough.  An SO_NOSIGPIPE socket
128         // option is another way, but even less standard.  So instead, the
129         // thread simply must be set to ignore SIGPIPE.
130 
131         rc = send(socketUnixP->fd, &buffer[len-bytesLeft],
132                   MIN(maxSend, bytesLeft), 0);
133 
134         if (ChannelTraceIsActive) {
135             if (rc < 0)
136                 fprintf(stderr, "Abyss channel: send() failed.  errno=%d (%s)",
137                         errno, strerror(errno));
138             else if (rc == 0)
139                 fprintf(stderr, "Abyss channel: send() failed.  "
140                         "Socket closed.\n");
141             else {
142                 size_t const bytesTransferred = rc;
143                 fprintf(stderr, "Abyss channel: sent %u bytes: '%.*s'\n",
144                         (unsigned)bytesTransferred,
145                         (int)(MIN(bytesTransferred, 4096)),
146                         &buffer[len-bytesLeft]);
147             }
148         }
149         if (rc <= 0)
150             /* 0 means connection closed; < 0 means severe error */
151             error = true;
152         else
153             bytesLeft -= rc;
154     }
155     *failedP = error;
156 }
157 
158 
159 
160 static ChannelReadImpl channelRead;
161 
162 static void
channelRead(TChannel * const channelP,unsigned char * const buffer,uint32_t const bufferSize,uint32_t * const bytesReceivedP,bool * const failedP)163 channelRead(TChannel *      const channelP,
164             unsigned char * const buffer,
165             uint32_t        const bufferSize,
166             uint32_t *      const bytesReceivedP,
167             bool *          const failedP) {
168 
169     struct socketUnix * const socketUnixP = channelP->implP;
170 
171     int rc;
172     rc = recv(socketUnixP->fd, buffer, bufferSize, 0);
173 
174     if (rc < 0) {
175         *failedP = true;
176         if (ChannelTraceIsActive)
177             fprintf(stderr, "Abyss channel: "
178                     "Failed to receive data from socket.  "
179                     "recv() failed with errno %d (%s)\n",
180                     errno, strerror(errno));
181     } else {
182         *failedP = false;
183         *bytesReceivedP = rc;
184 
185         if (ChannelTraceIsActive)
186             fprintf(stderr, "Abyss channel: read %u bytes: '%.*s'\n",
187                     *bytesReceivedP, (int)(*bytesReceivedP), buffer);
188     }
189 }
190 
191 
192 
193 static ChannelWaitImpl channelWait;
194 
195 static void
channelWait(TChannel * const channelP,bool const waitForRead,bool const waitForWrite,uint32_t const timeoutMs,bool * const readyToReadP,bool * const readyToWriteP,bool * const failedP)196 channelWait(TChannel * const channelP,
197             bool       const waitForRead,
198             bool       const waitForWrite,
199             uint32_t   const timeoutMs,
200             bool *     const readyToReadP,
201             bool *     const readyToWriteP,
202             bool *     const failedP) {
203 /*----------------------------------------------------------------------------
204    Wait for the channel to be immediately readable or writable.
205 
206    Readable means there is at least one byte of data to read or the
207    partner has disconnected.  Writable means the channel will take at
208    least one byte of data to send or the partner has disconnected.
209 
210    'waitForRead' and 'waitForWrite' determine which of these
211    conditions for which to wait; if both are true, we wait for either
212    one.
213 
214    We return before the requested condition holds if 'timeoutMs'
215    milliseconds pass.  timeoutMs == TIME_INFINITE means infinity.
216 
217    We return before the requested condition holds if the process receives
218    (and catches) a signal, but only if it receives that signal a certain
219    time after we start running.  (That means this function isn't useful
220    for most purposes).
221 
222    Return *readyToReadP == true if the reason for returning is that
223    the channel is immediately readable.  But only if 'readyToReadP' is
224    non-null.  *readyToWriteP is analogous
225    for writable.  Both may be true.
226 
227    Return *failedP true iff we fail to wait for the requested condition
228    because of some unusual problem and 'failedP' is non-null.  Being
229    interrupted by a signal is not a failure.
230 
231    If one of these return value pointers is NULL, don't return that
232    value.
233 -----------------------------------------------------------------------------*/
234     struct socketUnix * const socketUnixP = channelP->implP;
235 
236     /* Design note: some old systems may not have poll().  We're assuming
237        that we don't have to run on any such system.  select() is more
238        universal, but can't handle a file descriptor with a high number.
239 
240        pselect() and ppoll() would allow us to be properly
241        interruptible by a signal -- we would add a signal mask to our
242        arguments.  But ppoll() is fairly rare.  pselect() is more
243        common, but in older Linux systems it doesn't actually work.
244     */
245     bool readyToRead, readyToWrite, failed;
246     struct pollfd pollfds[2];
247     int rc;
248 
249     pollfds[0].fd = socketUnixP->fd;
250     pollfds[0].events =
251         (waitForRead  ? POLLIN  : 0) |
252         (waitForWrite ? POLLOUT : 0);
253 
254     pollfds[1].fd = socketUnixP->interruptPipe.interrupteeFd;
255     pollfds[1].events = POLLIN;
256 
257     rc = poll(pollfds, ARRAY_SIZE(pollfds),
258               timeoutMs == TIME_INFINITE ? -1 : (int)timeoutMs);
259 
260     if (rc < 0) {
261         if (errno == EINTR) {
262             failed       = false;
263             readyToRead  = false;
264             readyToWrite = false;
265         } else {
266             failed       = true;
267             readyToRead  = false; /* quiet compiler warning */
268             readyToWrite = false; /* quiet compiler warning */
269         }
270     } else {
271         failed       = false;
272         readyToRead  = !!(pollfds[0].revents & POLLIN);
273         readyToWrite = !!(pollfds[0].revents & POLLOUT);
274     }
275 
276     if (failedP)
277         *failedP       = failed;
278     if (readyToReadP)
279         *readyToReadP  = readyToRead;
280     if (readyToWriteP)
281         *readyToWriteP = readyToWrite;
282 }
283 
284 
285 
286 static ChannelInterruptImpl channelInterrupt;
287 
288 static void
channelInterrupt(TChannel * const channelP)289 channelInterrupt(TChannel * const channelP) {
290 /*----------------------------------------------------------------------------
291   Interrupt any waiting that a thread might be doing in channelWait()
292   now or in the future.
293 
294   TODO: Make a way to reset this so that future channelWait()s can once
295   again wait.
296 -----------------------------------------------------------------------------*/
297     struct socketUnix * const socketUnixP = channelP->implP;
298 
299     sockutil_interruptPipeInterrupt(socketUnixP->interruptPipe);
300 }
301 
302 
303 
304 void
ChannelUnixGetPeerName(TChannel * const channelP,struct sockaddr ** const sockaddrPP,size_t * const sockaddrLenP,const char ** const errorP)305 ChannelUnixGetPeerName(TChannel *         const channelP,
306                        struct sockaddr ** const sockaddrPP,
307                        size_t  *          const sockaddrLenP,
308                        const char **      const errorP) {
309 
310     struct socketUnix * const socketUnixP = channelP->implP;
311 
312     sockutil_getPeerName(socketUnixP->fd, sockaddrPP, sockaddrLenP, errorP);
313 }
314 
315 
316 
317 static ChannelFormatPeerInfoImpl channelFormatPeerInfo;
318 
319 static void
channelFormatPeerInfo(TChannel * const channelP,const char ** const peerStringP)320 channelFormatPeerInfo(TChannel *    const channelP,
321                       const char ** const peerStringP) {
322 
323     struct socketUnix * const socketUnixP = channelP->implP;
324 
325     sockutil_formatPeerInfo(socketUnixP->fd, peerStringP);
326 }
327 
328 
329 
330 static struct TChannelVtbl const channelVtbl = {
331     &channelDestroy,
332     &channelWrite,
333     &channelRead,
334     &channelWait,
335     &channelInterrupt,
336     &channelFormatPeerInfo,
337 };
338 
339 
340 
341 static void
makeChannelInfo(struct abyss_unix_chaninfo ** const channelInfoPP,struct sockaddr const peerAddr,socklen_t const peerAddrLen,const char ** const errorP)342 makeChannelInfo(struct abyss_unix_chaninfo ** const channelInfoPP,
343                 struct sockaddr               const peerAddr,
344                 socklen_t                     const peerAddrLen,
345                 const char **                 const errorP) {
346 
347     struct abyss_unix_chaninfo * channelInfoP;
348 
349     MALLOCVAR(channelInfoP);
350 
351     if (channelInfoP == NULL)
352         xmlrpc_asprintf(errorP, "Unable to allocate memory");
353     else {
354         channelInfoP->peerAddrLen = peerAddrLen;
355         channelInfoP->peerAddr    = peerAddr;
356 
357         *errorP = NULL;
358     }
359     *channelInfoPP = channelInfoP;
360 }
361 
362 
363 
364 static void
makeChannelFromFd(int const fd,TChannel ** const channelPP,const char ** const errorP)365 makeChannelFromFd(int           const fd,
366                   TChannel **   const channelPP,
367                   const char ** const errorP) {
368 
369     struct socketUnix * socketUnixP;
370 
371     MALLOCVAR(socketUnixP);
372 
373     if (socketUnixP == NULL)
374         xmlrpc_asprintf(errorP, "Unable to allocate memory for Unix "
375                         "channel descriptor");
376     else {
377         TChannel * channelP;
378 
379         socketUnixP->fd = fd;
380         socketUnixP->userSuppliedFd = true;
381 
382         sockutil_interruptPipeInit(&socketUnixP->interruptPipe, errorP);
383 
384         if (!*errorP) {
385             ChannelCreate(&channelVtbl, socketUnixP, &channelP);
386 
387             if (channelP == NULL)
388                 xmlrpc_asprintf(errorP, "Unable to allocate memory for "
389                                 "channel descriptor.");
390             else {
391                 *channelPP = channelP;
392                 *errorP = NULL;
393             }
394             if (*errorP)
395                 sockutil_interruptPipeTerm(socketUnixP->interruptPipe);
396         }
397         if (*errorP)
398             free(socketUnixP);
399     }
400 }
401 
402 
403 
404 void
ChannelUnixCreateFd(int const fd,TChannel ** const channelPP,struct abyss_unix_chaninfo ** const channelInfoPP,const char ** const errorP)405 ChannelUnixCreateFd(int                           const fd,
406                     TChannel **                   const channelPP,
407                     struct abyss_unix_chaninfo ** const channelInfoPP,
408                     const char **                 const errorP) {
409 
410     if (!sockutil_connected(fd))
411         xmlrpc_asprintf(errorP, "Socket on file descriptor %d is not in "
412                         "connected state.", fd);
413     else {
414         struct sockaddr * peerAddrP;
415         size_t peerAddrLen;
416         const char * error;
417 
418         sockutil_getPeerName(fd, &peerAddrP, &peerAddrLen, &error);
419 
420         if (error) {
421             xmlrpc_asprintf(errorP, "Failed to get identity of client.  %s",
422                             error);
423             xmlrpc_strfree(error);
424         } else {
425             makeChannelInfo(channelInfoPP, *peerAddrP, peerAddrLen, errorP);
426             if (!*errorP) {
427                 makeChannelFromFd(fd, channelPP, errorP);
428 
429                 if (*errorP)
430                     free(*channelInfoPP);
431             }
432             free(peerAddrP);
433         }
434     }
435 }
436 
437 
438 
439 /*=============================================================================
440       TChanSwitch
441 =============================================================================*/
442 
443 static SwitchDestroyImpl chanSwitchDestroy;
444 
445 static void
chanSwitchDestroy(TChanSwitch * const chanSwitchP)446 chanSwitchDestroy(TChanSwitch * const chanSwitchP) {
447 
448     struct socketUnix * const socketUnixP = chanSwitchP->implP;
449 
450     sockutil_interruptPipeTerm(socketUnixP->interruptPipe);
451 
452     if (!socketUnixP->userSuppliedFd)
453         close(socketUnixP->fd);
454 
455     free(socketUnixP);
456 }
457 
458 
459 
460 static SwitchListenImpl chanSwitchListen;
461 
462 static void
chanSwitchListen(TChanSwitch * const chanSwitchP,uint32_t const backlog,const char ** const errorP)463 chanSwitchListen(TChanSwitch * const chanSwitchP,
464                  uint32_t      const backlog,
465                  const char ** const errorP) {
466 
467     struct socketUnix * const socketUnixP = chanSwitchP->implP;
468 
469     if (socketUnixP->isListening)
470         xmlrpc_asprintf(errorP, "Channel switch is already listening");
471     else {
472         sockutil_listen(socketUnixP->fd, backlog, errorP);
473 
474         if (!*errorP)
475             socketUnixP->isListening = true;
476     }
477 }
478 
479 
480 
481 static void
createChannelForAccept(int const acceptedFd,struct sockaddr const peerAddr,TChannel ** const channelPP,void ** const channelInfoPP,const char ** const errorP)482 createChannelForAccept(int             const acceptedFd,
483                        struct sockaddr const peerAddr,
484                        TChannel **     const channelPP,
485                        void **         const channelInfoPP,
486                        const char **   const errorP) {
487 /*----------------------------------------------------------------------------
488    Make a channel object (TChannel) out of a socket just created by
489    accept() on a listening socket -- i.e. a socket for a client connection.
490 
491    'acceptedFd' is the file descriptor of the socket.
492 
493    'peerAddr' is the address of the client, from accept().
494 -----------------------------------------------------------------------------*/
495     struct abyss_unix_chaninfo * channelInfoP;
496 
497     makeChannelInfo(&channelInfoP, peerAddr, sizeof(peerAddr), errorP);
498     if (!*errorP) {
499         struct socketUnix * acceptedSocketP;
500 
501         MALLOCVAR(acceptedSocketP);
502 
503         if (!acceptedSocketP)
504             xmlrpc_asprintf(errorP, "Unable to allocate memory");
505         else {
506             acceptedSocketP->fd = acceptedFd;
507             acceptedSocketP->userSuppliedFd = false;
508 
509             sockutil_interruptPipeInit(
510                 &acceptedSocketP->interruptPipe, errorP);
511 
512             if (!*errorP) {
513                 TChannel * channelP;
514 
515                 ChannelCreate(&channelVtbl, acceptedSocketP, &channelP);
516                 if (!channelP)
517                     xmlrpc_asprintf(errorP,
518                                     "Failed to create TChannel object.");
519                 else {
520                     *errorP        = NULL;
521                     *channelPP     = channelP;
522                     *channelInfoPP = channelInfoP;
523                 }
524                 if (*errorP)
525                     sockutil_interruptPipeTerm(acceptedSocketP->interruptPipe);
526             }
527             if (*errorP)
528                 free(acceptedSocketP);
529         }
530         if (*errorP)
531             free(channelInfoP);
532     }
533 }
534 
535 
536 
537 static SwitchAcceptImpl chanSwitchAccept;
538 
539 static void
chanSwitchAccept(TChanSwitch * const chanSwitchP,TChannel ** const channelPP,void ** const channelInfoPP,const char ** const errorP)540 chanSwitchAccept(TChanSwitch * const chanSwitchP,
541                  TChannel **   const channelPP,
542                  void **       const channelInfoPP,
543                  const char ** const errorP) {
544 /*----------------------------------------------------------------------------
545    Accept a connection via the channel switch *chanSwitchP.  Return as
546    *channelPP the channel for the accepted connection.
547 
548    If no connection is waiting at *chanSwitchP, wait until one is.
549 
550    If we receive a signal while waiting, return immediately with
551    *channelPP == NULL.
552 -----------------------------------------------------------------------------*/
553     struct socketUnix * const listenSocketP = chanSwitchP->implP;
554 
555     bool interrupted;
556     TChannel * channelP;
557 
558     interrupted = false; /* Haven't been interrupted yet */
559     channelP    = NULL;  /* No connection yet */
560     *errorP     = NULL;  /* No error yet */
561 
562     while (!channelP && !*errorP && !interrupted) {
563 
564         sockutil_waitForConnection(listenSocketP->fd,
565                                    listenSocketP->interruptPipe,
566                                    &interrupted, errorP);
567 
568         if (!*errorP && !interrupted) {
569             struct sockaddr peerAddr;
570             socklen_t peerAddrLen;
571             int rc;
572 
573             peerAddrLen = sizeof(peerAddr);  /* initial value */
574 
575             rc = accept(listenSocketP->fd, &peerAddr, &peerAddrLen);
576 
577             if (rc >= 0) {
578                 int const acceptedFd = rc;
579 
580                 createChannelForAccept(acceptedFd, peerAddr,
581                                        &channelP, channelInfoPP, errorP);
582 
583                 if (*errorP)
584                     close(acceptedFd);
585             } else if (errno == EINTR)
586                 interrupted = true;
587             else
588                 xmlrpc_asprintf(errorP, "accept() failed, errno = %d (%s)",
589                                 errno, strerror(errno));
590         }
591     }
592     *channelPP = channelP;
593 }
594 
595 
596 
597 static SwitchInterruptImpl chanSwitchInterrupt;
598 
599 static void
chanSwitchInterrupt(TChanSwitch * const chanSwitchP)600 chanSwitchInterrupt(TChanSwitch * const chanSwitchP) {
601 /*----------------------------------------------------------------------------
602   Interrupt any waiting that a thread might be doing in chanSwitchAccept()
603   now or in the future.
604 
605   TODO: Make a way to reset this so that future chanSwitchAccept()s can once
606   again wait.
607 -----------------------------------------------------------------------------*/
608     struct socketUnix * const listenSocketP = chanSwitchP->implP;
609 
610     unsigned char const zero[1] = {0u};
611 
612     write(listenSocketP->interruptPipe.interruptorFd, &zero, sizeof(zero));
613 }
614 
615 
616 
617 static struct TChanSwitchVtbl const chanSwitchVtbl = {
618     &chanSwitchDestroy,
619     &chanSwitchListen,
620     &chanSwitchAccept,
621     &chanSwitchInterrupt,
622 };
623 
624 
625 
626 static void
createChanSwitch(int const fd,bool const userSuppliedFd,TChanSwitch ** const chanSwitchPP,const char ** const errorP)627 createChanSwitch(int            const fd,
628                  bool           const userSuppliedFd,
629                  TChanSwitch ** const chanSwitchPP,
630                  const char **  const errorP) {
631 /*----------------------------------------------------------------------------
632    Create a channel switch from the bound, but not yet listening, socket
633    with file descriptor 'fd'.
634 
635    Return the handle of the new channel switch as *chanSwitchPP.
636 
637    'userSuppliedFd' means the file descriptor (socket) shall _not_ belong to
638    the channel switch, so destroying the channel switch does not close it.
639 -----------------------------------------------------------------------------*/
640     struct socketUnix * socketUnixP;
641 
642     assert(!sockutil_connected(fd));
643 
644     if (SwitchTraceIsActive)
645         fprintf(stderr, "Creating Unix listen-socket based channel switch\n");
646 
647     MALLOCVAR(socketUnixP);
648 
649     if (socketUnixP == NULL)
650         xmlrpc_asprintf(errorP, "unable to allocate memory for Unix "
651                         "channel switch descriptor.");
652     else {
653         TChanSwitch * chanSwitchP;
654 
655         socketUnixP->fd = fd;
656         socketUnixP->userSuppliedFd = userSuppliedFd;
657         socketUnixP->isListening = false;
658 
659         sockutil_interruptPipeInit(&socketUnixP->interruptPipe, errorP);
660 
661         if (!*errorP) {
662             ChanSwitchCreate(&chanSwitchVtbl, socketUnixP, &chanSwitchP);
663             if (*errorP)
664                 sockutil_interruptPipeTerm(socketUnixP->interruptPipe);
665 
666             if (chanSwitchP == NULL)
667                 xmlrpc_asprintf(errorP, "Unable to allocate memory for "
668                                 "channel switch descriptor");
669             else {
670                 *chanSwitchPP = chanSwitchP;
671                 *errorP = NULL;
672             }
673         }
674         if (*errorP)
675             free(socketUnixP);
676     }
677 }
678 
679 
680 
681 static void
switchCreateIpV4Port(unsigned short const portNumber,TChanSwitch ** const chanSwitchPP,const char ** const errorP)682 switchCreateIpV4Port(unsigned short          const portNumber,
683                      TChanSwitch **          const chanSwitchPP,
684                      const char **           const errorP) {
685 /*----------------------------------------------------------------------------
686    Create a POSIX-socket-based channel switch for an IPv4 endpoint.
687 
688    Set the socket's local address so that a subsequent "listen" will listen on
689    all interfaces, port number 'portNumber'.
690 -----------------------------------------------------------------------------*/
691     int rc;
692     rc = socket(PF_INET, SOCK_STREAM, 0);
693     if (rc < 0)
694         xmlrpc_asprintf(errorP, "socket() failed with errno %d (%s)",
695                         errno, strerror(errno));
696     else {
697         int const socketFd = rc;
698 
699         sockutil_setSocketOptions(socketFd, errorP);
700         if (!*errorP) {
701             sockutil_bindSocketToPortInet(socketFd, portNumber, errorP);
702 
703             if (!*errorP) {
704                 bool const userSupplied = false;
705                 createChanSwitch(socketFd, userSupplied, chanSwitchPP, errorP);
706             }
707         }
708         if (*errorP)
709             close(socketFd);
710     }
711 }
712 
713 
714 
715 static void
switchCreateIpV6Port(unsigned short const portNumber,TChanSwitch ** const chanSwitchPP,const char ** const errorP)716 switchCreateIpV6Port(unsigned short          const portNumber,
717                      TChanSwitch **          const chanSwitchPP,
718                      const char **           const errorP) {
719 /*----------------------------------------------------------------------------
720   Same as switchCreateIpV4Port(), except for IPv6.
721 -----------------------------------------------------------------------------*/
722     int rc;
723     rc = socket(PF_INET6, SOCK_STREAM, 0);
724     if (rc < 0)
725         xmlrpc_asprintf(errorP, "socket() failed with errno %d (%s)",
726                         errno, strerror(errno));
727     else {
728         int const socketFd = rc;
729 
730         sockutil_setSocketOptions(socketFd, errorP);
731         if (!*errorP) {
732             sockutil_bindSocketToPortInet6(socketFd, portNumber, errorP);
733 
734             if (!*errorP) {
735                 bool const userSupplied = false;
736                 createChanSwitch(socketFd, userSupplied, chanSwitchPP, errorP);
737             }
738         }
739         if (*errorP)
740             close(socketFd);
741     }
742 }
743 
744 
745 
746 void
ChanSwitchUnixCreate(unsigned short const portNumber,TChanSwitch ** const chanSwitchPP,const char ** const errorP)747 ChanSwitchUnixCreate(unsigned short const portNumber,
748                      TChanSwitch ** const chanSwitchPP,
749                      const char **  const errorP) {
750 
751     switchCreateIpV4Port(portNumber, chanSwitchPP, errorP);
752 }
753 
754 
755 
756 void
ChanSwitchUnixCreate2(int const protocolFamily,const struct sockaddr * const sockAddrP,socklen_t const sockAddrLen,TChanSwitch ** const chanSwitchPP,const char ** const errorP)757 ChanSwitchUnixCreate2(int                     const protocolFamily,
758                       const struct sockaddr * const sockAddrP,
759                       socklen_t               const sockAddrLen,
760                       TChanSwitch **          const chanSwitchPP,
761                       const char **           const errorP) {
762 
763     int rc;
764     rc = socket(protocolFamily, SOCK_STREAM, 0);
765     if (rc < 0)
766         xmlrpc_asprintf(errorP, "socket() failed with errno %d (%s)",
767                         errno, strerror(errno));
768     else {
769         int const socketFd = rc;
770 
771         if (SwitchTraceIsActive)
772             fprintf(stderr, "Created socket for protocol family %d\n",
773                     protocolFamily);
774 
775         sockutil_setSocketOptions(socketFd, errorP);
776         if (!*errorP) {
777             sockutil_bindSocketToPort(socketFd, sockAddrP, sockAddrLen,
778                                       errorP);
779 
780             if (!*errorP) {
781                 bool const userSupplied = false;
782                 createChanSwitch(socketFd, userSupplied, chanSwitchPP, errorP);
783             }
784         }
785         if (*errorP)
786             close(socketFd);
787     }
788 
789 }
790 
791 
792 
793 void
ChanSwitchUnixCreateIpV6Port(unsigned short const portNumber,TChanSwitch ** const chanSwitchPP,const char ** const errorP)794 ChanSwitchUnixCreateIpV6Port(unsigned short const portNumber,
795                              TChanSwitch ** const chanSwitchPP,
796                              const char **  const errorP) {
797 
798     switchCreateIpV6Port(portNumber, chanSwitchPP, errorP);
799 }
800 
801 
802 
803 void
ChanSwitchUnixCreateFd(int const fd,TChanSwitch ** const chanSwitchPP,const char ** const errorP)804 ChanSwitchUnixCreateFd(int            const fd,
805                        TChanSwitch ** const chanSwitchPP,
806                        const char **  const errorP) {
807 
808     if (sockutil_connected(fd))
809         xmlrpc_asprintf(errorP,
810                         "Socket (file descriptor %d) is in connected "
811                         "state.", fd);
812     else {
813         bool const userSupplied = true;
814         createChanSwitch(fd, userSupplied, chanSwitchPP, errorP);
815     }
816 }
817 
818 
819 
820 void
ChanSwitchUnixGetListenName(TChanSwitch * const chanSwitchP,struct sockaddr ** const sockaddrPP,size_t * const sockaddrLenP,const char ** const errorP)821 ChanSwitchUnixGetListenName(TChanSwitch *      const chanSwitchP,
822                             struct sockaddr ** const sockaddrPP,
823                             size_t  *          const sockaddrLenP,
824                             const char **      const errorP) {
825 /*----------------------------------------------------------------------------
826    The primary case where this is useful is where the user created the channel
827    switch with a parameters telling the OS to pick the TCP port.  In that
828    case, this is the only way the user can find out what port the OS picked.
829 -----------------------------------------------------------------------------*/
830     struct socketUnix * const socketUnixP = chanSwitchP->implP;
831 
832     if (!socketUnixP->isListening)
833         xmlrpc_asprintf(errorP, "Channel Switch is not listening");
834     else
835         sockutil_getSockName(socketUnixP->fd,
836                              sockaddrPP, sockaddrLenP, errorP);
837 }
838 
839 
840 
841 /*=============================================================================
842       obsolete TSocket interface
843 =============================================================================*/
844 
845 
846 void
SocketUnixCreateFd(int const fd,TSocket ** const socketPP)847 SocketUnixCreateFd(int        const fd,
848                    TSocket ** const socketPP) {
849 
850     TSocket * socketP;
851     const char * error;
852 
853     if (sockutil_connected(fd)) {
854         TChannel * channelP;
855         struct abyss_unix_chaninfo * channelInfoP;
856         ChannelUnixCreateFd(fd, &channelP, &channelInfoP, &error);
857         if (!error)
858             SocketCreateChannel(channelP, channelInfoP, &socketP);
859     } else {
860         TChanSwitch * chanSwitchP;
861         ChanSwitchUnixCreateFd(fd, &chanSwitchP, &error);
862         if (!error)
863             SocketCreateChanSwitch(chanSwitchP, &socketP);
864     }
865     if (error) {
866         *socketPP = NULL;
867         xmlrpc_strfree(error);
868     } else
869         *socketPP = socketP;
870 }
871 
872 
873 
874