int tcpconnect(const ipaddr *addr, int64_t deadline) { int err; /* Open a socket. */ int s = socket(ipfamily(addr), SOCK_STREAM, 0); if(dill_slow(s < 0)) return -1; tcptune(s); /* Connect to the remote endpoint. */ int rc = dsconnect(s, ipsockaddr(addr), iplen(addr), deadline); if(dill_slow(rc < 0)) return -1; /* Create the object. */ struct tcpconn *conn = tcpconn_create(); if(dill_slow(!conn)) {err = errno; goto error1;} conn->fd = s; conn->addr = *addr; /* Bind the object to a sock handle. */ int bs = bsock(tcpconn_type, conn, &tcpconn_vfptrs); if(dill_slow(bs < 0)) {err = errno; goto error2;} return bs; error2: tcpconn_destroy(conn); error1: rc = dsclose(s); dill_assert(rc == 0); errno = err; return -1; }
char * get_packet(int fd) { size_t cnt = 0, len = 0; ssize_t rc = 0; unsigned char * pkt = malloc(20 + 4); if(!pkt) { printf("Unable to malloc() space for next packet!\n"); return NULL; } // 4 bytes, TUN info + 20 bytes, the size of an IP header while (cnt < (20 + 4)) { if ((rc = read(fd, pkt+cnt, 24)) <= 0 ) { if (rc < 0) { if (errno == EINTR) continue; printf("Socket #%d: Reading IP hdr: %s.", fd, strerror(errno)); } else printf("Socket #%d: Read %d bytes, expected 24 (hdr).", fd, cnt); free(pkt); return NULL; } cnt += rc; } len = iplen(pkt); return pkt; }
int handle_s_p2( clidata_t *client, char *hdrs ) { int gotten=0; int expected = get_content_length(hdrs); char *pkt; int cnt=0; queue_t *recvq = client->recvq; int chan1 = client->chan1; if( !expected ) { lprintf(log, WARN, "Client sent no Content-Length. Dropping."); return -1; } while( gotten < expected ) { if( (pkt=get_packet(chan1)) == NULL ) { lprintf(log, WARN, "get_packet() failed. Dropping client."); fdprintf(chan1, RESPONSE_500_ERR); return -1; } cnt++; gotten += iplen(pkt); dprintf(log, DEBUG, "got %d of %d bytes from client", gotten, expected); if( (q_add(recvq, pkt, Q_WAIT, iplen(pkt))) == -1 ) { lprintf(log, WARN, "q_add() failed. Dropping client."); fdprintf(chan1, RESPONSE_500_ERR); return -1; } } lprintf(log, INFO, "Got %d bytes in %d pkts", gotten, cnt); fdprintf(chan1, RESPONSE_204); return 0; }
int tcplisten(const ipaddr *addr, int backlog) { int err; if(dill_slow(backlog < 0)) {errno = EINVAL; return -1;} /* Open listening socket. */ int s = socket(ipfamily(addr), SOCK_STREAM, 0); if(dill_slow(s < 0)) return -1; tcptune(s); /* Start listening. */ int rc = bind(s, ipsockaddr(addr), iplen(addr)); if(dill_slow(rc != 0)) return -1; rc = listen(s, backlog); if(dill_slow(rc != 0)) return -1; /* If the user requested an ephemeral port, retrieve the port number assigned by the OS now. */ int port = ipport(addr); if(port == 0) { ipaddr baddr; socklen_t len = sizeof(ipaddr); rc = getsockname(s, (struct sockaddr*)&baddr, &len); if(dill_slow(rc < 0)) {err = errno; goto error1;} port = ipport(&baddr); } /* Create the object. */ struct tcplistener *lst = malloc(sizeof(struct tcplistener)); if(dill_slow(!lst)) {errno = ENOMEM; goto error1;} lst->fd = s; lst->port = port; /* Bind the object to a handle. */ int h = handle(tcplistener_type, lst, &tcplistener_vfptrs); if(dill_slow(h < 0)) {err = errno; goto error2;} return h; error2: free(lst); error1: rc = dsclose(s); dill_assert(rc == 0); errno = err; return -1; }
int handle_r_p2( clidata_t *client, char *hdrs ) { int expected = get_content_length(hdrs); queue_t *sendq = client->sendq; int chan2 = client->chan2; struct timespec ts; char *body; int sex; char *pkt; if( !expected ) { lprintf(log, WARN, "Client sent no Content-Length. Dropping."); goto cleanup1; } if( (body=getbody(chan2, hdrs, &expected)) == NULL ) { lprintf(log, WARN, "getbody() failed. Dropping client."); goto cleanup1; } if( (sex=strtol(body, NULL, 0)) == 0 ) { lprintf(log, WARN, "Client sent invalid seconds spec."); fdprintf(chan2, RESPONSE_400); goto cleanup2; } ts.tv_nsec = 0; ts.tv_sec = sex; dprintf(log, DEBUG, "waiting up to %d seconds.", sex); if( q_timedwait(sendq, &ts) ) { int sent=0, total, cnt=0; dprintf(log, DEBUG, "returned from wait, with data"); total = sendq->totsize; fdprintf(chan2, RESPONSE_200_NOBODY, sendq->totsize); while( sent < total ) { if( (pkt=q_remove(sendq, 0, NULL)) == NULL ) { lprintf(log, WARN, "q_remove failed!"); goto cleanup2; } if( write(chan2, pkt, iplen(pkt)) < 0 ) { lprintf(log, INFO, "send failed: %s", strerror(errno)); free(pkt); goto cleanup2; } cnt++; sent += iplen(pkt); free(pkt); } lprintf(log, INFO, "Sent %d bytes in %d pkts", sent, cnt); } else { dprintf(log, DEBUG, "returned from wait, with NO data"); if( client->chan2 != -1 ) fdprintf(chan2, RESPONSE_204); } return 0; cleanup2: free(body); cleanup1: return -1; }