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