xdasd_net.c

Go to the documentation of this file.
00001 /*----------------------------------------------------------------------------
00002  * Copyright (c) 2006, Novell, Inc.
00003  * All rights reserved.
00004  * 
00005  * Redistribution and use in source and binary forms, with or without 
00006  * modification, are permitted provided that the following conditions are 
00007  * met:
00008  * 
00009  *     * Redistributions of source code must retain the above copyright 
00010  *       notice, this list of conditions and the following disclaimer.
00011  *     * Redistributions in binary form must reproduce the above copyright 
00012  *       notice, this list of conditions and the following disclaimer in the 
00013  *       documentation and/or other materials provided with the distribution.
00014  *     * Neither the name of the Novell nor the names of its contributors 
00015  *       may be used to endorse or promote products derived from this 
00016  *       software without specific prior written permission.
00017  * 
00018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
00019  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00020  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
00021  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
00022  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
00023  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
00024  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
00025  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
00026  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
00027  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *--------------------------------------------------------------------------*/
00030 
00048 #include <xdas_base.h>
00049 #include <xdasd.h>
00050 
00051 #include "xdasd_filter.h"
00052 #include "xdasd_event.h"
00053 #include "xdasd_list.h"
00054 #include "xdasd_net.h"
00055 #include "xdasd_log.h"
00056 
00057 #include <malloc.h>
00058 #include <string.h>
00059 #include <errno.h>
00060 #include <stdio.h>
00061 
00066 #ifdef _WIN32
00067 # define socklen_t int
00068 # define so_bool_t char
00069 # define BAD_SOCKET INVALID_SOCKET
00070 
00071 /* map WSA error codes to unix names */
00072 # define EWOULDBLOCK        WSAEWOULDBLOCK
00073 # define EINPROGRESS        WSAEINPROGRESS
00074 # define EALREADY           WSAEALREADY
00075 # define ENOTSOCK           WSAENOTSOCK
00076 # define EDESTADDRREQ       WSAEDESTADDRREQ
00077 # define EMSGSIZE           WSAEMSGSIZE
00078 # define EPROTOTYPE         WSAEPROTOTYPE
00079 # define ENOPROTOOPT        WSAENOPROTOOPT
00080 # define EPROTONOSUPPORT    WSAEPROTONOSUPPORT
00081 # define ESOCKTNOSUPPORT    WSAESOCKTNOSUPPORT
00082 # define EOPNOTSUPP         WSAEOPNOTSUPP
00083 # define EPFNOSUPPORT       WSAEPFNOSUPPORT
00084 # define EAFNOSUPPORT       WSAEAFNOSUPPORT
00085 # define EADDRINUSE         WSAEADDRINUSE
00086 # define EADDRNOTAVAIL      WSAEADDRNOTAVAIL
00087 # define ENETDOWN           WSAENETDOWN
00088 # define ENETUNREACH        WSAENETUNREACH
00089 # define ENETRESET          WSAENETRESET
00090 # define ECONNABORTED       WSAECONNABORTED
00091 # define ECONNRESET         WSAECONNRESET
00092 # define ENOBUFS            WSAENOBUFS
00093 # define EISCONN            WSAEISCONN
00094 # define ENOTCONN           WSAENOTCONN
00095 # define ESHUTDOWN          WSAESHUTDOWN
00096 # define ETOOMANYREFS       WSAETOOMANYREFS
00097 # define ETIMEDOUT          WSAETIMEDOUT
00098 # define ECONNREFUSED       WSAECONNREFUSED
00099 # define ELOOP              WSAELOOP
00100 # define EHOSTDOWN          WSAEHOSTDOWN
00101 # define EHOSTUNREACH       WSAEHOSTUNREACH
00102 # define EREMOTE            WSAEREMOTE
00103 
00104 #else
00105 # include <sys/types.h>
00106 # include <sys/socket.h>
00107 # include <sys/un.h>
00108 # include <arpa/inet.h>
00109 # include <unistd.h>
00110 # include <fcntl.h>
00111 # define so_bool_t int
00112 # define BAD_SOCKET -1
00113 # define closesocket close
00114 #endif
00115 
00119 #define SOCKET_UNUSED      0
00120 #define SOCKET_CLOSE       1
00121 #define SOCKET_LISTEN      2
00122 #define STREAM_READ_FIRST  3
00123 #define STREAM_READ        4
00124 #define STREAM_WRITE_FIRST 5
00125 #define STREAM_WRITE       6
00126 /* @} */
00127 
00135 typedef struct XDASD_Socket_tag
00136 {
00137    XDLItem item;
00138    int state;
00139    sockfd_t fd;
00140    struct sockaddr_storage localaddr;
00141    struct sockaddr_storage peeraddr;
00142    xdas_buffer recvbuf;
00143    xdas_buffer sendbuf;
00144 } XDASD_Socket;
00145 
00150 static XDList s_socklist = {0, 0, 0};
00151 
00159 static XDASD_Socket * xdasd_socket_alloc(void)
00160 {
00161    XDASD_Socket * sock;
00162 
00163    if ((sock = (XDASD_Socket *)malloc(sizeof(*sock))) != 0)
00164    {
00165       memset(sock, 0, sizeof(*sock));
00166       sock->fd = BAD_SOCKET;
00167    }
00168    return sock;
00169 }
00170 
00178 static void xdasd_socket_free(XDASD_Socket * sock)
00179 {
00180    if (sock->fd != BAD_SOCKET)
00181       closesocket(sock->fd);
00182 
00183    xdas_buffer_free(sock->recvbuf);
00184    xdas_buffer_free(sock->sendbuf);
00185 
00186    free(sock);
00187 }
00188 
00196 static int xdasd_socket_error(void)
00197 {
00198 #ifdef _WIN32
00199    return (int)WSAGetLastError();
00200 #else
00201    return errno;
00202 #endif
00203 }
00204 
00214 static int xdasd_set_nonblocking(sockfd_t fd)
00215 {
00216    int err = 0;
00217 #ifdef _WIN32
00218    {
00219       u_long fdflags = 1;
00220       if ((err = ioctlsocket(fd, FIONBIO, &fdflags)) != 0)
00221          errno = WSAGetLastError();
00222    }
00223 #else
00224    {
00225       int fdflags = fcntl(fd, F_GETFL, 0);
00226       fcntl(fd, F_SETFL, fdflags | O_NONBLOCK);
00227    }
00228 #endif
00229    return err? -1: 0;
00230 }
00231 
00243 static XDASD_Socket * xdasd_create_listen_socket(const char * ipcpath)
00244 {
00245    XDASD_Socket * sock;
00246 
00247    if ((sock = xdasd_socket_alloc()) != 0)
00248    {
00249       struct sockaddr_storage ss;
00250       int addrsz = sizeof(ss);
00251 
00252       memset(&ss, 0, sizeof(ss));
00253 
00254       if (!ipcpath)
00255       {
00256          struct sockaddr_in * v4 = (struct sockaddr_in *)&ss;
00257          v4->sin_family = AF_INET;
00258          v4->sin_port = htons(XDASD_RESERVED_PORT);
00259          v4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
00260          addrsz = sizeof(*v4);
00261       }
00262 #ifndef _WIN32
00263       else
00264       {
00265          struct sockaddr_un * ud = (struct sockaddr_un *)&ss;
00266          ud->sun_family = AF_LOCAL;
00267          strncpy(ud->sun_path, ipcpath, sizeof(ud->sun_path) - 1);
00268          addrsz = sizeof(*ud);
00269       }
00270 #endif
00271 
00272       if ((sock->fd = socket(ss.ss_family, SOCK_STREAM, 0)) != BAD_SOCKET)
00273       {
00274          so_bool_t reuse = 1;
00275 
00276          setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, 
00277                (char *)&reuse, sizeof(reuse));
00278 
00279          if (bind(sock->fd, (struct sockaddr *)&ss, addrsz) == 0)
00280          {
00281             if (listen(sock->fd, 5) == 0)
00282             {
00283                memcpy(&sock->localaddr, &ss, addrsz);
00284                xdasd_set_nonblocking(sock->fd);
00285                sock->state = SOCKET_LISTEN;
00286                return sock;
00287             }
00288          }
00289       }
00290    }
00291 
00292    /* There's a problem if we get to here - clean up and return null. */
00293    if (sock)
00294       xdasd_socket_free(sock);
00295    return 0;
00296 }
00297 
00305 static void xdasd_accept(XDASD_Socket * sock)
00306 {
00307    sockfd_t fd;
00308    XDASD_Socket * connsock;
00309    struct sockaddr_storage peeraddr;
00310    socklen_t peeraddrlen = sizeof(peeraddr);
00311 
00312    if ((fd = accept(sock->fd, (struct sockaddr *)&peeraddr, 
00313          &peeraddrlen)) != BAD_SOCKET)
00314    {
00315       xdasd_set_nonblocking(sock->fd);
00316       if ((connsock = xdasd_socket_alloc()) != 0)
00317       {
00318          connsock->fd = fd;
00319          memcpy(&connsock->peeraddr, &peeraddr, peeraddrlen);
00320          memcpy(&connsock->localaddr, &peeraddr, peeraddrlen);
00321          connsock->state = STREAM_READ_FIRST;
00322          xdasd_list_link_head(&s_socklist, &connsock->item);
00323       }
00324    }
00325 }
00326 
00343 static int xdasd_net_dispatch(XDASD_Socket * sock)
00344 {
00345    static int (*handler_table[])(int*,xdas_buffer,xdas_buffer*) = 
00346    {
00347       xdasd_event_process,
00348       xdasd_filter_process,
00349    };
00350 
00351    size_t reqsz, rspsz;
00352    unsigned reqfn;
00353    int rspst, rspms = 0;
00354    xdas_buffer rsp, req = sock->recvbuf;
00355 
00356    if ((rsp = xdas_buffer_realloc(sock->sendbuf, 12)) == 0)
00357    {
00359       return (errno = ENOMEM), -1;
00360    }
00361 
00362    /* reserve space for 3 response header fields */
00363    rsp->curpos = rsp->start + 12;
00364 
00365    /* ensure request buffer contains a full request header */
00366    reqsz = xdas_buffer_get_uint32(req);
00367    if (req->end - req->curpos < 4 || (reqfn = xdas_buffer_get_uint32(req)) 
00368          >= xdas_elemcount(handler_table))
00369    {
00371       xdas_buffer_put_uint32(rsp, (unsigned)(rsp->curpos - rsp->start));
00372       xdas_buffer_put_uint32(rsp, XDAS_S_FAILURE);
00373       xdas_buffer_put_uint32(rsp, OXDAS_MS_PROTOCOL);
00374       sock->sendbuf = rsp;
00375       return 0;
00376    }
00377 
00379    /* printf("REQ: %d - %u bytes.\n", reqfn, reqsz); */
00380 
00381    /* dispatch to appropriate request handler */
00382    rspst = handler_table[reqfn](&rspms, req, &rsp);
00383 
00384    /* fill in response buffer size and response code */
00385    rspsz = rsp->curpos - rsp->start;
00386    rsp->curpos = rsp->start;
00387    xdas_buffer_put_uint32(rsp, rspsz);
00388    xdas_buffer_put_uint32(rsp, rspst);
00389    xdas_buffer_put_uint32(rsp, rspms);
00390    sock->sendbuf = rsp;
00391 
00393    /* printf("RSP: %d:%d - %u bytes.\n", rspst, rspms, rsp->curpos - rsp->start); */
00394 
00395    return 0;
00396 }
00397 
00405 static void xdasd_write_stream(XDASD_Socket * sock)
00406 {
00407    if (sock->state == STREAM_WRITE_FIRST)
00408    {
00409       sock->sendbuf->curpos = sock->sendbuf->start;
00410       sock->state = STREAM_WRITE;
00411    }
00412 
00413    /* either finish the STREAM_READ_FIRST, or do the next STREAM_READ */
00414    if (sock->sendbuf->end - sock->sendbuf->start != 0)
00415    {
00416       int byteswritten, flags = 0;
00417 #ifdef MSG_DONTWAIT
00418       flags = MSG_DONTWAIT;
00419 #endif
00420       if ((byteswritten = send(sock->fd, (char *)sock->sendbuf->curpos,
00421             (int)(sock->sendbuf->end - sock->sendbuf->start), flags)) > 0)
00422       {
00423          sock->sendbuf->curpos += byteswritten;
00424          if (sock->sendbuf->curpos == sock->sendbuf->end)
00425             sock->state = STREAM_READ_FIRST;
00426       }
00427       else if (xdasd_socket_error() != EWOULDBLOCK)
00428          sock->state = SOCKET_CLOSE;
00429    }
00430 }
00431 
00440 static void xdasd_read_stream(XDASD_Socket * sock)
00441 {
00442    int bytesread;
00443 
00444    if (sock->state == STREAM_READ_FIRST)
00445    {
00446       xdas_buffer req;
00447       size_t msgsz;
00448       char peek[4];
00449 
00450       if ((bytesread = recv(sock->fd, peek, sizeof(peek), MSG_PEEK)) <= 0)
00451       {
00452          sock->state = SOCKET_CLOSE;   /* connection reset by peer */
00453          return;
00454       }
00455 
00456       msgsz = AS_UINT32(peek);
00457       if (msgsz > MAX_XDAS_MSG_SIZE)
00458       {
00459          xdasd_log(0, "PROTOCOL_ERROR - message too large!\n");
00460          sock->state = SOCKET_CLOSE;
00461          return;
00462       }
00463       if ((req = xdas_buffer_realloc(sock->recvbuf, msgsz)) == 0)
00464       {
00465          xdasd_log(0, "INTERNAL_ERROR - out of memory!\n");
00466          sock->state = SOCKET_CLOSE;   /* out of memory */
00467          return;
00468       }
00469       req->curpos = req->start;
00470       sock->recvbuf = req;
00471       sock->state = STREAM_READ;
00472    }
00473 
00474    /* either finish the STREAM_READ_FIRST, or do the next STREAM_READ */
00475    if ((bytesread = recv(sock->fd, (char *)sock->recvbuf->curpos,
00476          (int)(sock->recvbuf->end - sock->recvbuf->curpos), 0)) <= 0)
00477    {
00478       sock->state = SOCKET_CLOSE;      /* connection reset by peer */
00479       return;
00480    }
00481 
00482    sock->recvbuf->curpos += bytesread;
00483    if (sock->recvbuf->curpos == sock->recvbuf->end)
00484    {
00485       /* reset curpos for data extraction, end ptr indicates reqsz. */
00486       sock->recvbuf->curpos = sock->recvbuf->start;
00487       if (xdasd_net_dispatch(sock) < 0)
00488       {
00489          sock->state = SOCKET_CLOSE;   /* ill-formatted request */
00490          return;
00491       }
00492 
00493       sock->state = STREAM_WRITE_FIRST;
00494       xdasd_write_stream(sock);
00495    }
00496 }
00497 
00498 /*--------------------------------------------------------------------------*/
00499 
00508 int xdasd_net_init(const char * ipcpath)
00509 {
00510    XDASD_Socket * sock;
00511 
00512 #ifdef _WIN32
00513    {
00514       WORD vreq = MAKEWORD(2,2);
00515       WSADATA wsadata;
00516       if (WSAStartup(vreq, &wsadata) != 0)
00517          return -1;
00518    }
00519 #endif
00520 
00521    /* remove all inbound sockets from the list */
00522    while (s_socklist.count)
00523       xdasd_socket_free((XDASD_Socket *)
00524             xdasd_list_unlink(&s_socklist, s_socklist.head));
00525 
00526 #ifndef _WIN32
00527    /* open unix domain socket first */
00528    if ((sock = xdasd_create_listen_socket(ipcpath)) != 0)
00529    {
00530       xdasd_list_link_tail(&s_socklist, &sock->item);
00531       xdasd_log(0, "Listening on Unix domain socket...\n");
00532    }
00533    else
00534       xdasd_log(0, "NETWORK: Could not initialize Unix domain socket.\n");
00535 #else
00536    (void)ipcpath;
00537 #endif
00538 
00539    /* now open local socket */
00540    if ((sock = xdasd_create_listen_socket(0)) != 0)
00541    {
00542       xdasd_list_link_tail(&s_socklist, &sock->item);
00543       xdasd_log(0, "Listening on TCP socket...\n");
00544    }
00545    else
00546       xdasd_log(0, "NETWORK: Could not initialize TCP socket.\n");
00547 
00548 #ifdef _WIN32
00549    if (!s_socklist.count)
00550    {
00551       errno = WSAGetLastError();
00552       WSACleanup();
00553    }
00554 #endif
00555 
00556    return s_socklist.count? 0: -1;
00557 }
00558 
00559 #ifdef _WIN32
00560 # pragma warning(push)
00561 # pragma warning(disable: 4127) /* FD_SET - conditional expr is constant */
00562 #endif
00563 
00572 void xdasd_net_load_fdsets(int * highfd, fd_set * readfds, fd_set * writefds)
00573 {
00574    XDASD_Socket * del = 0;
00575    XDASD_Socket * sock = (XDASD_Socket *)s_socklist.head;
00576 
00577    while (sock)
00578    {
00579       if (sock->fd > (sockfd_t)*highfd)
00580          *highfd = (int)sock->fd;
00581 
00582       switch(sock->state)
00583       {
00584          case SOCKET_LISTEN:
00585             FD_SET(sock->fd, readfds);
00586             break;
00587 
00588          case STREAM_READ_FIRST:
00589          case STREAM_READ:
00590             FD_SET(sock->fd, readfds);
00591             break;
00592 
00593          case STREAM_WRITE_FIRST:
00594          case STREAM_WRITE:
00595             FD_SET(sock->fd, writefds);
00596             break;
00597 
00598          case SOCKET_CLOSE:
00599             del = sock;
00600             break;
00601       }
00602       sock = (XDASD_Socket *)sock->item.next;
00603       if (del)
00604       {
00605          xdasd_socket_free((XDASD_Socket *)
00606                xdasd_list_unlink(&s_socklist, (XDLItem *)del));
00607          del = 0;
00608       }
00609    }
00610 }
00611 
00612 #ifdef _WIN32
00613 # pragma warning(pop)
00614 #endif
00615 
00625 void xdasd_net_event_handler(int fdcount, fd_set * readfds, fd_set * writefds)
00626 {
00627    XDASD_Socket * sock = (XDASD_Socket *)s_socklist.head;
00628 
00629    while (sock && fdcount)
00630    {
00631       if (FD_ISSET(sock->fd, readfds))
00632       {
00633          switch (sock->state)
00634          {
00635             case SOCKET_LISTEN:
00636                xdasd_accept(sock);
00637                break;
00638 
00639             case STREAM_READ_FIRST:
00640             case STREAM_READ:
00641                xdasd_read_stream(sock);
00642                break;
00643 
00644          }
00645          --fdcount;
00646       }
00647       else if (FD_ISSET(sock->fd, writefds))
00648       {
00649          switch (sock->state)
00650          {
00651             case STREAM_WRITE_FIRST:
00652             case STREAM_WRITE:
00653                xdasd_write_stream(sock);
00654                break;
00655          }
00656          --fdcount;
00657       }
00658       sock = (XDASD_Socket *)sock->item.next;
00659    }
00660 }
00661 
00666 void xdasd_net_exit(void)
00667 {
00668    XDASD_Socket * sock = (XDASD_Socket *)s_socklist.head;
00669    while (sock)
00670    {
00671       XDASD_Socket * del = sock;
00672       sock = (XDASD_Socket *)sock->item.next;
00673       xdasd_socket_free(del);
00674    } 
00675    s_socklist.head = s_socklist.tail = 0;
00676    s_socklist.count = 0;
00677 
00678 #ifdef _WIN32
00679    WSACleanup();
00680 #endif
00681 }
00682 

Generated on Thu Aug 20 22:33:06 2009 for OpenXDAS by  doxygen 1.5.6