00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <stdio.h>
00023 #include <unistd.h>
00024 #include <stdlib.h>
00025 #include <stdarg.h>
00026 #include <errno.h>
00027 #include <poll.h>
00028 #include <string.h>
00029 #include <signal.h>
00030 #include <sys/types.h>
00031 #include <sys/time.h>
00032 #include <sys/socket.h>
00033 #include <netinet/in.h>
00034 #include <arpa/inet.h>
00035 #include <net/if.h>
00036 #include <netdb.h>
00037
00038 #if defined(NEED_GETADDRINFO_COMPAT)
00039 #include "getaddrinfo.h"
00040 #include "dummyin6.h"
00041 #endif
00042 #ifndef AI_ADDRCONFIG
00043 #define AI_ADDRCONFIG 0
00044 #endif
00045
00046 #include <ccn/ccn.h>
00047 #include <ccn/ccnd.h>
00048
00049 void udplink_fatal(int line, char *format, ...);
00050
00051 #define UDPMAXBUF 8800
00052
00053 #ifdef __CYGWIN__
00054
00055 unsigned if_nametoindex(const char *ifname) {
00056 udplink_fatal(__LINE__, "interface name unsupported on cygwin");
00057 return 0;
00058 }
00059 #endif
00060
00061 static struct options {
00062 const char *localsockname;
00063 const char *remotehostname;
00064 struct addrinfo *localif_for_mcast_addrinfo;
00065 char remoteport[8];
00066 char localport[8];
00067 unsigned int remoteifindex;
00068 int multicastttl;
00069 int logging;
00070 } options = {NULL, NULL, NULL, "", "", 0, 0, 0};
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080 void
00081 usage(char *name) {
00082 fprintf(stderr, "Usage: %s [-d(ebug)] [-c ccnsocket] -h remotehost -r remoteport [-l localport] [-m multicastlocaladdress] [-t multicastttl]\n", name);
00083 }
00084
00085 void
00086 udplink_fatal(int line, char *format, ...)
00087 {
00088 struct timeval t;
00089 va_list ap;
00090 va_start(ap, format);
00091 gettimeofday(&t, NULL);
00092 fprintf(stderr, "%d.%06d udplink[%d] line %d: ", (int)t.tv_sec, (unsigned)t.tv_usec, getpid(), line);
00093 vfprintf(stderr, format, ap);
00094 va_end(ap);
00095 exit(1);
00096 }
00097
00098 void
00099 udplink_note(char *format, ...)
00100 {
00101 struct timeval t;
00102 va_list ap;
00103 va_start(ap, format);
00104 gettimeofday(&t, NULL);
00105 fprintf(stderr, "%d.%06d udplink[%d]: ", (int)t.tv_sec, (unsigned)t.tv_usec, getpid());
00106 vfprintf(stderr, format, ap);
00107 va_end(ap);
00108 }
00109
00110 void
00111 udplink_print_data(char *source, unsigned char *data, int start, int length, int logging)
00112 {
00113 int i;
00114
00115 udplink_note("%d bytes from %s", length, source);
00116 if (logging > 2) {
00117 fprintf(stderr, ":");
00118 for (i = 0; i < length; i++) {
00119 if ((i % 20) == 0) fprintf(stderr, "\n%4d: ", i);
00120 if (((i + 10) % 20) == 0) fprintf(stderr, "| ");
00121 fprintf(stderr, "%02x ", data[i + start]);
00122 }
00123 }
00124 fprintf(stderr, "\n");
00125 }
00126
00127 ssize_t
00128 send_remote_unencapsulated(int s, struct addrinfo *r, unsigned char *buf, size_t start, size_t length) {
00129 ssize_t result;
00130
00131 if (memcmp(&buf[start], CCN_EMPTY_PDU, CCN_EMPTY_PDU_LENGTH - 1) != 0) {
00132 return (-2);
00133 }
00134 result = sendto(s, buf + CCN_EMPTY_PDU_LENGTH - 1 + start, length - CCN_EMPTY_PDU_LENGTH,
00135 0, r->ai_addr, r->ai_addrlen);
00136 return (result);
00137 }
00138
00139 void process_options(int argc, char * const argv[], struct options *opt) {
00140 int c;
00141 char *cp = NULL;
00142 char *rportstr = NULL;
00143 char *lportstr = NULL;
00144 char *mcastoutstr = NULL;
00145 char *ttlstr = NULL;
00146 struct addrinfo hints = {0};
00147 int result;
00148 int n;
00149
00150 while ((c = getopt(argc, argv, "dc:h:r:l:m:t:")) != -1) {
00151 switch (c) {
00152 case 'd':
00153 opt->logging++;
00154 break;
00155 case 'c':
00156 opt->localsockname = optarg;
00157 break;
00158 case 'h':
00159 opt->remotehostname = optarg;
00160 break;
00161 case 'r':
00162 rportstr = optarg;
00163 break;
00164 case 'l':
00165 lportstr = optarg;
00166 break;
00167 case 'm':
00168 mcastoutstr = optarg;
00169 break;
00170 case 't':
00171 ttlstr = optarg;
00172 break;
00173 }
00174 }
00175
00176
00177 if (opt->remotehostname == NULL || rportstr == NULL) {
00178 usage(argv[0]);
00179 exit(1);
00180 }
00181
00182 if (strspn(rportstr, "0123456789") != strlen(rportstr)) {
00183 usage(argv[0]);
00184 exit(1);
00185 }
00186
00187 n = atoi(rportstr);
00188 if (n <= 0 || n >= 65536) {
00189 usage(argv[0]);
00190 exit(1);
00191 }
00192 sprintf(opt->remoteport, "%d", n);
00193
00194 if (lportstr != NULL) {
00195 if (strspn(lportstr, "0123456789") != strlen(lportstr)) {
00196 usage(argv[0]);
00197 exit(1);
00198 }
00199 n = atoi(lportstr);
00200 if (n <= 0 || n >= 65536) {
00201 usage(argv[0]);
00202 exit(1);
00203 }
00204 }
00205 sprintf(opt->localport, "%d", n);
00206
00207 if (mcastoutstr != NULL) {
00208 hints.ai_family = PF_INET;
00209 hints.ai_socktype = SOCK_DGRAM;
00210 hints.ai_flags = AI_NUMERICHOST;
00211 #ifdef AI_NUMERICSERV
00212 hints.ai_flags |= AI_NUMERICSERV;
00213 #endif
00214 udplink_note("interface %s requested (port %s)\n", mcastoutstr, opt->localport);
00215 result = getaddrinfo(mcastoutstr, opt->localport, &hints, &opt->localif_for_mcast_addrinfo);
00216 if (result != 0 || opt->localif_for_mcast_addrinfo == NULL) {
00217 udplink_fatal(__LINE__, "getaddrinfo(\"%s\", ...): %s\n", mcastoutstr, gai_strerror(result));
00218 }
00219 }
00220
00221 if (ttlstr != NULL) {
00222 if (strspn(ttlstr, "0123456789") != strlen(ttlstr)) {
00223 usage(argv[0]);
00224 exit(1);
00225 }
00226 opt->multicastttl = atoi(ttlstr);
00227 if (opt->multicastttl < 1 || opt->multicastttl > 255) {
00228 usage(argv[0]);
00229 exit(1);
00230 }
00231 }
00232
00233 cp = strchr(opt->remotehostname, '%');
00234 if (cp != NULL) {
00235 cp++;
00236 errno = 0;
00237 opt->remoteifindex = atoi(cp);
00238 if (opt->remoteifindex == 0) {
00239 opt->remoteifindex = if_nametoindex(cp);
00240 if (opt->remoteifindex == 0 && errno != 0) {
00241 udplink_fatal(__LINE__, "Invalid interface name %s\n", cp);
00242 }
00243 }
00244 }
00245 }
00246
00247 void
00248 set_multicast_sockopt(int socket_r, int socket_w, struct addrinfo *ai, struct options *opt)
00249 {
00250 struct addrinfo hints;
00251 struct ip_mreq mreq;
00252 #ifdef IPV6_JOIN_GROUP
00253 struct ipv6_mreq mreq6;
00254 #endif
00255 unsigned char csockopt;
00256 unsigned int isockopt;
00257 int result;
00258
00259 memset((void *)&hints, 0, sizeof(hints));
00260 memset((void *)&mreq, 0, sizeof(mreq));
00261 #ifdef IPV6_JOIN_GROUP
00262 memset((void *)&mreq6, 0, sizeof(mreq6));
00263 #endif
00264
00265 if (ai->ai_family == PF_INET && IN_MULTICAST(ntohl(((struct sockaddr_in *)(ai->ai_addr))->sin_addr.s_addr))) {
00266 if (opt->logging > 0) udplink_note("IPv4 multicast\n");
00267 #ifdef IP_ADD_MEMBERSHIP
00268 memcpy((void *)&mreq.imr_multiaddr, &((struct sockaddr_in *)ai->ai_addr)->sin_addr, sizeof(mreq.imr_multiaddr));
00269 if (opt->localif_for_mcast_addrinfo != NULL) {
00270 memcpy((void *)&mreq.imr_interface.s_addr, &((struct sockaddr_in *)opt->localif_for_mcast_addrinfo->ai_addr)->sin_addr, sizeof(mreq.imr_interface.s_addr));
00271 }
00272 result = setsockopt(socket_r, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
00273 if (result == -1) udplink_fatal(__LINE__, "setsockopt(..., IP_ADD_MEMBERSHIP, ...): %s\n", strerror(errno));
00274 #endif
00275 #ifdef IP_MULTICAST_LOOP
00276 csockopt = 0;
00277 result = setsockopt(socket_w, IPPROTO_IP, IP_MULTICAST_LOOP, &csockopt, sizeof(csockopt));
00278 if (result == -1) udplink_fatal(__LINE__, "setsockopt(..., IP_MULTICAST_LOOP, ...): %s\n", strerror(errno));
00279 #endif
00280 #ifdef IP_MULTICAST_TTL
00281 if (opt->multicastttl > 0) {
00282 csockopt = opt->multicastttl;
00283 result = setsockopt(socket_w, IPPROTO_IP, IP_MULTICAST_TTL, &csockopt, sizeof(csockopt));
00284 if (result == -1) {
00285 udplink_fatal(__LINE__, "setsockopt(..., IP_MULTICAST_TTL, ...): %s\n", strerror(errno));
00286 }
00287 }
00288 #endif
00289 } else if (ai->ai_family == PF_INET6 && IN6_IS_ADDR_MULTICAST((&((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr))) {
00290 if (opt->logging > 0) udplink_note("IPv6 multicast\n");
00291 #ifdef IPV6_JOIN_GROUP
00292 memcpy((void *)&mreq6.ipv6mr_multiaddr, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr, sizeof(mreq6.ipv6mr_multiaddr));
00293 if (opt->remoteifindex > 0) {
00294 mreq6.ipv6mr_interface = opt->remoteifindex;
00295 }
00296 result = setsockopt(socket_r, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6));
00297 if (result == -1) {
00298 udplink_fatal(__LINE__, "setsockopt(..., IPV6_JOIN_GROUP, ...): %s\n", strerror(errno));
00299 }
00300 #endif
00301 #ifdef IPV6_MULTICAST_LOOP
00302 isockopt = 0;
00303 result = setsockopt(socket_w, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &isockopt, sizeof(isockopt));
00304 if (result == -1) {
00305 udplink_fatal(__LINE__, "setsockopt(..., IPV6_MULTICAST_LOOP, ...): %s\n", strerror(errno));
00306 }
00307 #endif
00308 #ifdef IPV6_MULTICAST_HOPS
00309 if (opt->multicastttl > 0) {
00310 isockopt = opt->multicastttl;
00311 result = setsockopt(socket_w, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &isockopt, sizeof(isockopt));
00312 if (result == -1) {
00313 udplink_fatal(__LINE__, "setsockopt(..., IPV6_MULTICAST_LOOP, ...): %s\n", strerror(errno));
00314 }
00315 }
00316 #endif
00317 }
00318 }
00319
00320 void
00321 changeloglevel(int s) {
00322 switch (s) {
00323 case SIGUSR1:
00324 options.logging = 0;
00325 udplink_note("logging disabled\n");
00326 break;
00327 case SIGUSR2:
00328 if (options.logging < 10) options.logging++;
00329 udplink_note("log level %d\n", options.logging);
00330 break;
00331 }
00332 return;
00333 }
00334
00335 int
00336 main (int argc, char * const argv[]) {
00337 int result;
00338 int localsock_rw = 0;
00339 int remotesock_w = 0;
00340 int remotesock_r = 0;
00341 char canonical_remote[NI_MAXHOST] = "";
00342 struct addrinfo *raddrinfo = NULL;
00343 struct addrinfo *laddrinfo = NULL;
00344 struct addrinfo hints = {0};
00345 struct pollfd fds[2];
00346 struct ccn *ccn;
00347 struct ccn_skeleton_decoder ldecoder = {0};
00348 struct ccn_skeleton_decoder *ld = &ldecoder;
00349 struct ccn_skeleton_decoder rdecoder = {0};
00350 struct ccn_skeleton_decoder *rd = &rdecoder;
00351 unsigned char rbuf[UDPMAXBUF];
00352 struct ccn_charbuf *charbuf;
00353 ssize_t msgstart = 0;
00354 ssize_t dres;
00355 struct sigaction sigact_changeloglevel;
00356 unsigned char *deferredbuf = NULL;
00357 size_t deferredlen = 0;
00358 int dropped_count = 0;
00359 size_t dropped_bytes = 0;
00360 const int one = 1;
00361
00362 process_options(argc, argv, &options);
00363
00364
00365 memset(&sigact_changeloglevel, 0, sizeof(sigact_changeloglevel));
00366 sigact_changeloglevel.sa_handler = changeloglevel;
00367 sigaction(SIGUSR1, &sigact_changeloglevel, NULL);
00368 sigaction(SIGUSR2, &sigact_changeloglevel, NULL);
00369
00370
00371 ccn = ccn_create();
00372 localsock_rw = ccn_connect(ccn, options.localsockname);
00373 if (localsock_rw == -1) {
00374 udplink_fatal(__LINE__, "ccn_connect: %s\n", strerror(errno));
00375 }
00376
00377 hints.ai_family = AF_UNSPEC;
00378 hints.ai_socktype = SOCK_DGRAM;
00379 hints.ai_flags = AI_ADDRCONFIG;
00380 #ifdef AI_NUMERICSERV
00381 hints.ai_flags |= AI_NUMERICSERV;
00382 #endif
00383
00384
00385 result = getaddrinfo(options.remotehostname, options.remoteport, &hints, &raddrinfo);
00386 if (result != 0 || raddrinfo == NULL) {
00387 udplink_fatal(__LINE__, "getaddrinfo(\"%s\", \"%s\", ...): %s\n", options.remotehostname, options.remoteport, gai_strerror(result));
00388 }
00389
00390 getnameinfo(raddrinfo->ai_addr, raddrinfo->ai_addrlen, canonical_remote, sizeof(canonical_remote), NULL, 0, 0);
00391
00392
00393 hints.ai_family = raddrinfo->ai_family;
00394 hints.ai_flags = AI_PASSIVE;
00395 #ifdef AI_NUMERICSERV
00396 hints.ai_flags |= AI_NUMERICSERV;
00397 #endif
00398
00399 result = getaddrinfo(NULL, options.localport, &hints, &laddrinfo);
00400 if (result != 0 || laddrinfo == NULL) {
00401 udplink_fatal(__LINE__, "getaddrinfo(NULL, %s, ...): %s\n", options.localport, gai_strerror(result));
00402 }
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418 remotesock_w = socket(raddrinfo->ai_family, raddrinfo->ai_socktype, 0);
00419 if (remotesock_w == -1) {
00420 udplink_fatal(__LINE__, "socket: %s\n", strerror(errno));
00421 }
00422 remotesock_r = remotesock_w;
00423
00424 if (options.localif_for_mcast_addrinfo != NULL) {
00425
00426
00427
00428 remotesock_r = socket(raddrinfo->ai_family, raddrinfo->ai_socktype, 0);
00429 if (remotesock_r == -1) {
00430 udplink_fatal(__LINE__, "socket: %s\n", strerror(errno));
00431 }
00432 result = setsockopt(remotesock_r, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
00433 if (result == -1) udplink_fatal(__LINE__, "setsockopt(remotesock_r, ..., SO_REUSEADDR, ...)");
00434
00435
00436 result = bind(remotesock_r, raddrinfo->ai_addr, raddrinfo->ai_addrlen);
00437 if (result == -1) {
00438 udplink_fatal(__LINE__, "bind(remotesock_r, local...): %s\n", strerror(errno));
00439 }
00440 }
00441
00442 set_multicast_sockopt(remotesock_r, remotesock_w, raddrinfo, &options);
00443
00444 if (options.localif_for_mcast_addrinfo != NULL) {
00445 result = bind(remotesock_w, options.localif_for_mcast_addrinfo->ai_addr, options.localif_for_mcast_addrinfo->ai_addrlen);
00446 } else {
00447 result = bind(remotesock_w, laddrinfo->ai_addr, laddrinfo->ai_addrlen);
00448 }
00449 if (result == -1) {
00450 udplink_fatal(__LINE__, "bind(remotesock_w, local...): %s\n", strerror(errno));
00451 }
00452
00453 udplink_note("connected to %s:%s\n", canonical_remote, options.remoteport);
00454
00455
00456
00457 result = send(localsock_rw, CCN_EMPTY_PDU, CCN_EMPTY_PDU_LENGTH, 0);
00458 if (result == -1) {
00459 udplink_fatal(__LINE__, "initial send: %s\n", strerror(errno));
00460 }
00461
00462 charbuf = ccn_charbuf_create();
00463
00464 fds[0].fd = localsock_rw;
00465 fds[0].events = POLLIN;
00466 fds[1].fd = remotesock_r;
00467 fds[1].events = POLLIN;
00468
00469 for (;;) {
00470 if (0 == (result = poll(fds, 2, -1))) continue;
00471 if (-1 == result) {
00472 if (errno == EINTR) continue;
00473 udplink_fatal(__LINE__, "poll: %s\n", strerror(errno));
00474 }
00475
00476 if (fds[0].revents & (POLLOUT)) {
00477 fds[1].events |= POLLIN;
00478 fds[0].events &= ~POLLOUT;
00479 if (deferredlen > 0) {
00480 result = send(localsock_rw, deferredbuf, deferredlen, 0);
00481 if (result == -1 && (options.logging > 1 || errno != EAGAIN))
00482 udplink_note("sendto(local, deferredbuf, %ld):"
00483 " %s (sending deferred)\n",
00484 (long) deferredlen, strerror(errno));
00485 if (result == deferredlen) {
00486
00487 if (dropped_count != 0 && options.logging > 0) {
00488 udplink_note("dropped %d from remote (%ld bytes)\n",
00489 dropped_count, (long)dropped_bytes);
00490 dropped_count = 0;
00491 dropped_bytes = 0;
00492 }
00493 deferredlen = 0;
00494 }
00495 else if (result > 0) {
00496 memmove(deferredbuf,
00497 deferredbuf + result,
00498 deferredlen - result);
00499 deferredlen -= result;
00500 fds[0].events |= POLLOUT;
00501 }
00502 else
00503 deferredlen = 0;
00504 }
00505 }
00506
00507
00508 if (fds[0].revents & (POLLIN)) {
00509 unsigned char *lbuf = ccn_charbuf_reserve(charbuf, 32);
00510 ssize_t recvlen;
00511 int tries;
00512 if (charbuf->length == 0) {
00513 memset(ld, 0, sizeof(*ld));
00514 }
00515 recvlen = recv(localsock_rw, lbuf , charbuf->limit - charbuf->length, 0);
00516 if (recvlen == -1) {
00517 if (errno == EAGAIN) continue;
00518 udplink_fatal(__LINE__, "recv(localsock_rw, ...): %s\n", strerror(errno));
00519 }
00520 if (recvlen == 0) {
00521 break;
00522 }
00523 charbuf->length += recvlen;
00524 dres = ccn_skeleton_decode(ld, lbuf, recvlen);
00525 tries = 0;
00526 while (ld->state == 0 && ld->nest == 0) {
00527 if (options.logging > 1)
00528 udplink_print_data("local", charbuf->buf, msgstart, ld->index - msgstart, options.logging);
00529 result = send_remote_unencapsulated(remotesock_w, raddrinfo, charbuf->buf, msgstart, ld->index - msgstart);
00530 if (result == -1) {
00531 if (errno == EAGAIN) continue;
00532 if (errno == EPERM && (tries++ < 3)) {
00533
00534 if (options.logging > 0)
00535 udplink_note("sendto(remotesock_w, rbuf, %ld): %s (will retry)\n", (long) ld->index - msgstart, strerror(errno));
00536 continue;
00537 }
00538 if (errno == ENOBUFS) {
00539
00540 if (options.logging > 0)
00541 udplink_note("sendto(remotesock_w, rbuf, %ld): %s (message dropped)\n", (long) ld->index - msgstart, strerror(errno));
00542 }
00543 else
00544 udplink_fatal(__LINE__, "sendto(remotesock_w, rbuf, %ld): %s\n", (long)ld->index - msgstart, strerror(errno));
00545 }
00546 else if (result == -2) {
00547 udplink_note("protocol error, missing CCNx PDU encapsulation. Message dropped\n");
00548 }
00549
00550 msgstart = ld->index;
00551 if (msgstart == charbuf->length) {
00552 charbuf->length = 0;
00553 msgstart = 0;
00554 break;
00555 }
00556 recvlen = charbuf->length - msgstart;
00557 dres = ccn_skeleton_decode(ld, charbuf->buf + msgstart, recvlen);
00558 }
00559 if (ld->state < 0) {
00560 udplink_fatal(__LINE__, "local data protocol error\n");
00561 }
00562
00563 if (msgstart < charbuf->length && msgstart > 0) {
00564 memmove(charbuf->buf, charbuf->buf + msgstart, charbuf->length - msgstart);
00565 charbuf->length -= msgstart;
00566 ld->index -= msgstart;
00567 msgstart = 0;
00568 }
00569 }
00570
00571
00572 if (fds[1].revents & (POLLIN)) {
00573 struct sockaddr from = {0};
00574 socklen_t fromlen = sizeof(from);
00575 ssize_t recvlen;
00576 unsigned char *recvbuf;
00577 char addrbuf[128];
00578
00579 memmove(rbuf, CCN_EMPTY_PDU, CCN_EMPTY_PDU_LENGTH - 1);
00580 recvbuf = &rbuf[CCN_EMPTY_PDU_LENGTH - 1];
00581 recvlen = recvfrom(remotesock_r, recvbuf, sizeof(rbuf) - CCN_EMPTY_PDU_LENGTH,
00582 0, &from, &fromlen);
00583 if (options.logging > 1) {
00584 if (from.sa_family == AF_INET) {
00585 inet_ntop(AF_INET, &((struct sockaddr_in *)&from)->sin_addr, addrbuf, sizeof(addrbuf));
00586 } else {
00587 inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&from)->sin6_addr, addrbuf, sizeof(addrbuf));
00588 }
00589 udplink_print_data(addrbuf, recvbuf, 0, recvlen, options.logging);
00590 }
00591 if (recvlen == sizeof(rbuf) - CCN_EMPTY_PDU_LENGTH) {
00592 udplink_note("remote packet too large, discarded\n");
00593 continue;
00594 }
00595 if (deferredlen != 0) {
00596 dropped_count++;
00597 dropped_bytes += recvlen;
00598 continue;
00599 }
00600
00601 recvbuf[recvlen] = CCN_EMPTY_PDU[CCN_EMPTY_PDU_LENGTH - 1];
00602 memset(rd, 0, sizeof(*rd));
00603 dres = ccn_skeleton_decode(rd, rbuf, recvlen + CCN_EMPTY_PDU_LENGTH);
00604 if (rd->state != 0 || dres != (recvlen + CCN_EMPTY_PDU_LENGTH)) {
00605 if (recvlen == 1)
00606 udplink_note("remote data protocol error (1 byte recv): likely heartbeat from app sending to wrong port\n");
00607 else
00608 udplink_note("remote data protocol error\n");
00609 continue;
00610 }
00611
00612 result = send(localsock_rw, rbuf, recvlen + CCN_EMPTY_PDU_LENGTH, 0);
00613 if (result == -1) {
00614 if (errno == EAGAIN) {
00615
00616
00617
00618
00619 fds[1].events &= ~POLLIN;
00620 fds[0].events |= POLLOUT;
00621 deferredbuf = realloc(deferredbuf, recvlen + CCN_EMPTY_PDU_LENGTH);
00622 deferredlen = recvlen + CCN_EMPTY_PDU_LENGTH;
00623 memcpy(deferredbuf, rbuf, deferredlen);
00624 if (options.logging > 1)
00625 udplink_note("sendto(localsock_rw, rbuf, %ld): %s (deferred)\n", (long) deferredlen, strerror(errno));
00626 continue;
00627 } else {
00628 udplink_fatal(__LINE__, "sendto(localsock_rw, rbuf, %ld): %s\n", (long) recvlen + CCN_EMPTY_PDU_LENGTH, strerror(errno));
00629 }
00630 }
00631 if (result != recvlen + CCN_EMPTY_PDU_LENGTH) {
00632
00633 fds[0].events |= POLLOUT;
00634 deferredlen = recvlen + CCN_EMPTY_PDU_LENGTH - result;
00635 deferredbuf = realloc(deferredbuf, deferredlen);
00636 memcpy(deferredbuf, rbuf + result, deferredlen);
00637 if (options.logging > 0)
00638 udplink_note("sendto(localsock_rw, rbuf, %ld): %s (deferred partial)\n", (long) deferredlen, strerror(errno));
00639 continue;
00640 }
00641 }
00642 }
00643
00644 udplink_note("disconnected\n");
00645 ccn_destroy(&ccn);
00646 freeaddrinfo(raddrinfo);
00647 freeaddrinfo(laddrinfo);
00648 if (deferredbuf != NULL) {
00649 free(deferredbuf);
00650 deferredbuf = NULL;
00651 }
00652 exit(0);
00653 }