abyss_socket_unix.c

Go to the documentation of this file.
00001 /******************************************************************************
00002 **
00003 ** socket_unix.c
00004 **
00005 ** This file is part of the ABYSS Web server project.
00006 **
00007 ** Copyright (C) 2000 by Moez Mahfoudh <mmoez@bigfoot.com>.
00008 ** All rights reserved.
00009 **
00010 ** Redistribution and use in source and binary forms, with or without
00011 ** modification, are permitted provided that the following conditions
00012 ** are met:
00013 ** 1. Redistributions of source code must retain the above copyright
00014 **    notice, this list of conditions and the following disclaimer.
00015 ** 2. Redistributions in binary form must reproduce the above copyright
00016 **    notice, this list of conditions and the following disclaimer in the
00017 **    documentation and/or other materials provided with the distribution.
00018 ** 3. The name of the author may not be used to endorse or promote products
00019 **    derived from this software without specific prior written permission.
00020 ** 
00021 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
00022 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00023 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00024 ** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
00025 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00026 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00027 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00028 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00030 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00031 ** SUCH DAMAGE.
00032 **
00033 *******************************************************************************/
00034 
00035 /*=============================================================================
00036                                  socket_unix.c
00037 ===============================================================================
00038   This is the implementation of TSocket for a standard Unix (POSIX)
00039   stream socket -- what you create with a socket() C library call.
00040 =============================================================================*/
00041 
00042 #include <xmlrpc-c/config.h>
00043 
00044 #include <stdlib.h>
00045 #include <assert.h>
00046 #include <sys/types.h>
00047 #include <unistd.h>
00048 #include <stdio.h>
00049 #include <string.h>
00050 #include <sys/socket.h>
00051 #include <sys/time.h>
00052 #include <netinet/in.h>
00053 #include <netinet/tcp.h>
00054 #include <netdb.h>
00055 #include <arpa/inet.h>
00056 #include <errno.h>
00057 
00058 #if HAVE_SYS_FILIO_H
00059   #include <sys/filio.h>
00060 #endif
00061 //#if HAVE_SYS_IOCTL_H
00062   #include <sys/ioctl.h>
00063 //#endif
00064 
00065 #include "abyss_xmlrpc_int.h"
00066 #include "abyss_mallocvar.h"
00067 #include "abyss_trace.h"
00068 #include "abyss_socket.h"
00069 #include <xmlrpc-c/abyss.h>
00070 
00071 #include "abyss_socket_unix.h"
00072 
00073 
00074 
00075 struct socketUnix {
00076 /*----------------------------------------------------------------------------
00077    The properties/state of a TSocket unique to a Unix TSocket.
00078 -----------------------------------------------------------------------------*/
00079     int fd;
00080         /* File descriptor of the POSIX socket (such as is created by
00081            socket() in the C library) on which the TSocket is based.
00082         */
00083     abyss_bool userSuppliedFd;
00084         /* The file descriptor and associated POSIX socket belong to the
00085            user; we did not create it.
00086         */
00087 };
00088 
00089 
00090 void
00091 SocketUnixInit(abyss_bool * const succeededP) {
00092 
00093     *succeededP = TRUE;
00094 }
00095 
00096 
00097 
00098 void
00099 SocketUnixTerm(void) {
00100 
00101 }
00102 
00103 
00104 
00105 static SocketDestroyImpl            socketDestroy;
00106 static SocketWriteImpl              socketWrite;
00107 static SocketReadImpl               socketRead;
00108 static SocketConnectImpl            socketConnect;
00109 static SocketBindImpl               socketBind;
00110 static SocketListenImpl             socketListen;
00111 static SocketAcceptImpl             socketAccept;
00112 static SocketErrorImpl              socketError;
00113 static SocketWaitImpl               socketWait;
00114 static SocketAvailableReadBytesImpl socketAvailableReadBytes;
00115 static SocketGetPeerNameImpl        socketGetPeerName;
00116 
00117 
00118 static struct TSocketVtbl const vtbl = {
00119     &socketDestroy,
00120     &socketWrite,
00121     &socketRead,
00122     &socketConnect,
00123     &socketBind,
00124     &socketListen,
00125     &socketAccept,
00126     &socketError,
00127     &socketWait,
00128     &socketAvailableReadBytes,
00129     &socketGetPeerName
00130 };
00131 
00132 
00133 
00134 void
00135 SocketUnixCreate(TSocket ** const socketPP) {
00136 
00137     struct socketUnix * socketUnixP;
00138 
00139     MALLOCVAR(socketUnixP);
00140 
00141     if (socketUnixP) {
00142         int rc;
00143         rc = socket(AF_INET, SOCK_STREAM, 0);
00144         if (rc < 0)
00145             *socketPP = NULL;
00146         else {
00147             socketUnixP->fd = rc;
00148             socketUnixP->userSuppliedFd = FALSE;
00149             
00150             {
00151                 int32_t n = 1;
00152                 int rc;
00153                 rc = setsockopt(socketUnixP->fd, SOL_SOCKET, SO_REUSEADDR,
00154                                 (char*)&n, sizeof(n));
00155                 if (rc < 0)
00156                     *socketPP = NULL;
00157                 else
00158                     SocketCreate(&vtbl, socketUnixP, socketPP);
00159             }
00160             if (!*socketPP)
00161                 close(socketUnixP->fd);
00162         }
00163         if (!*socketPP)
00164             free(socketUnixP);
00165     } else
00166         *socketPP = NULL;
00167 }
00168 
00169 
00170 
00171 void
00172 SocketUnixCreateFd(int        const fd,
00173                    TSocket ** const socketPP) {
00174 
00175     struct socketUnix * socketUnixP;
00176 
00177     MALLOCVAR(socketUnixP);
00178 
00179     if (socketUnixP) {
00180         socketUnixP->fd = fd;
00181         socketUnixP->userSuppliedFd = TRUE;
00182 
00183         SocketCreate(&vtbl, socketUnixP, socketPP);
00184 
00185         if (!*socketPP)
00186             free(socketUnixP);
00187     } else
00188         *socketPP = NULL;
00189 }
00190 
00191 
00192 
00193 static void
00194 socketDestroy(TSocket * const socketP) {
00195 
00196     struct socketUnix * const socketUnixP = socketP->implP;
00197 
00198     if (!socketUnixP->userSuppliedFd)
00199         close(socketUnixP->fd);
00200 
00201     free(socketUnixP);
00202 }
00203 
00204 
00205 
00206 static void
00207 socketWrite(TSocket *             const socketP,
00208             const unsigned char * const buffer,
00209             uint32_t              const len,
00210             abyss_bool *          const failedP) {
00211 
00212     struct socketUnix * const socketUnixP = socketP->implP;
00213 
00214     size_t bytesLeft;
00215     abyss_bool error;
00216 
00217     assert(sizeof(size_t) >= sizeof(len));
00218 
00219     for (bytesLeft = len, error = FALSE;
00220          bytesLeft > 0 && !error;
00221         ) {
00222         size_t const maxSend = (size_t)(-1) >> 1;
00223 
00224         ssize_t rc;
00225         
00226         rc = send(socketUnixP->fd, &buffer[len-bytesLeft],
00227                   MIN(maxSend, bytesLeft), 0);
00228 
00229         if (SocketTraceIsActive) {
00230             if (rc < 0)
00231                 fprintf(stderr, "Abyss socket: send() failed.  errno=%d (%s)",
00232                         errno, strerror(errno));
00233             else if (rc == 0)
00234                 fprintf(stderr, "Abyss socket: send() failed.  "
00235                         "Socket closed.\n");
00236             else
00237                 fprintf(stderr, "Abyss socket: sent %u bytes: '%.*s'\n",
00238                         (unsigned int)-rc, (int)-rc, &buffer[len-bytesLeft]);
00239         }
00240         if (rc <= 0)
00241             /* 0 means connection closed; < 0 means severe error */
00242             error = TRUE;
00243         else
00244             bytesLeft -= rc;
00245     }
00246     *failedP = error;
00247 }
00248 
00249 
00250 
00251 static uint32_t
00252 socketRead(TSocket * const socketP, 
00253            char *    const buffer, 
00254            uint32_t  const len) {
00255 
00256     struct socketUnix * const socketUnixP = socketP->implP;
00257 
00258     int rc;
00259     rc = recv(socketUnixP->fd, buffer, len, 0);
00260     if (SocketTraceIsActive) {
00261         if (rc < 0)
00262             fprintf(stderr, "Abyss socket: recv() failed.  errno=%d (%s)",
00263                     errno, strerror(errno));
00264         else 
00265             fprintf(stderr, "Abyss socket: read %u bytes: '%.*s'\n",
00266                     len, (int)len, buffer);
00267     }
00268     return rc;
00269 }
00270 
00271 
00272 
00273 abyss_bool
00274 socketConnect(TSocket * const socketP,
00275               TIPAddr * const addrP,
00276               uint16_t  const portNumber) {
00277 
00278     struct socketUnix * const socketUnixP = socketP->implP;
00279 
00280     struct sockaddr_in name;
00281     int rc;
00282 
00283     name.sin_family = AF_INET;
00284     name.sin_port = htons(portNumber);
00285     name.sin_addr = *addrP;
00286 
00287     rc = connect(socketUnixP->fd, (struct sockaddr *)&name, sizeof(name));
00288 
00289     return rc != -1;
00290 }
00291 
00292 
00293 
00294 abyss_bool
00295 socketBind(TSocket * const socketP,
00296            TIPAddr * const addrP,
00297            uint16_t  const portNumber) {
00298 
00299     struct socketUnix * const socketUnixP = socketP->implP;
00300 
00301     struct sockaddr_in name;
00302     int rc;
00303 
00304     name.sin_family = AF_INET;
00305     name.sin_port   = htons(portNumber);
00306     if (addrP)
00307         name.sin_addr = *addrP;
00308     else
00309         name.sin_addr.s_addr = INADDR_ANY;
00310 
00311     rc = bind(socketUnixP->fd, (struct sockaddr *)&name, sizeof(name));
00312 
00313     return (rc != -1);
00314 }
00315 
00316 
00317 
00318 abyss_bool
00319 socketListen(TSocket * const socketP,
00320              uint32_t  const backlog) {
00321 
00322     struct socketUnix * const socketUnixP = socketP->implP;
00323 
00324     int32_t const minus1 = -1;
00325 
00326     int rc;
00327 
00328     /* Disable the Nagle algorithm to make persistant connections faster */
00329 
00330     setsockopt(socketUnixP->fd, IPPROTO_TCP,TCP_NODELAY,
00331                &minus1, sizeof(minus1));
00332 
00333     rc = listen(socketUnixP->fd, backlog);
00334 
00335     return (rc != -1);
00336 }
00337 
00338 
00339 
00340 static void
00341 socketAccept(TSocket *    const listenSocketP,
00342              abyss_bool * const connectedP,
00343              abyss_bool * const failedP,
00344              TSocket **   const acceptedSocketPP,
00345              TIPAddr *    const ipAddrP) {
00346 /*----------------------------------------------------------------------------
00347    Accept a connection on the listening socket 'listenSocketP'.  Return as
00348    *acceptedSocketPP the socket for the accepted connection.
00349 
00350    If no connection is waiting on 'listenSocketP', wait until one is.
00351 
00352    If we receive a signal while waiting, return immediately.
00353 
00354    Return *connectedP true iff we accepted a connection.  Return
00355    *failedP true iff we were unable to accept a connection for some
00356    reason other than that we were interrupted.  Return both false if
00357    our wait for a connection was interrupted by a signal.
00358 -----------------------------------------------------------------------------*/
00359     struct socketUnix * const listenSocketUnixP = listenSocketP->implP;
00360 
00361     abyss_bool connected, failed, interrupted;
00362 
00363     connected  = FALSE;
00364     failed      = FALSE;
00365     interrupted = FALSE;
00366 
00367     while (!connected && !failed && !interrupted) {
00368         struct sockaddr_in sa;
00369         socklen_t size = sizeof(sa);
00370         int rc;
00371         rc = accept(listenSocketUnixP->fd, (struct sockaddr *)&sa, &size);
00372         if (rc >= 0) {
00373             int const acceptedFd = rc;
00374             struct socketUnix * acceptedSocketUnixP;
00375 
00376             MALLOCVAR(acceptedSocketUnixP);
00377 
00378             if (acceptedSocketUnixP) {
00379                 acceptedSocketUnixP->fd = acceptedFd;
00380                 acceptedSocketUnixP->userSuppliedFd = FALSE;
00381                 
00382                 SocketCreate(&vtbl, acceptedSocketUnixP, acceptedSocketPP);
00383                 if (!*acceptedSocketPP)
00384                     failed = TRUE;
00385                 else {
00386                     connected = TRUE;
00387                     *ipAddrP = sa.sin_addr;
00388                 }
00389                 if (failed)
00390                     free(acceptedSocketUnixP);
00391             } else
00392                 failed = TRUE;
00393             if (failed)
00394                 close(acceptedFd);
00395         } else if (errno == EINTR)
00396             interrupted = TRUE;
00397         else
00398             failed = TRUE;
00399     }   
00400     *failedP    = failed;
00401     *connectedP = connected;
00402 }
00403 
00404 
00405 
00406 static uint32_t
00407 socketWait(TSocket *  const socketP,
00408            abyss_bool const rd,
00409            abyss_bool const wr,
00410            uint32_t   const timems) {
00411 
00412     struct socketUnix * const socketUnixP = socketP->implP;
00413 
00414     fd_set rfds, wfds;
00415     struct timeval tv;
00416 
00417     FD_ZERO(&rfds);
00418     FD_ZERO(&wfds);
00419 
00420     if (rd)
00421         FD_SET(socketUnixP->fd, &rfds);
00422 
00423     if (wr)
00424         FD_SET(socketUnixP->fd, &wfds);
00425 
00426     tv.tv_sec  = timems / 1000;
00427     tv.tv_usec = timems % 1000;
00428 
00429     for (;;) {
00430         int rc;
00431 
00432         rc = select(socketUnixP->fd + 1, &rfds, &wfds, NULL,
00433                     (timems == TIME_INFINITE ? NULL : &tv));
00434 
00435         switch(rc) {   
00436         case 0: /* time out */
00437             return 0;
00438 
00439         case -1:  /* socket error */
00440             if (errno == EINTR)
00441                 break;
00442             
00443             return 0;
00444             
00445         default:
00446             if (FD_ISSET(socketUnixP->fd, &rfds))
00447                 return 1;
00448             if (FD_ISSET(socketUnixP->fd, &wfds))
00449                 return 2;
00450             return 0;
00451         }
00452     }
00453 }
00454 
00455 
00456 
00457 static uint32_t
00458 socketAvailableReadBytes(TSocket * const socketP) {
00459 
00460     struct socketUnix * const socketUnixP = socketP->implP;
00461 
00462     uint32_t x;
00463     int rc;
00464 
00465     rc = ioctl(socketUnixP->fd, FIONREAD, &x);
00466 
00467     return rc == 0 ? x : 0;
00468 }
00469 
00470 
00471 
00472 static void
00473 socketGetPeerName(TSocket *    const socketP,
00474                   TIPAddr *    const ipAddrP,
00475                   uint16_t *   const portNumberP,
00476                   abyss_bool * const successP) {
00477 
00478     struct socketUnix * const socketUnixP = socketP->implP;
00479 
00480     socklen_t addrlen;
00481     int rc;
00482     struct sockaddr sockAddr;
00483 
00484     addrlen = sizeof(sockAddr);
00485     
00486     rc = getpeername(socketUnixP->fd, &sockAddr, &addrlen);
00487 
00488     if (rc < 0) {
00489         TraceMsg("getpeername() failed.  errno=%d (%s)",
00490                  errno, strerror(errno));
00491         *successP = FALSE;
00492     } else {
00493         if (addrlen != sizeof(sockAddr)) {
00494             TraceMsg("getpeername() returned a socket address of the wrong "
00495                      "size: %u.  Expected %u", addrlen, sizeof(sockAddr));
00496             *successP = FALSE;
00497         } else {
00498             if (sockAddr.sa_family != AF_INET) {
00499                 TraceMsg("Socket does not use the Inet (IP) address "
00500                          "family.  Instead it uses family %d",
00501                          sockAddr.sa_family);
00502                 *successP = FALSE;
00503             } else {
00504                 struct sockaddr_in * const sockAddrInP = (struct sockaddr_in *)
00505                     &sockAddr;
00506 
00507                 *ipAddrP     = sockAddrInP->sin_addr;
00508                 *portNumberP = sockAddrInP->sin_port;
00509 
00510                 *successP = TRUE;
00511             }
00512         }
00513     }
00514 }
00515 
00516 
00517 
00518 static uint32_t
00519 socketError(TSocket * const socketP) {
00520 
00521     if (socketP){} /* defeat compiler warning */
00522 
00523     return errno;
00524 }

Generated on Thu May 17 10:00:23 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6