00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifdef HAVE_CONFIG_H
00018 # include <dtn-config.h>
00019 #endif
00020
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <errno.h>
00024 #include <string.h>
00025 #include <unistd.h>
00026 #include <sys/types.h>
00027 #include <sys/socket.h>
00028 #include <netinet/in.h>
00029 #include <arpa/inet.h>
00030 #include <oasys/compat/inet_aton.h>
00031 #include <oasys/compat/inttypes.h>
00032
00033 #include "dtn_ipc.h"
00034 #include "dtn_errno.h"
00035 #include "dtn_types.h"
00036
00037
00038 int dtnipc_version = DTN_IPC_VERSION;
00039
00040 const char*
00041 dtnipc_msgtoa(u_int8_t type)
00042 {
00043 #define CASE(_type) case _type : return #_type; break;
00044
00045 switch(type) {
00046 CASE(DTN_OPEN);
00047 CASE(DTN_CLOSE);
00048 CASE(DTN_LOCAL_EID);
00049 CASE(DTN_REGISTER);
00050 CASE(DTN_UNREGISTER);
00051 CASE(DTN_FIND_REGISTRATION);
00052 CASE(DTN_CHANGE_REGISTRATION);
00053 CASE(DTN_BIND);
00054 CASE(DTN_SEND);
00055 CASE(DTN_RECV);
00056 CASE(DTN_BEGIN_POLL);
00057 CASE(DTN_CANCEL_POLL);
00058 CASE(DTN_CANCEL);
00059 CASE(DTN_SESSION_UPDATE);
00060
00061 default:
00062 return "(unknown type)";
00063 }
00064
00065 #undef CASE
00066 }
00067
00068
00069
00070
00071 int
00072 dtnipc_open(dtnipc_handle_t* handle)
00073 {
00074 int remote_version, ret;
00075 char *env, *end;
00076 struct sockaddr_in sa;
00077 in_addr_t ipc_addr;
00078 u_int16_t ipc_port;
00079 u_int32_t handshake;
00080 u_int port;
00081
00082
00083 memset(handle, 0, sizeof(dtnipc_handle_t));
00084
00085
00086 if (getenv("DTNAPI_DEBUG") != 0) {
00087 handle->debug = 1;
00088 }
00089
00090
00091
00092
00093
00094 xdrmem_create(&handle->xdr_encode, handle->buf + 8,
00095 DTN_MAX_API_MSG - 8, XDR_ENCODE);
00096
00097 xdrmem_create(&handle->xdr_decode, handle->buf + 8,
00098 DTN_MAX_API_MSG - 8, XDR_DECODE);
00099
00100
00101 handle->sock = socket(PF_INET, SOCK_STREAM, 0);
00102 if (handle->sock < 0)
00103 {
00104 handle->err = DTN_ECOMM;
00105 dtnipc_close(handle);
00106 return -1;
00107 }
00108
00109
00110
00111 ipc_addr = htonl(INADDR_LOOPBACK);
00112 ipc_port = DTN_IPC_PORT;
00113
00114 if ((env = getenv("DTNAPI_ADDR")) != NULL) {
00115 if (inet_aton(env, (struct in_addr*)&ipc_addr) == 0)
00116 {
00117 fprintf(stderr, "DTNAPI_ADDR environment variable (%s) "
00118 "not a valid ip address\n", env);
00119 exit(1);
00120 }
00121 }
00122
00123 if ((env = getenv("DTNAPI_PORT")) != NULL) {
00124 port = strtoul(env, &end, 10);
00125 if (*end != '\0' || port > 0xffff)
00126 {
00127 fprintf(stderr, "DTNAPI_PORT environment variable (%s) "
00128 "not a valid ip port\n", env);
00129 exit(1);
00130 }
00131 ipc_port = (u_int16_t)port;
00132 }
00133
00134
00135 memset(&sa, 0, sizeof(sa));
00136 sa.sin_family = AF_INET;
00137 sa.sin_addr.s_addr = ipc_addr;
00138 sa.sin_port = htons(ipc_port);
00139
00140 ret = connect(handle->sock, (const struct sockaddr*)&sa, sizeof(sa));
00141 if (ret != 0) {
00142 if (handle->debug) {
00143 fprintf(stderr, "dtn_ipc: error connecting to server: %s\n",
00144 strerror(errno));
00145 }
00146
00147 handle->err = DTN_ECOMM;
00148 dtnipc_close(handle);
00149 return -1;
00150 }
00151
00152 if (handle->debug) {
00153 fprintf(stderr, "dtn_ipc: connected to server: fd %d\n", handle->sock);
00154 }
00155
00156
00157
00158
00159 handshake = htonl(DTN_OPEN << 16 | dtnipc_version);
00160 ret = write(handle->sock, &handshake, sizeof(handshake));
00161 if (ret != sizeof(handshake)) {
00162 if (handle->debug) {
00163 fprintf(stderr, "dtn_ipc: handshake error\n");
00164 }
00165 handle->err = DTN_ECOMM;
00166 dtnipc_close(handle);
00167 return -1;
00168 }
00169 handle->total_sent += ret;
00170
00171
00172 handshake = 0;
00173 ret = read(handle->sock, &handshake, sizeof(handshake));
00174 if (ret != sizeof(handshake) || (ntohl(handshake) >> 16) != DTN_OPEN) {
00175 if (handle->debug) {
00176 fprintf(stderr, "dtn_ipc: handshake error\n");
00177 }
00178 dtnipc_close(handle);
00179 handle->err = DTN_ECOMM;
00180 return -1;
00181 }
00182
00183 handle->total_rcvd += ret;
00184
00185 remote_version = (ntohl(handshake) & 0x0ffff);
00186 if (remote_version != dtnipc_version) {
00187 if (handle->debug) {
00188 fprintf(stderr, "dtn_ipc: version mismatch\n");
00189 }
00190 dtnipc_close(handle);
00191 handle->err = DTN_EVERSION;
00192 return -1;
00193 }
00194
00195 return 0;
00196 }
00197
00198
00199
00200
00201
00202 int
00203 dtnipc_close(dtnipc_handle_t* handle)
00204 {
00205 int ret;
00206
00207
00208 if (handle->err != DTN_ECOMM) {
00209 ret = dtnipc_send_recv(handle, DTN_CLOSE);
00210 } else {
00211 ret = -1;
00212 }
00213
00214 xdr_destroy(&handle->xdr_encode);
00215 xdr_destroy(&handle->xdr_decode);
00216
00217 if (handle->sock > 0) {
00218 close(handle->sock);
00219 }
00220
00221 handle->sock = 0;
00222
00223 return ret;
00224 }
00225
00226
00227
00228
00229
00230
00231
00232 int
00233 dtnipc_send(dtnipc_handle_t* handle, dtnapi_message_type_t type)
00234 {
00235 int ret;
00236 u_int32_t len, msglen, origlen;
00237
00238
00239
00240
00241
00242
00243 handle->buf[3] = type;
00244
00245 len = xdr_getpos(&handle->xdr_encode);
00246 msglen = len + 5;
00247 len = htonl(len);
00248 memcpy(&handle->buf[4], &len, sizeof(len));
00249
00250
00251 xdr_setpos(&handle->xdr_encode, 0);
00252
00253
00254 origlen = msglen;
00255 char* bp = &handle->buf[3];
00256 do {
00257 ret = write(handle->sock, bp, msglen);
00258 handle->total_sent += ret;
00259
00260 if (handle->debug) {
00261 fprintf(stderr, "dtn_ipc: send(%s) wrote %d/%d bytes (%s) "
00262 "(total sent/rcvd %u/%u)\n",
00263 dtnipc_msgtoa(type), ret, origlen,
00264 ret == -1 ? strerror(errno) : "success",
00265 handle->total_sent, handle->total_rcvd);
00266 }
00267
00268 if (ret <= 0) {
00269 if (errno == EINTR)
00270 continue;
00271
00272 handle->err = DTN_ECOMM;
00273 dtnipc_close(handle);
00274 return -1;
00275 }
00276
00277 bp += ret;
00278 msglen -= ret;
00279
00280 } while (msglen > 0);
00281
00282 return 0;
00283 }
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293 int
00294 dtnipc_recv(dtnipc_handle_t* handle, int* status)
00295 {
00296 int ret;
00297 u_int32_t len, nread;
00298 u_int32_t statuscode;
00299
00300
00301 xdr_setpos(&handle->xdr_decode, 0);
00302
00303
00304 ret = read(handle->sock, handle->buf, 8);
00305 handle->total_rcvd += ret;
00306
00307
00308 if (ret != 8) {
00309 handle->err = DTN_ECOMM;
00310 dtnipc_close(handle);
00311 return -1;
00312 }
00313
00314 memcpy(&statuscode, handle->buf, sizeof(statuscode));
00315 statuscode = ntohl(statuscode);
00316 *status = statuscode;
00317
00318 memcpy(&len, &handle->buf[4], sizeof(len));
00319 len = ntohl(len);
00320
00321 if (handle->debug) {
00322 fprintf(stderr, "dtn_ipc: recv() read %d/8 bytes for status (%s): "
00323 "status %d len %d (total sent/rcvd %u/%u)\n",
00324 ret, ret == -1 ? strerror(errno) : "success",
00325 *status, len, handle->total_sent, handle->total_rcvd);
00326 }
00327
00328
00329 nread = 8;
00330 while (nread < len + 8) {
00331 ret = read(handle->sock,
00332 &handle->buf[nread], sizeof(handle->buf) - nread);
00333 handle->total_rcvd += ret;
00334
00335 if (handle->debug) {
00336 fprintf(stderr, "dtn_ipc: recv() read %d/%d bytes (%s)\n",
00337 ret, len, ret == -1 ? strerror(errno) : "success");
00338 }
00339
00340 if (ret <= 0) {
00341 if (errno == EINTR)
00342 continue;
00343
00344 handle->err = DTN_ECOMM;
00345 dtnipc_close(handle);
00346 return -1;
00347 }
00348
00349 nread += ret;
00350 }
00351
00352 return len;
00353 }
00354
00355
00361 int dtnipc_send_recv(dtnipc_handle_t* handle, dtnapi_message_type_t type)
00362 {
00363 int status;
00364
00365
00366 if (dtnipc_send(handle, type) < 0) {
00367 return -1;
00368 }
00369
00370
00371 if (dtnipc_recv(handle, &status) < 0) {
00372 return -1;
00373 }
00374
00375
00376 if (status != DTN_SUCCESS) {
00377 handle->err = status;
00378 return -1;
00379 }
00380
00381 return 0;
00382 }