dtn_ipc.c

Go to the documentation of this file.
00001 /*
00002  * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By
00003  * downloading, copying, installing or using the software you agree to
00004  * this license. If you do not agree to this license, do not download,
00005  * install, copy or use the software.
00006  * 
00007  * Intel Open Source License 
00008  * 
00009  * Copyright (c) 2004 Intel Corporation. All rights reserved. 
00010  * 
00011  * Redistribution and use in source and binary forms, with or without
00012  * modification, are permitted provided that the following conditions are
00013  * met:
00014  * 
00015  *   Redistributions of source code must retain the above copyright
00016  *   notice, this list of conditions and the following disclaimer.
00017  * 
00018  *   Redistributions in binary form must reproduce the above copyright
00019  *   notice, this list of conditions and the following disclaimer in the
00020  *   documentation and/or other materials provided with the distribution.
00021  * 
00022  *   Neither the name of the Intel Corporation nor the names of its
00023  *   contributors may be used to endorse or promote products derived from
00024  *   this software without specific prior written permission.
00025  *  
00026  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00027  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00028  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00029  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
00030  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00031  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00032  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00033  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00034  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00035  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00036  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00037  */
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040 #include <errno.h>
00041 #include <string.h>
00042 #include <unistd.h>
00043 #include <sys/types.h>
00044 #include <sys/socket.h>
00045 #include <netinet/in.h>
00046 #include <arpa/inet.h>
00047 #include <oasys/compat/inet_aton.h>
00048 #include <oasys/compat/inttypes.h>
00049 
00050 #include "dtn_ipc.h"
00051 #include "dtn_errno.h"
00052 #include "dtn_types.h"
00053 
00054 /* exposed globally for testing purposes only */
00055 int dtnipc_version = DTN_IPC_VERSION;
00056 
00057 const char*
00058 dtnipc_msgtoa(u_int8_t type)
00059 {
00060 #define CASE(_type) case _type : return #_type; break;
00061     
00062     switch(type) {
00063         CASE(DTN_OPEN);
00064         CASE(DTN_CLOSE);
00065         CASE(DTN_LOCAL_EID);
00066         CASE(DTN_REGISTER);
00067         CASE(DTN_UNREGISTER);
00068         CASE(DTN_FIND_REGISTRATION);
00069         CASE(DTN_CHANGE_REGISTRATION);
00070         CASE(DTN_BIND);
00071         CASE(DTN_SEND);
00072         CASE(DTN_RECV);
00073         CASE(DTN_BEGIN_POLL);
00074         CASE(DTN_CANCEL_POLL);
00075 
00076     default:
00077         return "(unknown type)";
00078     }
00079     
00080 #undef CASE
00081 }
00082 
00083 /*
00084  * Initialize the handle structure.
00085  */
00086 int
00087 dtnipc_open(dtnipc_handle_t* handle)
00088 {
00089     int ret;
00090     char *env, *end;
00091     struct sockaddr_in sa;
00092     in_addr_t ipc_addr;
00093     u_int16_t ipc_port;
00094     u_int32_t handshake;
00095     u_int port;
00096 
00097     // zero out the handle
00098     memset(handle, 0, sizeof(dtnipc_handle_t));
00099     
00100     // note that we leave eight bytes free to be used for the framing
00101     // -- the type code and length for send (which is only five
00102     // bytes), and the return code and length for recv (which is
00103     // actually eight bytes)
00104     xdrmem_create(&handle->xdr_encode, handle->buf + 8,
00105                   DTN_MAX_API_MSG, XDR_ENCODE);
00106     
00107     xdrmem_create(&handle->xdr_decode, handle->buf + 8,
00108                   DTN_MAX_API_MSG, XDR_DECODE);
00109 
00110     // open the socket
00111     handle->sock = socket(PF_INET, SOCK_STREAM, 0);
00112     if (handle->sock < 0)
00113     {
00114         handle->err = DTN_ECOMM;
00115         dtnipc_close(handle);
00116         return -1;
00117     }
00118 
00119     // check for DTNAPI environment variables overriding the address /
00120     // port defaults
00121     ipc_addr = htonl(INADDR_LOOPBACK);
00122     ipc_port = DTN_IPC_PORT;
00123     
00124     if ((env = getenv("DTNAPI_ADDR")) != NULL) {
00125         if (inet_aton(env, (struct in_addr*)&ipc_addr) == 0)
00126         {
00127             fprintf(stderr, "DTNAPI_ADDR environment variable (%s) "
00128                     "not a valid ip address\n", env);
00129             exit(1);
00130         }
00131     }
00132 
00133     if ((env = getenv("DTNAPI_PORT")) != NULL) {
00134         port = strtoul(env, &end, 10);
00135         if (*end != '\0' || port > 0xffff)
00136         {
00137             fprintf(stderr, "DTNAPI_PORT environment variable (%s) "
00138                     "not a valid ip port\n", env);
00139             exit(1);
00140         }
00141         ipc_port = (u_int16_t)port;
00142     }
00143 
00144     // connect to the server
00145     memset(&sa, 0, sizeof(sa));
00146     sa.sin_family = AF_INET;
00147     sa.sin_addr.s_addr = ipc_addr;
00148     sa.sin_port = htons(ipc_port);
00149     
00150     ret = connect(handle->sock, (const struct sockaddr*)&sa, sizeof(sa));
00151     if (ret != 0) {
00152         handle->err = DTN_ECOMM;
00153         dtnipc_close(handle);
00154         return -1;
00155     }
00156 
00157     // send the session initiation to the server on the handshake
00158     // port. it consists of DTN_OPEN in the high 16 bits and IPC
00159     // version in the low 16 bits
00160     handshake = htonl(DTN_OPEN << 16 | dtnipc_version);
00161     ret = write(handle->sock, &handshake, sizeof(handshake));
00162     if (ret != sizeof(handshake)) {
00163         handle->err = DTN_ECOMM;
00164         dtnipc_close(handle);
00165         return -1;
00166     }
00167 
00168     // wait for the handshake response
00169     handshake = 0;
00170     ret = read(handle->sock, &handshake, sizeof(handshake));
00171     if (ret != sizeof(handshake) || (ntohl(handshake) >> 16) != DTN_OPEN) {
00172         handle->err = DTN_ECOMM;
00173         dtnipc_close(handle);
00174         return -1;
00175     }
00176     
00177     if ((ntohl(handshake) & 0x0ffff) != DTN_IPC_VERSION) {
00178         handle->err = DTN_EMSGTYPE;
00179         dtnipc_close(handle);
00180         return -1;
00181     }
00182     
00183     return 0;
00184 }
00185 
00186 /*
00187  * Clean up the handle. dtnipc_open must have already been called on
00188  * the handle.
00189  */
00190 int
00191 dtnipc_close(dtnipc_handle_t* handle)
00192 {
00193     int ret;
00194     
00195     // first send a close over RPC
00196     if (handle->err != DTN_ECOMM) {
00197         ret = dtnipc_send_recv(handle, DTN_CLOSE);
00198     } else {
00199         ret = -1;
00200     }
00201     
00202     xdr_destroy(&handle->xdr_encode);
00203     xdr_destroy(&handle->xdr_decode);
00204 
00205     if (handle->sock > 0) {
00206         close(handle->sock);
00207     }
00208 
00209     handle->sock = 0;
00210 
00211     return ret;
00212 }
00213       
00214 
00215 /*
00216  * Send a message over the dtn ipc protocol.
00217  *
00218  * Returns 0 on success, -1 on error.
00219  */
00220 int
00221 dtnipc_send(dtnipc_handle_t* handle, dtnapi_message_type_t type)
00222 {
00223     int ret;
00224     size_t len, msglen;
00225     
00226     // pack the message code in the fourth byte of the buffer and the
00227     // message length into the next four. we don't use xdr routines
00228     // for these since we need to be able to decode the length on the
00229     // other side to make sure we've read the whole message, and we
00230     // need the type to know which xdr decoder to call
00231     handle->buf[3] = type;
00232 
00233     len = xdr_getpos(&handle->xdr_encode);
00234     msglen = len + 5;
00235     len = htonl(len);
00236     memcpy(&handle->buf[4], &len, sizeof(len));
00237     
00238     // reset the xdr encoder
00239     xdr_setpos(&handle->xdr_encode, 0);
00240     
00241     // send the message, looping until it's all sent
00242     char* bp = &handle->buf[3];
00243     do {
00244         ret = write(handle->sock, bp, msglen);
00245         
00246         if (ret <= 0) {
00247             if (errno == EINTR)
00248                 continue;
00249             
00250             handle->err = DTN_ECOMM;
00251             dtnipc_close(handle);
00252             return -1;
00253         }
00254 
00255         bp     += ret;
00256         msglen -= ret;
00257         
00258     } while (msglen > 0);
00259     
00260     return 0;
00261 }
00262 
00263 /*
00264  * Receive a message on the ipc channel. May block if there is no
00265  * pending message.
00266  *
00267  * Sets status to the server-returned status code and returns the
00268  * length of any reply message on success, returns -1 on internal
00269  * error.
00270  */
00271 int
00272 dtnipc_recv(dtnipc_handle_t* handle, int* status)
00273 {
00274     int ret;
00275     size_t len, nread;
00276     u_int32_t statuscode;
00277 
00278     // reset the xdr decoder before reading in any data
00279     xdr_setpos(&handle->xdr_decode, 0);
00280 
00281     // read as much as possible into the buffer
00282     ret = read(handle->sock, handle->buf, sizeof(handle->buf));
00283 
00284     // make sure we got at least the status code and length
00285     if (ret < 8) {
00286         handle->err = DTN_ECOMM;
00287         dtnipc_close(handle);
00288         return -1;
00289     }
00290     
00291     memcpy(&statuscode, handle->buf, sizeof(statuscode));
00292     statuscode = ntohl(statuscode);
00293     *status = statuscode;
00294     
00295     memcpy(&len, &handle->buf[4], sizeof(len));
00296     len = ntohl(len);
00297 
00298     // read the rest of the message if we didn't get it all
00299     nread = ret;
00300     while (nread < len + 8) {
00301         ret = read(handle->sock,
00302                    &handle->buf[nread], sizeof(handle->buf) - nread);
00303         if (ret <= 0) {
00304             if (errno == EINTR)
00305                 continue;
00306             
00307             handle->err = DTN_ECOMM;
00308             dtnipc_close(handle);
00309             return -1;
00310         }
00311 
00312         nread += ret;
00313     }
00314 
00315     return len;
00316 }
00317 
00318 
00324 int dtnipc_send_recv(dtnipc_handle_t* handle, dtnapi_message_type_t type)
00325 {
00326     int status;
00327 
00328     // send the message
00329     if (dtnipc_send(handle, type) < 0) {
00330         return -1;
00331     }
00332 
00333     // wait for a response
00334     if (dtnipc_recv(handle, &status) < 0) {
00335         return -1;
00336     }
00337 
00338     // handle server-side errors
00339     if (status != DTN_SUCCESS) {
00340         handle->err = status;
00341         return -1;
00342     }
00343 
00344     return 0;
00345 }

Generated on Fri Dec 22 14:47:58 2006 for DTN Reference Implementation by  doxygen 1.5.1