initial load of upstream version 1.06.32
[xmlrpc-c] / lib / abyss / src / socket_unix.c
1 /*=============================================================================
2                                  socket_unix.c
3 ===============================================================================
4   This is the implementation of TSocket for a standard Unix (POSIX)
5   stream socket -- what you create with a socket() C library call.
6 =============================================================================*/
7
8 #include "xmlrpc_config.h"
9
10 #include <stdlib.h>
11 #include <assert.h>
12 #include <sys/types.h>
13 #include <unistd.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <sys/socket.h>
17 #include <sys/time.h>
18 #include <netinet/in.h>
19 #include <netinet/tcp.h>
20 #include <netdb.h>
21 #include <arpa/inet.h>
22 #include <errno.h>
23
24 #if HAVE_SYS_FILIO_H
25   #include <sys/filio.h>
26 #endif
27 #if HAVE_SYS_IOCTL_H
28   #include <sys/ioctl.h>
29 #endif
30
31 #include "xmlrpc-c/util_int.h"
32 #include "mallocvar.h"
33 #include "trace.h"
34 #include "socket.h"
35 #include "xmlrpc-c/abyss.h"
36
37 #include "socket_unix.h"
38
39
40
41 struct socketUnix {
42 /*----------------------------------------------------------------------------
43    The properties/state of a TSocket unique to a Unix TSocket.
44 -----------------------------------------------------------------------------*/
45     int fd;
46         /* File descriptor of the POSIX socket (such as is created by
47            socket() in the C library) on which the TSocket is based.
48         */
49     abyss_bool userSuppliedFd;
50         /* The file descriptor and associated POSIX socket belong to the
51            user; we did not create it.
52         */
53 };
54
55
56 void
57 SocketUnixInit(abyss_bool * const succeededP) {
58
59     *succeededP = TRUE;
60 }
61
62
63
64 void
65 SocketUnixTerm(void) {
66
67 }
68
69
70
71 static SocketDestroyImpl            socketDestroy;
72 static SocketWriteImpl              socketWrite;
73 static SocketReadImpl               socketRead;
74 static SocketConnectImpl            socketConnect;
75 static SocketBindImpl               socketBind;
76 static SocketListenImpl             socketListen;
77 static SocketAcceptImpl             socketAccept;
78 static SocketErrorImpl              socketError;
79 static SocketWaitImpl               socketWait;
80 static SocketAvailableReadBytesImpl socketAvailableReadBytes;
81 static SocketGetPeerNameImpl        socketGetPeerName;
82
83
84 static struct TSocketVtbl const vtbl = {
85     &socketDestroy,
86     &socketWrite,
87     &socketRead,
88     &socketConnect,
89     &socketBind,
90     &socketListen,
91     &socketAccept,
92     &socketError,
93     &socketWait,
94     &socketAvailableReadBytes,
95     &socketGetPeerName
96 };
97
98
99
100 void
101 SocketUnixCreate(TSocket ** const socketPP) {
102
103     struct socketUnix * socketUnixP;
104
105     MALLOCVAR(socketUnixP);
106
107     if (socketUnixP) {
108         int rc;
109         rc = socket(AF_INET, SOCK_STREAM, 0);
110         if (rc < 0)
111             *socketPP = NULL;
112         else {
113             socketUnixP->fd = rc;
114             socketUnixP->userSuppliedFd = FALSE;
115             
116             {
117                 int32_t n = 1;
118                 int rc;
119                 rc = setsockopt(socketUnixP->fd, SOL_SOCKET, SO_REUSEADDR,
120                                 (char*)&n, sizeof(n));
121                 if (rc < 0)
122                     *socketPP = NULL;
123                 else
124                     SocketCreate(&vtbl, socketUnixP, socketPP);
125             }
126             if (!*socketPP)
127                 close(socketUnixP->fd);
128         }
129         if (!*socketPP)
130             free(socketUnixP);
131     } else
132         *socketPP = NULL;
133 }
134
135
136
137 void
138 SocketUnixCreateFd(int        const fd,
139                    TSocket ** const socketPP) {
140
141     struct socketUnix * socketUnixP;
142
143     MALLOCVAR(socketUnixP);
144
145     if (socketUnixP) {
146         socketUnixP->fd = fd;
147         socketUnixP->userSuppliedFd = TRUE;
148
149         SocketCreate(&vtbl, socketUnixP, socketPP);
150
151         if (!*socketPP)
152             free(socketUnixP);
153     } else
154         *socketPP = NULL;
155 }
156
157
158
159 static void
160 socketDestroy(TSocket * const socketP) {
161
162     struct socketUnix * const socketUnixP = socketP->implP;
163
164     if (!socketUnixP->userSuppliedFd)
165         close(socketUnixP->fd);
166
167     free(socketUnixP);
168 }
169
170
171
172 static void
173 socketWrite(TSocket *             const socketP,
174             const unsigned char * const buffer,
175             uint32_t              const len,
176             abyss_bool *          const failedP) {
177
178     struct socketUnix * const socketUnixP = socketP->implP;
179
180     size_t bytesLeft;
181     abyss_bool error;
182
183     assert(sizeof(size_t) >= sizeof(len));
184
185     for (bytesLeft = len, error = FALSE;
186          bytesLeft > 0 && !error;
187         ) {
188         size_t const maxSend = (size_t)(-1) >> 1;
189
190         ssize_t rc;
191         
192         rc = send(socketUnixP->fd, &buffer[len-bytesLeft],
193                   MIN(maxSend, bytesLeft), 0);
194
195         if (SocketTraceIsActive) {
196             if (rc < 0)
197                 fprintf(stderr, "Abyss socket: send() failed.  errno=%d (%s)",
198                         errno, strerror(errno));
199             else if (rc == 0)
200                 fprintf(stderr, "Abyss socket: send() failed.  "
201                         "Socket closed.\n");
202             else
203                 fprintf(stderr, "Abyss socket: sent %u bytes: '%.*s'\n",
204                         rc, rc, &buffer[len-bytesLeft]);
205         }
206         if (rc <= 0)
207             /* 0 means connection closed; < 0 means severe error */
208             error = TRUE;
209         else
210             bytesLeft -= rc;
211     }
212     *failedP = error;
213 }
214
215
216
217 static uint32_t
218 socketRead(TSocket * const socketP, 
219            char *    const buffer, 
220            uint32_t  const len) {
221
222     struct socketUnix * const socketUnixP = socketP->implP;
223
224     int rc;
225     rc = recv(socketUnixP->fd, buffer, len, 0);
226     if (SocketTraceIsActive) {
227         if (rc < 0)
228             fprintf(stderr, "Abyss socket: recv() failed.  errno=%d (%s)",
229                     errno, strerror(errno));
230         else 
231             fprintf(stderr, "Abyss socket: read %u bytes: '%.*s'\n",
232                     len, (int)len, buffer);
233     }
234     return rc;
235 }
236
237
238
239 abyss_bool
240 socketConnect(TSocket * const socketP,
241               TIPAddr * const addrP,
242               uint16_t  const portNumber) {
243
244     struct socketUnix * const socketUnixP = socketP->implP;
245
246     struct sockaddr_in name;
247     int rc;
248
249     name.sin_family = AF_INET;
250     name.sin_port = htons(portNumber);
251     name.sin_addr = *addrP;
252
253     rc = connect(socketUnixP->fd, (struct sockaddr *)&name, sizeof(name));
254
255     return rc != -1;
256 }
257
258
259
260 abyss_bool
261 socketBind(TSocket * const socketP,
262            TIPAddr * const addrP,
263            uint16_t  const portNumber) {
264
265     struct socketUnix * const socketUnixP = socketP->implP;
266
267     struct sockaddr_in name;
268     int rc;
269
270     name.sin_family = AF_INET;
271     name.sin_port   = htons(portNumber);
272     if (addrP)
273         name.sin_addr = *addrP;
274     else
275         name.sin_addr.s_addr = INADDR_ANY;
276
277     rc = bind(socketUnixP->fd, (struct sockaddr *)&name, sizeof(name));
278
279     return (rc != -1);
280 }
281
282
283
284 abyss_bool
285 socketListen(TSocket * const socketP,
286              uint32_t  const backlog) {
287
288     struct socketUnix * const socketUnixP = socketP->implP;
289
290     int32_t const minus1 = -1;
291
292     int rc;
293
294     /* Disable the Nagle algorithm to make persistant connections faster */
295
296     setsockopt(socketUnixP->fd, IPPROTO_TCP,TCP_NODELAY,
297                &minus1, sizeof(minus1));
298
299     rc = listen(socketUnixP->fd, backlog);
300
301     return (rc != -1);
302 }
303
304
305
306 static void
307 socketAccept(TSocket *    const listenSocketP,
308              abyss_bool * const connectedP,
309              abyss_bool * const failedP,
310              TSocket **   const acceptedSocketPP,
311              TIPAddr *    const ipAddrP) {
312 /*----------------------------------------------------------------------------
313    Accept a connection on the listening socket 'listenSocketP'.  Return as
314    *acceptedSocketPP the socket for the accepted connection.
315
316    If no connection is waiting on 'listenSocketP', wait until one is.
317
318    If we receive a signal while waiting, return immediately.
319
320    Return *connectedP true iff we accepted a connection.  Return
321    *failedP true iff we were unable to accept a connection for some
322    reason other than that we were interrupted.  Return both false if
323    our wait for a connection was interrupted by a signal.
324 -----------------------------------------------------------------------------*/
325     struct socketUnix * const listenSocketUnixP = listenSocketP->implP;
326
327     abyss_bool connected, failed, interrupted;
328
329     connected  = FALSE;
330     failed      = FALSE;
331     interrupted = FALSE;
332
333     while (!connected && !failed && !interrupted) {
334         struct sockaddr_in sa;
335         socklen_t size = sizeof(sa);
336         int rc;
337         rc = accept(listenSocketUnixP->fd, (struct sockaddr *)&sa, &size);
338         if (rc >= 0) {
339             int const acceptedFd = rc;
340             struct socketUnix * acceptedSocketUnixP;
341
342             MALLOCVAR(acceptedSocketUnixP);
343
344             if (acceptedSocketUnixP) {
345                 acceptedSocketUnixP->fd = acceptedFd;
346                 acceptedSocketUnixP->userSuppliedFd = FALSE;
347                 
348                 SocketCreate(&vtbl, acceptedSocketUnixP, acceptedSocketPP);
349                 if (!*acceptedSocketPP)
350                     failed = TRUE;
351                 else {
352                     connected = TRUE;
353                     *ipAddrP = sa.sin_addr;
354                 }
355                 if (failed)
356                     free(acceptedSocketUnixP);
357             } else
358                 failed = TRUE;
359             if (failed)
360                 close(acceptedFd);
361         } else if (errno == EINTR)
362             interrupted = TRUE;
363         else
364             failed = TRUE;
365     }   
366     *failedP    = failed;
367     *connectedP = connected;
368 }
369
370
371
372 static uint32_t
373 socketWait(TSocket *  const socketP,
374            abyss_bool const rd,
375            abyss_bool const wr,
376            uint32_t   const timems) {
377
378     struct socketUnix * const socketUnixP = socketP->implP;
379
380     fd_set rfds, wfds;
381     struct timeval tv;
382
383     if (SocketTraceIsActive)
384         fprintf(stderr, "Waiting %u milliseconds for %s %s of socket\n",
385                 timems, rd ? "READ" : "", wr ? "WRITE" : "");
386
387     FD_ZERO(&rfds);
388     FD_ZERO(&wfds);
389
390     if (rd)
391         FD_SET(socketUnixP->fd, &rfds);
392
393     if (wr)
394         FD_SET(socketUnixP->fd, &wfds);
395
396     tv.tv_sec  = timems / 1000;
397     tv.tv_usec = timems % 1000;
398
399     for (;;) {
400         int rc;
401
402         rc = select(socketUnixP->fd + 1, &rfds, &wfds, NULL,
403                     (timems == TIME_INFINITE ? NULL : &tv));
404
405         switch(rc) {   
406         case 0: /* time out */
407             return 0;
408
409         case -1:  /* socket error */
410             if (errno == EINTR)
411                 break;
412             
413             return 0;
414             
415         default:
416             if (FD_ISSET(socketUnixP->fd, &rfds))
417                 return 1;
418             if (FD_ISSET(socketUnixP->fd, &wfds))
419                 return 2;
420             return 0;
421         }
422     }
423 }
424
425
426
427 static uint32_t
428 socketAvailableReadBytes(TSocket * const socketP) {
429
430     struct socketUnix * const socketUnixP = socketP->implP;
431
432     uint32_t x;
433     int rc;
434
435     rc = ioctl(socketUnixP->fd, FIONREAD, &x);
436
437     if (SocketTraceIsActive) {
438         if (rc == 0)
439             fprintf(stderr, "Socket has %u bytes available\n", x);
440         else
441             fprintf(stderr, "ioctl(FIONREAD) failed, errno=%d (%s)\n",
442                     errno, strerror(errno));
443     }
444     return rc == 0 ? x : 0;
445 }
446
447
448
449 static void
450 socketGetPeerName(TSocket *    const socketP,
451                   TIPAddr *    const ipAddrP,
452                   uint16_t *   const portNumberP,
453                   abyss_bool * const successP) {
454
455     struct socketUnix * const socketUnixP = socketP->implP;
456
457     socklen_t addrlen;
458     int rc;
459     struct sockaddr sockAddr;
460
461     addrlen = sizeof(sockAddr);
462     
463     rc = getpeername(socketUnixP->fd, &sockAddr, &addrlen);
464
465     if (rc < 0) {
466         TraceMsg("getpeername() failed.  errno=%d (%s)",
467                  errno, strerror(errno));
468         *successP = FALSE;
469     } else {
470         if (addrlen != sizeof(sockAddr)) {
471             TraceMsg("getpeername() returned a socket address of the wrong "
472                      "size: %u.  Expected %u", addrlen, sizeof(sockAddr));
473             *successP = FALSE;
474         } else {
475             if (sockAddr.sa_family != AF_INET) {
476                 TraceMsg("Socket does not use the Inet (IP) address "
477                          "family.  Instead it uses family %d",
478                          sockAddr.sa_family);
479                 *successP = FALSE;
480             } else {
481                 struct sockaddr_in * const sockAddrInP = (struct sockaddr_in *)
482                     &sockAddr;
483
484                 *ipAddrP     = sockAddrInP->sin_addr;
485                 *portNumberP = sockAddrInP->sin_port;
486
487                 *successP = TRUE;
488             }
489         }
490     }
491 }
492
493
494
495 static uint32_t
496 socketError(TSocket * const socketP) {
497
498     if (socketP){} /* defeat compiler warning */
499
500     return errno;
501 }