dtn_ipc.c

Go to the documentation of this file.
00001 /*
00002  *    Copyright 2004-2006 Intel Corporation
00003  * 
00004  *    Licensed under the Apache License, Version 2.0 (the "License");
00005  *    you may not use this file except in compliance with the License.
00006  *    You may obtain a copy of the License at
00007  * 
00008  *        http://www.apache.org/licenses/LICENSE-2.0
00009  * 
00010  *    Unless required by applicable law or agreed to in writing, software
00011  *    distributed under the License is distributed on an "AS IS" BASIS,
00012  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *    See the License for the specific language governing permissions and
00014  *    limitations under the License.
00015  */
00016 
00017 #include <stdio.h>
00018 #include <stdlib.h>
00019 #include <errno.h>
00020 #include <string.h>
00021 #include <unistd.h>
00022 #include <sys/types.h>
00023 #include <sys/socket.h>
00024 #include <netinet/in.h>
00025 #include <arpa/inet.h>
00026 #include <oasys/compat/inet_aton.h>
00027 #include <oasys/compat/inttypes.h>
00028 
00029 #include "dtn_ipc.h"
00030 #include "dtn_errno.h"
00031 #include "dtn_types.h"
00032 
00033 /* exposed globally for testing purposes only */
00034 int dtnipc_version = DTN_IPC_VERSION;
00035 
00036 const char*
00037 dtnipc_msgtoa(u_int8_t type)
00038 {
00039 #define CASE(_type) case _type : return #_type; break;
00040     
00041     switch(type) {
00042         CASE(DTN_OPEN);
00043         CASE(DTN_CLOSE);
00044         CASE(DTN_LOCAL_EID);
00045         CASE(DTN_REGISTER);
00046         CASE(DTN_UNREGISTER);
00047         CASE(DTN_FIND_REGISTRATION);
00048         CASE(DTN_CHANGE_REGISTRATION);
00049         CASE(DTN_BIND);
00050         CASE(DTN_SEND);
00051         CASE(DTN_RECV);
00052         CASE(DTN_BEGIN_POLL);
00053         CASE(DTN_CANCEL_POLL);
00054 
00055     default:
00056         return "(unknown type)";
00057     }
00058     
00059 #undef CASE
00060 }
00061 
00062 /*
00063  * Initialize the handle structure.
00064  */
00065 int
00066 dtnipc_open(dtnipc_handle_t* handle)
00067 {
00068     int ret;
00069     char *env, *end;
00070     struct sockaddr_in sa;
00071     in_addr_t ipc_addr;
00072     u_int16_t ipc_port;
00073     u_int32_t handshake;
00074     u_int port;
00075 
00076     // zero out the handle
00077     memset(handle, 0, sizeof(dtnipc_handle_t));
00078     
00079     // note that we leave eight bytes free to be used for the framing
00080     // -- the type code and length for send (which is only five
00081     // bytes), and the return code and length for recv (which is
00082     // actually eight bytes)
00083     xdrmem_create(&handle->xdr_encode, handle->buf + 8,
00084                   DTN_MAX_API_MSG, XDR_ENCODE);
00085     
00086     xdrmem_create(&handle->xdr_decode, handle->buf + 8,
00087                   DTN_MAX_API_MSG, XDR_DECODE);
00088 
00089     // open the socket
00090     handle->sock = socket(PF_INET, SOCK_STREAM, 0);
00091     if (handle->sock < 0)
00092     {
00093         handle->err = DTN_ECOMM;
00094         dtnipc_close(handle);
00095         return -1;
00096     }
00097 
00098     // check for DTNAPI environment variables overriding the address /
00099     // port defaults
00100     ipc_addr = htonl(INADDR_LOOPBACK);
00101     ipc_port = DTN_IPC_PORT;
00102     
00103     if ((env = getenv("DTNAPI_ADDR")) != NULL) {
00104         if (inet_aton(env, (struct in_addr*)&ipc_addr) == 0)
00105         {
00106             fprintf(stderr, "DTNAPI_ADDR environment variable (%s) "
00107                     "not a valid ip address\n", env);
00108             exit(1);
00109         }
00110     }
00111 
00112     if ((env = getenv("DTNAPI_PORT")) != NULL) {
00113         port = strtoul(env, &end, 10);
00114         if (*end != '\0' || port > 0xffff)
00115         {
00116             fprintf(stderr, "DTNAPI_PORT environment variable (%s) "
00117                     "not a valid ip port\n", env);
00118             exit(1);
00119         }
00120         ipc_port = (u_int16_t)port;
00121     }
00122 
00123     // connect to the server
00124     memset(&sa, 0, sizeof(sa));
00125     sa.sin_family = AF_INET;
00126     sa.sin_addr.s_addr = ipc_addr;
00127     sa.sin_port = htons(ipc_port);
00128     
00129     ret = connect(handle->sock, (const struct sockaddr*)&sa, sizeof(sa));
00130     if (ret != 0) {
00131         handle->err = DTN_ECOMM;
00132         dtnipc_close(handle);
00133         return -1;
00134     }
00135 
00136     // send the session initiation to the server on the handshake
00137     // port. it consists of DTN_OPEN in the high 16 bits and IPC
00138     // version in the low 16 bits
00139     handshake = htonl(DTN_OPEN << 16 | dtnipc_version);
00140     ret = write(handle->sock, &handshake, sizeof(handshake));
00141     if (ret != sizeof(handshake)) {
00142         handle->err = DTN_ECOMM;
00143         dtnipc_close(handle);
00144         return -1;
00145     }
00146 
00147     // wait for the handshake response
00148     handshake = 0;
00149     ret = read(handle->sock, &handshake, sizeof(handshake));
00150     if (ret != sizeof(handshake) || (ntohl(handshake) >> 16) != DTN_OPEN) {
00151         handle->err = DTN_ECOMM;
00152         dtnipc_close(handle);
00153         return -1;
00154     }
00155     
00156     if ((ntohl(handshake) & 0x0ffff) != DTN_IPC_VERSION) {
00157         handle->err = DTN_EMSGTYPE;
00158         dtnipc_close(handle);
00159         return -1;
00160     }
00161     
00162     return 0;
00163 }
00164 
00165 /*
00166  * Clean up the handle. dtnipc_open must have already been called on
00167  * the handle.
00168  */
00169 int
00170 dtnipc_close(dtnipc_handle_t* handle)
00171 {
00172     int ret;
00173     
00174     // first send a close over RPC
00175     if (handle->err != DTN_ECOMM) {
00176         ret = dtnipc_send_recv(handle, DTN_CLOSE);
00177     } else {
00178         ret = -1;
00179     }
00180     
00181     xdr_destroy(&handle->xdr_encode);
00182     xdr_destroy(&handle->xdr_decode);
00183 
00184     if (handle->sock > 0) {
00185         close(handle->sock);
00186     }
00187 
00188     handle->sock = 0;
00189 
00190     return ret;
00191 }
00192       
00193 
00194 /*
00195  * Send a message over the dtn ipc protocol.
00196  *
00197  * Returns 0 on success, -1 on error.
00198  */
00199 int
00200 dtnipc_send(dtnipc_handle_t* handle, dtnapi_message_type_t type)
00201 {
00202     int ret;
00203     u_int32_t len, msglen;
00204     
00205     // pack the message code in the fourth byte of the buffer and the
00206     // message length into the next four. we don't use xdr routines
00207     // for these since we need to be able to decode the length on the
00208     // other side to make sure we've read the whole message, and we
00209     // need the type to know which xdr decoder to call
00210     handle->buf[3] = type;
00211 
00212     len = xdr_getpos(&handle->xdr_encode);
00213     msglen = len + 5;
00214     len = htonl(len);
00215     memcpy(&handle->buf[4], &len, sizeof(len));
00216     
00217     // reset the xdr encoder
00218     xdr_setpos(&handle->xdr_encode, 0);
00219     
00220     // send the message, looping until it's all sent
00221     char* bp = &handle->buf[3];
00222     do {
00223         ret = write(handle->sock, bp, msglen);
00224         
00225         if (ret <= 0) {
00226             if (errno == EINTR)
00227                 continue;
00228             
00229             handle->err = DTN_ECOMM;
00230             dtnipc_close(handle);
00231             return -1;
00232         }
00233 
00234         bp     += ret;
00235         msglen -= ret;
00236         
00237     } while (msglen > 0);
00238     
00239     return 0;
00240 }
00241 
00242 /*
00243  * Receive a message on the ipc channel. May block if there is no
00244  * pending message.
00245  *
00246  * Sets status to the server-returned status code and returns the
00247  * length of any reply message on success, returns -1 on internal
00248  * error.
00249  */
00250 int
00251 dtnipc_recv(dtnipc_handle_t* handle, int* status)
00252 {
00253     int ret;
00254     u_int32_t len, nread;
00255     u_int32_t statuscode;
00256 
00257     // reset the xdr decoder before reading in any data
00258     xdr_setpos(&handle->xdr_decode, 0);
00259 
00260     // read as much as possible into the buffer
00261     ret = read(handle->sock, handle->buf, sizeof(handle->buf));
00262 
00263     // make sure we got at least the status code and length
00264     if (ret < 8) {
00265         handle->err = DTN_ECOMM;
00266         dtnipc_close(handle);
00267         return -1;
00268     }
00269     
00270     memcpy(&statuscode, handle->buf, sizeof(statuscode));
00271     statuscode = ntohl(statuscode);
00272     *status = statuscode;
00273     
00274     memcpy(&len, &handle->buf[4], sizeof(len));
00275     len = ntohl(len);
00276 
00277     // read the rest of the message if we didn't get it all
00278     nread = ret;
00279     while (nread < len + 8) {
00280         ret = read(handle->sock,
00281                    &handle->buf[nread], sizeof(handle->buf) - nread);
00282         if (ret <= 0) {
00283             if (errno == EINTR)
00284                 continue;
00285             
00286             handle->err = DTN_ECOMM;
00287             dtnipc_close(handle);
00288             return -1;
00289         }
00290 
00291         nread += ret;
00292     }
00293 
00294     return len;
00295 }
00296 
00297 
00303 int dtnipc_send_recv(dtnipc_handle_t* handle, dtnapi_message_type_t type)
00304 {
00305     int status;
00306 
00307     // send the message
00308     if (dtnipc_send(handle, type) < 0) {
00309         return -1;
00310     }
00311 
00312     // wait for a response
00313     if (dtnipc_recv(handle, &status) < 0) {
00314         return -1;
00315     }
00316 
00317     // handle server-side errors
00318     if (status != DTN_SUCCESS) {
00319         handle->err = status;
00320         return -1;
00321     }
00322 
00323     return 0;
00324 }

Generated on Sat Sep 8 08:43:26 2007 for DTN Reference Implementation by  doxygen 1.5.3