/* Remember that pcap descriptor is in nonblocking state. */ int do_actual_pcap_read(msevent *nse) { mspcap *mp = (mspcap *)nse->iod->pcap; nsock_pcap npp; nsock_pcap *n; struct pcap_pkthdr *pkt_header; const unsigned char *pkt_data = NULL; int rc; memset(&npp, 0, sizeof(nsock_pcap)); if (nse->iod->nsp->tracelevel > 2) nsock_trace(nse->iod->nsp, "PCAP do_actual_pcap_read TEST (IOD #%li) (EID #%li)", nse->iod->id, nse->id); assert( FILESPACE_LENGTH(&(nse->iobuf)) == 0 ); rc = pcap_next_ex(mp->pt, &pkt_header, &pkt_data); switch(rc) { case 1: /* read good packet */ #ifdef PCAP_RECV_TIMEVAL_VALID npp.ts = pkt_header->ts; #else /* on these platforms time received from pcap is invalid. It's better to set current time */ memcpy(&npp.ts, nsock_gettimeofday(), sizeof(struct timeval)); #endif npp.len = pkt_header->len; npp.caplen = pkt_header->caplen; npp.packet = pkt_data; fscat(&(nse->iobuf), (char *)&npp, sizeof(npp)); fscat(&(nse->iobuf), (char *)pkt_data, npp.caplen); n = (nsock_pcap *)FILESPACE_STR(&(nse->iobuf)); n->packet = (unsigned char *)FILESPACE_STR(&(nse->iobuf)) + sizeof(npp); if (nse->iod->nsp->tracelevel > 2) nsock_trace(nse->iod->nsp, "PCAP do_actual_pcap_read READ (IOD #%li) (EID #%li) size=%i", nse->iod->id, nse->id, pkt_header->caplen); return(1); case 0: /* timeout */ return(0); case -1: /* error */ fatal("pcap_next_ex() fatal error while reading from pcap: %s\n", pcap_geterr(mp->pt)); break; case -2: /* no more packets in savefile (if reading from one) */ default: assert(0); } return 0; }
nsock_event_id nsock_sendto(nsock_pool ms_pool, nsock_iod ms_iod, nsock_ev_handler handler, int timeout_msecs, void *userdata, struct sockaddr *saddr, size_t sslen, unsigned short port, const char *data, int datalen) { mspool *nsp = (mspool *) ms_pool; msiod *nsi = (msiod *) ms_iod; msevent *nse; char displaystr[256]; struct sockaddr_in *sin = (struct sockaddr_in *) saddr; #if HAVE_IPV6 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) saddr; #endif nse = msevent_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler, userdata); assert(nse); if (sin->sin_family == AF_INET) { sin->sin_port = htons(port); } else { assert(sin->sin_family == AF_INET6); #if HAVE_IPV6 sin6->sin6_port = htons(port); #else fatal("IPv6 address passed to nsock_connect_* call, but nsock was not compiled w/IPv6 support"); #endif } assert(sslen <= sizeof(nse->writeinfo.dest)); memcpy(&nse->writeinfo.dest, saddr, sslen); nse->writeinfo.destlen = sslen; assert(sslen <= sizeof(nse->iod->peer)); memcpy(&nse->iod->peer, saddr, sslen); nse->iod->peerlen = sslen; if (datalen < 0) datalen = (int) strlen(data); if (nsp->tracelevel > 0) { if (nsp->tracelevel > 1 && datalen < 80) { memcpy(displaystr, ": ", 2); memcpy(displaystr + 2, data, datalen); displaystr[2 + datalen] = '\0'; replacenonprintable(displaystr + 2, datalen, '.'); } else { displaystr[0] = '\0'; } nsock_trace(nsp, "Sendto request for %d bytes to IOD #%li EID %li [%s:%hu]%s", datalen, nsi->id, nse->id, inet_ntop_ez(&nse->writeinfo.dest, nse->writeinfo.destlen), port, displaystr); } fscat(&nse->iobuf, data, datalen); nsp_add_event(nsp, nse); return nse->id; }
void test_fscat() { char c[PATH_MAX + 1]; char *d, *f, *res = "directory/file"; d = "directory"; f = "file"; fscat(d, f, c); if (strcmp(res, c) != 0) { fprintf(stderr, "%s + %s = %s\n", d, f, c); fprintf(stderr, "Invalid fscatination\n"); abort(); } d = "directory/"; f = "file"; fscat(d, f, c); if (strcmp(res, c) != 0) { fprintf(stderr, "%s + %s = %s\n", d, f, c); fprintf(stderr, "Invalid fscatination\n"); abort(); } d = "directory"; f = "/file"; fscat(d, f, c); if (strcmp(res, c) != 0) { fprintf(stderr, "%s + %s = %s\n", d, f, c); fprintf(stderr, "Invalid fscatination\n"); abort(); } d = "directory///"; f = "file"; fscat(d, f, c); if (strcmp(res, c) != 0) { fprintf(stderr, "%s + %s = %s\n", d, f, c); fprintf(stderr, "Invalid fscatination\n"); abort(); } d = "directory"; f = "///file"; fscat(d, f, c); if (strcmp(res, c) != 0) { fprintf(stderr, "%s + %s = %s\n", d, f, c); fprintf(stderr, "Invalid fscatination\n"); abort(); } d = "directory///"; f = "///file"; fscat(d, f, c); if (strcmp(res, c) != 0) { fprintf(stderr, "%s + %s = %s\n", d, f, c); fprintf(stderr, "Invalid fscatination\n"); abort(); } }
/* Write some data to the socket. If the write is not COMPLETED within timeout_msecs , NSE_STATUS_TIMEOUT will be returned. If you are supplying NUL-terminated data, you can optionally pass -1 for datalen and nsock_write will figure out the length itself */ nsock_event_id nsock_write(nsock_pool ms_pool, nsock_iod ms_iod, nsock_ev_handler handler, int timeout_msecs, void *userdata, const char *data, int datalen) { mspool *nsp = (mspool *) ms_pool; msiod *nsi = (msiod *) ms_iod; msevent *nse; char displaystr[256]; nse = msevent_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler, userdata); assert(nse); nse->writeinfo.dest.ss_family = AF_UNSPEC; if (datalen < 0) datalen = (int) strlen(data); if (nsp->tracelevel > 0) { if (nsp->tracelevel > 1 && datalen < 80) { memcpy(displaystr, ": ", 2); memcpy(displaystr + 2, data, datalen); displaystr[2 + datalen] = '\0'; replacenonprintable(displaystr + 2, datalen, '.'); } else displaystr[0] = '\0'; if (nsi->peerlen > 0) nsock_trace(nsp, "Write request for %d bytes to IOD #%li EID %li [%s:%hu]%s", datalen, nsi->id, nse->id, inet_ntop_ez(&nsi->peer, nsi->peerlen), nsi_peerport(nsi), displaystr); else nsock_trace(nsp, "Write request for %d bytes to IOD #%li EID %li (peer unspecified)%s", datalen, nsi->id, nse->id, displaystr); } fscat(&nse->iobuf, data, datalen); nsp_add_event(nsp, nse); return nse->id; }
/* Returns -1 if an error, otherwise the number of newly written bytes */ static int do_actual_read(mspool *ms, msevent *nse) { char buf[8192]; int buflen = 0; msiod *iod = nse->iod; int err = 0; int max_chunk = NSOCK_READ_CHUNK_SIZE; int startlen = FILESPACE_LENGTH(&nse->iobuf); if (nse->readinfo.read_type == NSOCK_READBYTES) max_chunk = nse->readinfo.num; if (!iod->ssl) { do { struct sockaddr_storage peer; socklen_t peerlen; peerlen = sizeof(peer); buflen = recvfrom(iod->sd, buf, sizeof(buf), 0, (struct sockaddr *)&peer, &peerlen); /* Using recv() was failing, at least on UNIX, for non-network sockets * (i.e. stdin) in this case, a read() is done - as on ENOTSOCK we may * have a non-network socket */ if (buflen == -1) { if (socket_errno() == ENOTSOCK) { peer.ss_family = AF_UNSPEC; peerlen = 0; buflen = read(iod->sd, buf, sizeof(buf)); } } if (buflen == -1) { err = socket_errno(); break; } if (peerlen > 0) { assert(peerlen <= sizeof(iod->peer)); memcpy(&iod->peer, &peer, peerlen); iod->peerlen = peerlen; } if (buflen > 0) { if (fscat(&nse->iobuf, buf, buflen) == -1) { nse->event_done = 1; nse->status = NSE_STATUS_ERROR; nse->errnum = ENOMEM; return -1; } /* Sometimes a service just spews and spews data. So we return after a * somewhat large amount to avoid monopolizing resources and avoid DOS * attacks. */ if (FILESPACE_LENGTH(&nse->iobuf) > max_chunk) return FILESPACE_LENGTH(&nse->iobuf) - startlen; /* No good reason to read again if we we were successful in the read but * didn't fill up the buffer. Especially for UDP, where we want to * return only one datagram at a time. The consistency of the above * assignment of iod->peer depends on not consolidating more than one * UDP read buffer. */ if (buflen > 0 && buflen < sizeof(buf)) return FILESPACE_LENGTH(&nse->iobuf) - startlen; } } while (buflen > 0 || (buflen == -1 && err == EINTR)); if (buflen == -1) { if (err != EINTR && err != EAGAIN) { nse->event_done = 1; nse->status = NSE_STATUS_ERROR; nse->errnum = err; return -1; } } } else { #if HAVE_OPENSSL /* OpenSSL read */ while ((buflen = SSL_read(iod->ssl, buf, sizeof(buf))) > 0) { if (fscat(&nse->iobuf, buf, buflen) == -1) { nse->event_done = 1; nse->status = NSE_STATUS_ERROR; nse->errnum = ENOMEM; return -1; } /* Sometimes a service just spews and spews data. So we return * after a somewhat large amount to avoid monopolizing resources * and avoid DOS attacks. */ if (FILESPACE_LENGTH(&nse->iobuf) > max_chunk) return FILESPACE_LENGTH(&nse->iobuf) - startlen; } if (buflen == -1) { err = SSL_get_error(iod->ssl, buflen); if (err == SSL_ERROR_WANT_READ) { int evclr; evclr = socket_count_dec_ssl_desire(nse); socket_count_read_inc(iod); update_events(iod, ms, EV_READ, evclr); nse->sslinfo.ssl_desire = err; } else if (err == SSL_ERROR_WANT_WRITE) { int evclr; evclr = socket_count_dec_ssl_desire(nse); socket_count_write_inc(iod); update_events(iod, ms, EV_WRITE, evclr); nse->sslinfo.ssl_desire = err; } else { /* Unexpected error */ nse->event_done = 1; nse->status = NSE_STATUS_ERROR; nse->errnum = EIO; if (ms->tracelevel > 2) nsock_trace(ms, "SSL_read() failed for reason %s on NSI %li", ERR_reason_error_string(err), iod->id); return -1; } } #endif /* HAVE_OPENSSL */ } if (buflen == 0) { nse->event_done = 1; nse->eof = 1; if (FILESPACE_LENGTH(&nse->iobuf) > 0) { nse->status = NSE_STATUS_SUCCESS; return FILESPACE_LENGTH(&nse->iobuf) - startlen; } else { nse->status = NSE_STATUS_EOF; return 0; } } return FILESPACE_LENGTH(&nse->iobuf) - startlen; }
/* Same as nsock_write except you can use a printf-style format and you can only use this for ASCII strings */ nsock_event_id nsock_printf(nsock_pool ms_pool, nsock_iod ms_iod, nsock_ev_handler handler, int timeout_msecs, void *userdata, char *format, ... ) { mspool *nsp = (mspool *) ms_pool; msiod *nsi = (msiod *) ms_iod; msevent *nse; char buf[4096]; char *buf2 = NULL; int res, res2; int strlength = 0; char displaystr[256]; va_list ap; va_start(ap,format); nse = msevent_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler, userdata); assert(nse); res = Vsnprintf(buf, sizeof(buf), format, ap); va_end(ap); if (res != -1) { if (res > sizeof(buf)) { buf2 = (char * ) safe_malloc(res + 16); res2 = Vsnprintf(buf2, sizeof(buf), format, ap); if (res2 == -1 || res2 > res) { free(buf2); buf2 = NULL; } else strlength = res2; } else { buf2 = buf; strlength = res; } } if (!buf2) { nse->event_done = 1; nse->status = NSE_STATUS_ERROR; nse->errnum = EMSGSIZE; } else { if (strlength == 0) { nse->event_done = 1; nse->status = NSE_STATUS_SUCCESS; } else { fscat(&nse->iobuf, buf2, strlength); } } if (nsp->tracelevel > 0) { if (nsp->tracelevel > 1 && nse->status != NSE_STATUS_ERROR && strlength < 80) { memcpy(displaystr, ": ", 2); memcpy(displaystr + 2, buf2, strlength); displaystr[2 + strlength] = '\0'; replacenonprintable(displaystr + 2, strlength, '.'); } else displaystr[0] = '\0'; if (nsi->peerlen > 0) nsock_trace(nsp, "Write request for %d bytes to IOD #%li EID %li [%s:%hu]%s", strlength, nsi->id, nse->id, inet_ntop_ez(&nsi->peer, nsi->peerlen), nsi_peerport(nsi), displaystr); else nsock_trace(nsp, "Write request for %d bytes to IOD #%li EID %li (peer unspecified)%s", strlength, nsi->id, nse->id, displaystr); } if (buf2 != buf) { free(buf2); } nsp_add_event(nsp, nse); return nse->id; }