coroutine void dialogue(tcpsock as, chan ch) { chs(ch, int, CONN_ESTABLISHED); int64_t deadline = now() + 10000; tcpsend(as, "What's your name?\r\n", 19, deadline); if(errno != 0) goto cleanup; tcpflush(as, deadline); if(errno != 0) goto cleanup; char inbuf[256]; size_t sz = tcprecvuntil(as, inbuf, sizeof(inbuf), "\r", 1, deadline); if(errno != 0) goto cleanup; inbuf[sz - 1] = 0; char outbuf[256]; int rc = snprintf(outbuf, sizeof(outbuf), "Hello, %s!\r\n", inbuf); sz = tcpsend(as, outbuf, rc, deadline); if(errno != 0) goto cleanup; tcpflush(as, deadline); cleanup: if(errno == 0) chs(ch, int, CONN_SUCCEEDED); else chs(ch, int, CONN_FAILED); tcpclose(as); }
coroutine void dialogue(tcpsock as) { int64_t deadline = now() + 10000; tcpsend(as, "What's your name?\r\n", 19, deadline); if(errno != 0) goto cleanup; tcpflush(as, deadline); if(errno != 0) goto cleanup; char inbuf[256]; size_t sz = tcprecvuntil(as, inbuf, sizeof(inbuf), "\r", 1, deadline); if(errno != 0) goto cleanup; inbuf[sz - 1] = 0; char outbuf[256]; int rc = snprintf(outbuf, sizeof(outbuf), "Hello, %s!\r\n", inbuf); sz = tcpsend(as, outbuf, rc, deadline); if(errno != 0) goto cleanup; tcpflush(as, deadline); if(errno != 0) goto cleanup; cleanup: tcpclose(as); }
int main(int argc, char *argv[]) { int port = 5555; if(argc > 1) port = atoi(argv[1]); tcpsock ls = tcplisten(iplocal(NULL, port, 0)); if(!ls) { perror("Can't open listening socket"); return 1; } while(1) { tcpsock as = tcpaccept(ls, -1); tcpsend(as, "What's your name?\r\n", 19, -1); tcpflush(as, -1); char inbuf[256]; size_t sz = tcprecvuntil(as, inbuf, sizeof(inbuf), "\r", 1, -1); inbuf[sz - 1] = 0; char outbuf[256]; int rc = snprintf(outbuf, sizeof(outbuf), "Hello, %s!\n", inbuf); sz = tcpsend(as, outbuf, rc, -1); tcpflush(as, -1); tcpclose(as); } }
size_t wsocksend(wsock s, const void *msg, size_t len, int64_t deadline) { if(s->flags & WSOCK_LISTENING) {errno = EOPNOTSUPP; return 0;} if(s->flags & WSOCK_BROKEN) {errno = ECONNABORTED; return 0;} uint8_t buf[12]; size_t sz; buf[0] = 0x82; if(len > 0xffff) { buf[1] = 127; wsock_putll(buf + 2, len); sz = 10; } else if(len > 125) { buf[1] = 126; wsock_puts(buf + 2, len); sz = 4; } else { buf[1] = (uint8_t)len; sz = 2; } uint8_t mask[4]; if(s->flags & WSOCK_CLIENT) { ((uint16_t*)mask)[0] = (uint16_t)wsock_random(); ((uint16_t*)mask)[1] = (uint16_t)wsock_random(); buf[1] |= 0x80; memcpy(buf + sz, mask, 4); sz += 4; } tcpsend(s->u, buf, sz, deadline); if(errno != 0) {s->flags |= WSOCK_BROKEN; return 0;} if(s->flags & WSOCK_CLIENT) { /* TODO: Use static buffer or something. This way of implementing mapping is performance nightmare. */ uint8_t *masked = malloc(len); if(!masked) {s->flags |= WSOCK_BROKEN; errno = ENOMEM; return 0;} size_t i; for(i = 0; i != len; ++i) masked[i] = ((uint8_t*)msg)[i] ^ mask[i % 4]; tcpsend(s->u, masked, len, deadline); int err = errno; free(masked); errno = err; } else { tcpsend(s->u, msg, len, deadline); } if(errno != 0) {s->flags |= WSOCK_BROKEN; return 0;} tcpflush(s->u, deadline); if(errno != 0) {s->flags |= WSOCK_BROKEN; return 0;} return len; }
coroutine void client(int port) { ipaddr addr = ipremote("127.0.0.1", port, 0, -1); tcpsock cs = tcpconnect(addr, -1); assert(cs); char ipstr[16] = {0}; ipaddrstr(addr, ipstr); assert(errno == 0); assert(strcmp(ipstr, "127.0.0.1") == 0); int fd = tcpdetach(cs); assert(fd != -1); cs = tcpattach(fd, 0); assert(cs); msleep(now() + 100); char buf[16]; size_t sz = tcprecv(cs, buf, 3, -1); assert(sz == 3 && buf[0] == 'A' && buf[1] == 'B' && buf[2] == 'C'); sz = tcpsend(cs, "123\n45\n6789", 11, -1); assert(sz == 11 && errno == 0); tcpflush(cs, -1); assert(errno == 0); tcpclose(cs); }
int main() { tcpsock ls = tcplisten("*:5555"); assert(ls); go(client()); tcpsock as = tcpaccept(ls); tcpsend(as, "ABC", 3); int rc = tcpflush(as); assert(rc == 0); char buf[16]; ssize_t sz = tcprecvuntil(as, buf, sizeof(buf), '\n'); assert(sz == 4); assert(buf[0] == '1' && buf[1] == '2' && buf[2] == '3' && buf[3] == '\n'); sz = tcprecvuntil(as, buf, sizeof(buf), '\n'); assert(sz == 3); assert(buf[0] == '4' && buf[1] == '5' && buf[2] == '\n'); sz = tcprecvuntil(as, buf, 3, '\n'); assert(sz == 0); assert(buf[0] == '6' && buf[1] == '7' && buf[2] == '8'); tcpclose(as); tcpclose(ls); return 0; }
int main(int argc, char *argv[]) { int port = 5555; if(argc > 1) port = atoi(argv[1]); ipaddr addr = iplocal(NULL, port, 0); tcpsock ls = tcplisten(addr, 10); if(!ls) { perror("Can't open listening socket"); return 1; } while(1) { tcpsock as = tcpaccept(ls, -1); printf("New connection!\n"); tcpsend(as, "What's your name?\r\n", 19, -1); tcpflush(as, -1); tcpclose(as); } return 0; }
// java testButton. JNIEXPORT void JNICALL Java_com_projecttango_experiments_nativepointcloud_TangoJNINative_testButton( JNIEnv*, jobject) { float val [8 + 3*2]; //point no val[0]=3*2; //zaverage val[1]=2/2; //rotation val[2]=0.0; val[3]=-1.0; val[4]=-1.0; //translation val[5]=1.0; val[6]=0.0; val[7]=1.0; //points val[8]=2; val[9]=2; val[10]=2; val[11]=0.0; val[12]=0.0; val[13]=0.0; unsigned int microseconds=50; while(1){ tcpsend(val,sizeof(val)/sizeof(val[0])); std::this_thread::sleep_for(std::chrono::milliseconds(microseconds)); } }
void wsockpong(wsock s, int64_t deadline) { if(s->flags & WSOCK_LISTENING) {errno = EOPNOTSUPP; return;} if(s->flags & (WSOCK_BROKEN | WSOCK_DONE)) {errno = ECONNABORTED; return;} tcpsend(s->u, "\x8A\x00", 2, deadline); if(errno != 0) {s->flags |= WSOCK_BROKEN;} tcpflush(s->u, deadline); if(errno != 0) {s->flags |= WSOCK_BROKEN;} errno = 0; }
void doconnect(void) { ipaddr addr = ipremote("127.0.0.1", 5557, 0, -1); tcpsock s = tcpmuxconnect(addr, "foo", -1); assert(s); tcpsend(s, "abc", 3, -1); assert(errno == 0); tcpflush(s, -1); assert(errno == 0); }
/*------------------------------------------------------------------------ * tcpxmit - handle TCP output events while we are transmitting *------------------------------------------------------------------------ */ int tcpxmit(int tcbnum, int event) { struct tcb *ptcb = &tcbtab[tcbnum]; void *tv; int tosend, pending, window; if (event == RETRANSMIT) { tmclear(tcps_oport, MKEVENT(SEND, tcbnum)); tcprexmt(tcbnum, event); ptcb->tcb_ostate = TCPO_REXMT; return OK; } /* else SEND */ tosend = tcphowmuch(ptcb); if (tosend == 0) { if (ptcb->tcb_flags & TCBF_NEEDOUT) tcpsend(tcbnum, TSF_NEWDATA); /* just an ACK */ if (ptcb->tcb_snext == ptcb->tcb_suna) return OK; /* still unacked data; restart transmit timer */ tv = MKEVENT(RETRANSMIT, tcbnum); if (!tmleft(tcps_oport, tv)) tmset(tcps_oport, TCPQLEN, tv, ptcb->tcb_rexmt); return OK; } else if (ptcb->tcb_swindow == 0) { ptcb->tcb_ostate = TCPO_PERSIST; ptcb->tcb_persist = ptcb->tcb_rexmt; tcpsend(tcbnum, TSF_NEWDATA); tmset(tcps_oport, TCPQLEN, MKEVENT(PERSIST,tcbnum), ptcb->tcb_persist); return OK; } /* else, we have data and window */ ptcb->tcb_ostate = TCPO_XMIT; window = min(ptcb->tcb_swindow, ptcb->tcb_cwnd); pending = ptcb->tcb_snext - ptcb->tcb_suna; while (tcphowmuch(ptcb) > 0 && pending < window) { tcpsend(tcbnum, TSF_NEWDATA); pending = ptcb->tcb_snext - ptcb->tcb_suna; } tv = MKEVENT(RETRANSMIT, tcbnum); if (!tmleft(tcps_oport, tv)) tmset(tcps_oport, TCPQLEN, tv, ptcb->tcb_rexmt); return OK; }
int mqtt_send_packet(void* socket_info, const void* buf, unsigned int count) { NETSOCKET fd = *((NETSOCKET*)socket_info); int ret = 0; ret = tcpsend(fd, buf, count); if(ret < 0) printf("tcp send fail\n"); return ret; }
void handler(tcpsock accepted_socket, chan channel) { // request name from connected client tcpsend(accepted_socket, "What's your name?\r\n", 19, -1); tcpflush(accepted_socket, -1); // send a message to the communication channel, signifying this connection chs(channel, int, 1); // capture the name, and create a response message char inbuf[256], outbuf[256]; size_t size = tcprecvuntil(accepted_socket, inbuf, sizeof(inbuf), "\r", 1, -1); inbuf[size-1] = 0; int rc = snprintf(outbuf, sizeof(outbuf), "Hello, %s!\r\n", inbuf); // flush the message to the server tcpsend(accepted_socket, outbuf, rc, -1); cleanup: tcpflush(accepted_socket, -1); tcpclose(accepted_socket); }
void wsockdone(wsock s, int64_t deadline) { if(s->flags & WSOCK_LISTENING) {errno = EOPNOTSUPP; return;} if(s->flags & WSOCK_BROKEN) {errno = ECONNABORTED; return;} if(!(s->flags & WSOCK_DONE)) { if(s->flags & WSOCK_DONE) {errno = EPROTO; return;} tcpsend(s->u, "\x88\x00", 2, deadline); if(errno != 0) {s->flags |= WSOCK_BROKEN;} tcpflush(s->u, deadline); if(errno != 0) {s->flags |= WSOCK_BROKEN;} s->flags |= WSOCK_DONE; } errno = 0; }
void client(void) { tcpsock cs = tcpconnect("127.0.0.1:5555"); assert(cs); char buf[16]; ssize_t sz = tcprecv(cs, buf, 3); assert(buf[0] == 'A' && buf[1] == 'B' && buf[2] == 'C'); tcpsend(cs, "123\n45\n6789", 11); int rc = tcpflush(cs); assert(rc == 0); tcpclose(cs); }
int main(int argc, char *argv[]) { if(argc != 3) { printf("usage: c10k <parallel-connections> <roundtrip-count>\n"); return 1; } long conns = atol(argv[1]); long roundtrips = atol(argv[2]); assert(conns >= 1); tcpsock ls = tcplisten(iplocal("127.0.0.1", 5555, 0), 10); assert(ls); int i; for(i = 0; i != conns - 1; ++i) { go(connector()); tcpsock as = tcpaccept(ls, -1); assert(as); } go(sender(roundtrips)); tcpsock as = tcpaccept(ls, -1); assert(as); int64_t start = now(); char buf[1]; size_t nbytes; for(i = 0; i != roundtrips; ++i) { nbytes = tcpsend(as, "A", 1, -1); assert(errno == 0); assert(nbytes == 1); tcpflush(as, -1); assert(errno == 0); nbytes = tcprecv(as, buf, 1, -1); assert(errno == 0); assert(nbytes == 1); assert(buf[0] == 'A'); } int64_t stop = now(); long duration = (long)(stop - start); long us = (duration * 1000) / roundtrips; printf("done %ld roundtrips in %f seconds\n", roundtrips, ((float)duration) / 1000); printf("duration of a single roundtrip: %ld us\n", us); printf("roundtrips per second: %ld\n", (long)(roundtrips * 1000 / duration)); return 0; }
static coroutine void sender(long roundtrips) { tcpsock s = tcpconnect(iplocal("127.0.0.1", 5555, 0), -1); assert(s); char buf[1]; int i; size_t nbytes; for(i = 0; i != roundtrips; ++i) { nbytes = tcprecv(s, buf, 1, -1); assert(errno == 0); assert(nbytes == 1); assert(buf[0] == 'A'); nbytes = tcpsend(s, "A", 1, -1); assert(errno == 0); assert(nbytes == 1); tcpflush(s, -1); assert(errno == 0); } }
int main() { char buf[16]; tcpsock ls = tcplisten(iplocal(NULL, 5555, 0), 10); assert(ls); int fd = tcpdetach(ls); assert(fd != -1); ls = tcpattach(fd, 1); assert(ls); assert(tcpport(ls) == 5555); go(client(5555)); tcpsock as = tcpaccept(ls, -1); /* Test deadline. */ int64_t deadline = now() + 30; size_t sz = tcprecv(as, buf, sizeof(buf), deadline); assert(sz == 0 && errno == ETIMEDOUT); int64_t diff = now() - deadline; assert(diff > -20 && diff < 20); sz = tcpsend(as, "ABC", 3, -1); assert(sz == 3 && errno == 0); tcpflush(as, -1); assert(errno == 0); sz = tcprecvuntil(as, buf, sizeof(buf), "\n", 1, -1); assert(sz == 4); assert(buf[0] == '1' && buf[1] == '2' && buf[2] == '3' && buf[3] == '\n'); sz = tcprecvuntil(as, buf, sizeof(buf), "\n", 1, -1); assert(sz == 3); assert(buf[0] == '4' && buf[1] == '5' && buf[2] == '\n'); sz = tcprecvuntil(as, buf, 3, "\n", 1, -1); assert(sz == 3); assert(buf[0] == '6' && buf[1] == '7' && buf[2] == '8'); tcpclose(as); tcpclose(ls); return 0; }
void client(ipaddr addr, int messages, chan results) { int sent = 0; tcpsock s = tcpconnect(addr, -1); if (s == NULL) { perror("tcpconnect"); goto out; } while (messages--) { tcpsend(s, "hello\n", 6, -1); if (errno != 0) { perror("tcpsend"); goto out; } tcpflush(s, -1); if (errno != 0) { perror("tcpflush"); goto out; } char buf[100]; size_t sz = tcprecvuntil(s, buf, sizeof(buf), "\n", 1, -1); if (errno != 0) { perror("tcprecvuntil"); goto out; } buf[sz - 1] = 0; if (sz != 6) { fprintf(stderr, "unexpedted return: %s\n", buf); goto out; } sent++; } out: tcpclose(s); chs(results, int, sent); }
void tcpsendall(int sockid, const char *buff, int len, int maxtime) { smallset_t set; postime_t end = getcurtime() + maxtime, cur; int ret, x; set.init(1); set.set(0, sockid); while (len > 0) { while ((cur = getcurtime()) <= end) { set.init(1); set.set(0, sockid); x = end.after(cur); if (x > 1000) x = 1000; set.waitwrite(x); if (set.canwrite(0) || posclient_quitflag) break; } if (!set.canwrite(0)) throw PException("Could not send buffer"); ret = tcpsend(sockid, buff, len); buff += ret; len -= ret; } }
wsock wsockaccept(wsock s, int64_t deadline) { int err = 0; if(!(s->flags & WSOCK_LISTENING)) {err = EOPNOTSUPP; goto err0;} struct wsock *as = (struct wsock*)malloc(sizeof(struct wsock)); if(!as) {err = ENOMEM; goto err0;} as->flags = 0; as->u = tcpaccept(s->u, deadline); if(errno != 0) {err = errno; goto err1;} wsock_str_init(&as->url, NULL, 0); wsock_str_init(&as->subprotocol, NULL, 0); /* Parse request. */ char buf[256]; size_t sz = wsock_getline(as, buf, sizeof(buf), deadline); if(sz < 0) {err = errno; goto err2;} char *lend = buf + sz; char *wstart = buf; char *wend = (char*)memchr(buf, ' ', lend - wstart); if(!wend || wend - wstart != 3 || memcmp(wstart, "GET", 3) != 0) { err = EPROTO; goto err2;} wstart = wend + 1; wend = (char*)memchr(wstart, ' ', lend - wstart); if(!wend) {err = EPROTO; goto err2;} wsock_str_init(&as->url, wstart, wend - wstart); wstart = wend + 1; wend = (char*)memchr(wstart, ' ', lend - wstart); if(wend || lend - wstart != 8 || memcmp(wstart, "HTTP/1.1", 8) != 0) { err = EPROTO; goto err2;} int hasupgrade = 0; int hasconnection = 0; int haskey = 0; int hassubprotocol = 0; const char *subprotocol = NULL; size_t subprotocolsz = 0; struct wsock_sha1 sha1; while(1) { sz = wsock_getline(as, buf, sizeof(buf), deadline); if(sz < 0) {err = errno; goto err2;} if(sz == 0) break; lend = buf + sz; char *nstart = buf; char *nend = (char*)memchr(buf, ' ', lend - nstart); if(!nend || nend - nstart < 1 || nend[-1] != ':') { err = EPROTO; goto err2;} size_t nsz = nend - nstart - 1; char *vstart = nend + 1; char *vend = (char*)memchr(vstart, ' ', lend - vstart); if(vend) {err = EPROTO; goto err2;} size_t vsz = lend - vstart; if(nsz == 7 && memcmp(nstart, "Upgrade", 7) == 0) { if(hasupgrade || vsz != 9 || memcmp(vstart, "websocket", 9) != 0) { err = EPROTO; goto err2;} hasupgrade = 1; continue; } if(nsz == 10 && memcmp(nstart, "Connection", 10) == 0) { if(hasconnection || vsz != 7 || memcmp(vstart, "Upgrade", 7) != 0) { err = EPROTO; goto err2;} hasconnection = 1; continue; } if(nsz == 17 && memcmp(nstart, "Sec-WebSocket-Key", 17) == 0) { if(haskey) {err = EPROTO; goto err2;} wsock_sha1_init(&sha1); int i; for(i = 0; i != vsz; ++i) wsock_sha1_hashbyte(&sha1, vstart[i]); const char *uuid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; for(i = 0; i != 36; ++i) wsock_sha1_hashbyte(&sha1, uuid[i]); haskey = 1; continue; } if(nsz == 22 && memcmp(nstart, "Sec-WebSocket-Protocol", 22) == 0) { /* TODO: RFC6455, section 11.3.4 allows for multiple instances of this field. */ if(hassubprotocol) {err = EPROTO; goto err2;} const char *available = wsock_str_get(&s->subprotocol); if(available) { subprotocol = wsock_hassubprotocol(available, vstart, vsz, &subprotocolsz); if(!subprotocol) {err = EPROTO; goto err2;} } else { subprotocol = vstart; subprotocolsz = vsz; } hassubprotocol = 1; wsock_str_init(&as->subprotocol, subprotocol, subprotocolsz); continue; } } if(!hasupgrade || !hasconnection || !haskey) {err = EPROTO; goto err2;} /* If the subprotocol was not specified by the client, we still want to use one of the suerver-supported protocols locally. */ if(!subprotocol) { const char *available = wsock_str_get(&s->subprotocol); if(available) { size_t asz = 0; while(available[asz] != 0 && available[asz] != ',') ++asz; wsock_str_init(&as->subprotocol, available, asz); } } /* Send reply. */ const char *lit1 = "HTTP/1.1 101 Switching Protocols\r\n" "Upgrade: websocket\r\n" "Connection: Upgrade\r\n" "Sec-WebSocket-Accept: "; tcpsend(as->u, lit1, strlen(lit1), deadline); if(errno != 0) {err = errno; goto err2;} char key[32]; wsock_sha1_result(&sha1); sz = wsock_base64_encode(wsock_sha1_result(&sha1), 20, key, sizeof(key)); assert(sz > 0); tcpsend(as->u, key, sz, deadline); if(errno != 0) {err = errno; goto err2;} if(hassubprotocol) { tcpsend(as->u, "\r\nSec-WebSocket-Protocol: ", 26, deadline); if(errno != 0) {err = errno; goto err2;} tcpsend(as->u, subprotocol, subprotocolsz, deadline); if(errno != 0) {err = errno; goto err2;} } tcpsend(as->u, "\r\n\r\n", 4, deadline); if(errno != 0) {err = errno; goto err2;} tcpflush(as->u, deadline); if(errno != 0) {err = errno; goto err2;} return as; err2: tcpclose(as->u); err1: free(as); err0: errno = err; return NULL; }
wsock wsockconnect(ipaddr addr, const char *subprotocol, const char *url, int64_t deadline) { /* Check the arguments. */ if(!wsock_checkstring(url)) return NULL; if(subprotocol) { if(!wsock_checkstring(subprotocol)) return NULL; } /* Open TCP connection. */ int err = 0; struct wsock *s = (struct wsock*)malloc(sizeof(struct wsock)); if(!s) {err = ENOMEM; goto err0;} s->flags = WSOCK_CLIENT; s->u = tcpconnect(addr, deadline); if(errno != 0) {err = errno; goto err1;} wsock_str_init(&s->url, url, strlen(url)); wsock_str_init(&s->subprotocol, NULL, 0); /* Send request. */ tcpsend(s->u, "GET ", 4, deadline); if(errno != 0) {err = errno; goto err2;} tcpsend(s->u, url, strlen(url), deadline); if(errno != 0) {err = errno; goto err2;} const char *lit1 = " HTTP/1.1\r\n" "Upgrade: websocket\r\n" "Connection: Upgrade\r\n" "Sec-WebSocket-Key: "; tcpsend(s->u, lit1, strlen(lit1), deadline); if(errno != 0) {err = errno; goto err2;} uint8_t nonce[16]; int i; for(i = 0; i != 8; ++i) ((uint16_t*) nonce)[i] = wsock_random() & 0xffff; char swsk[32]; int swsk_len = wsock_base64_encode(nonce, 16, swsk, sizeof(swsk)); assert(swsk_len > 0); tcpsend(s->u, swsk, swsk_len, deadline); if(errno != 0) {err = errno; goto err2;} if(subprotocol) { tcpsend(s->u, "\r\nSec-WebSocket-Protocol: ", 26, deadline); if(errno != 0) {err = errno; goto err2;} tcpsend(s->u, subprotocol, strlen(subprotocol), deadline); if(errno != 0) {err = errno; goto err2;} } tcpsend(s->u, "\r\n\r\n", 4, deadline); if(errno != 0) {err = errno; goto err2;} tcpflush(s->u, deadline); if(errno != 0) {err = errno; goto err2;} /* Parse reply. */ char buf[256]; size_t sz = wsock_getline(s, buf, sizeof(buf), deadline); if(sz < 0) {err = errno; goto err2;} char *lend = buf + sz; char *wstart = buf; char *wend = (char*)memchr(buf, ' ', lend - wstart); if(!wend || wend - wstart != 8 || memcmp(wstart, "HTTP/1.1", 8) != 0) { err = EPROTO; goto err2;} wstart = wend + 1; wend = (char*)memchr(wstart, ' ', lend - wstart); if(!wend || wend - wstart != 3 || memcmp(wstart, "101", 3) != 0) { err = EPROTO; goto err2;} int hasupgrade = 0; int hasconnection = 0; int haskey = 0; int hassubprotocol = 0; while(1) { sz = wsock_getline(s, buf, sizeof(buf), deadline); if(sz < 0) {err = errno; goto err2;} if(sz == 0) break; lend = buf + sz; char *nstart = buf; char *nend = (char*)memchr(buf, ' ', lend - nstart); if(!nend || nend - nstart < 1 || nend[-1] != ':') { err = EPROTO; goto err2;} size_t nsz = nend - nstart - 1; char *vstart = nend + 1; char *vend = (char*)memchr(vstart, ' ', lend - vstart); if(vend) {err = EPROTO; goto err2;} size_t vsz = lend - vstart; if(nsz == 7 && memcmp(nstart, "Upgrade", 7) == 0) { if(hasupgrade || vsz != 9 || memcmp(vstart, "websocket", 9) != 0) { err = EPROTO; goto err2;} hasupgrade = 1; continue; } if(nsz == 10 && memcmp(nstart, "Connection", 10) == 0) { if(hasconnection || vsz != 7 || memcmp(vstart, "Upgrade", 7) != 0) { err = EPROTO; goto err2;} hasconnection = 1; continue; } if(nsz == 20 && memcmp(nstart, "Sec-WebSocket-Accept", 20) == 0) { if(haskey) {err = EPROTO; goto err2;} /* TODO */ haskey = 1; continue; } if(nsz == 22 && memcmp(nstart, "Sec-WebSocket-Protocol", 22) == 0) { if(hassubprotocol) {err = EPROTO; goto err2;} for(i = 0; i != vsz; ++i) if(vstart[i] == ',') {err = EPROTO; goto err2;} if(!wsock_hassubprotocol(subprotocol, vstart, vsz, NULL)) { err = EPROTO; goto err2;} wsock_str_init(&s->subprotocol, vstart, vsz); hassubprotocol = 1; continue; } } if(!hasupgrade || !hasconnection || !haskey) {err = EPROTO; goto err2;} return s; err2: tcpclose(s->u); err1: free(s); err0: errno = err; return NULL; }
size_t wsockrecv(wsock s, void *msg, size_t len, int64_t deadline) { if(s->flags & WSOCK_LISTENING) {errno = EOPNOTSUPP; return 0;} if(s->flags & WSOCK_BROKEN) {errno = ECONNABORTED; return 0;} size_t res = 0; while(1) { uint8_t hdr1[2]; tcprecv(s->u, hdr1, 2, deadline); if(errno != 0) {s->flags |= WSOCK_BROKEN; return 0;} if(hdr1[0] & 0x70) { s->flags &= WSOCK_BROKEN; errno = EPROTO; return 0;} int opcode = hdr1[0] & 0x0f; if(opcode == 8) { if(!(s->flags & WSOCK_DONE)) { /* TODO: Close frames from client should be masked. */ tcpsend(s->u, "\x88\x00", 2, deadline); tcpflush(s->u, deadline); s->flags |= (WSOCK_BROKEN & WSOCK_DONE); } errno = ECONNRESET; return 0; } if(opcode == 9) { /* TODO: Account for pings and pongs with payload. */ if(!(s->flags & WSOCK_DONE)) { tcpsend(s->u, "\x8A\x00", 2, deadline); if(errno != 0) {s->flags &= WSOCK_BROKEN; return 0;} tcpflush(s->u, deadline); if(errno != 0) {s->flags &= WSOCK_BROKEN; return 0;} } continue; } if(opcode == 10) { /* TODO: Account for pings and pongs with payload. */ /* TODO: Do we want to make exiting the function here optional? */ errno = EAGAIN; return 0; } if(!!(s->flags & WSOCK_CLIENT) ^ !(hdr1[1] & 0x80)) { s->flags &= WSOCK_BROKEN; errno = EPROTO; return 0;} size_t sz = hdr1[1] & 0x7f; if(sz == 126) { uint8_t hdr2[2]; tcprecv(s->u, hdr2, 2, deadline); if(errno != 0) {s->flags |= WSOCK_BROKEN; return 0;} sz = wsock_gets(hdr2); } else if(sz == 127) { uint8_t hdr2[8]; tcprecv(s->u, hdr2, 8, deadline); if(errno != 0) {s->flags |= WSOCK_BROKEN; return 0;} sz = wsock_getll(hdr2); } uint8_t mask[4]; if(!(s->flags & WSOCK_CLIENT)) { tcprecv(s->u, mask, 4, deadline); if(errno != 0) {s->flags |= WSOCK_BROKEN; return 0;} } size_t toread = sz < len ? sz : len; if(toread > 0) { tcprecv(s->u, msg, toread, deadline); if(errno != 0) {s->flags |= WSOCK_BROKEN; return 0;} } if(!(s->flags & WSOCK_CLIENT)) { size_t i; for(i = 0; i != toread; ++i) ((uint8_t*)msg)[i] ^= mask[i % 4]; } if(sz > toread) { tcprecv(s->u, NULL, sz - toread, deadline); if(errno != 0) {s->flags |= WSOCK_BROKEN; return 0;} } res += sz; if(hdr1[0] & 0x80) break; msg = ((uint8_t*)msg) + sz; len -= sz; } return res; }
/*---------------------------------------------------------------------------*/ PROCESS_THREAD(http_req_process, ev, data) { static struct etimer httptimeout; SOCKETMSG msg; PROCESS_BEGIN(); while(1) { //wait for TCP connected or uip_timeout. PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_MSG || ev == PROCESS_EVENT_TIMER || ev == PROCESS_EVENT_EXIT); if(ev == PROCESS_EVENT_MSG) { msg = *(SOCKETMSG *)data; if(msg.status == SOCKET_CONNECTED) { //send out the http request. if(httpreqdata.cmdlen) tcpsend(httpreqdata.httpsock, httpreqdata.httpcmd, httpreqdata.cmdlen); } else if(msg.status == SOCKET_SENDACK) { //set timeot for http response. etimer_set(&httptimeout, 10 * CLOCK_CONF_SECOND); } else if(msg.status == SOCKET_NEWDATA) { //Get http response, parse response and close socket. etimer_stop(&httptimeout); httpreqdata.rsplen = tcprecv(httpreqdata.httpsock, httpreqdata.httprsp, HTTPRSP_MAX); tcpclose(httpreqdata.httpsock); httpreqdata.httpsock = -1; httpreqdata.httpstatus = HTTP_IDLE; if(httpreqdata.rsplen > 0 && httpreqdata.callbackfn) { httpreqdata.httprsp[httpreqdata.rsplen] = 0; httprsp_parse(httpreqdata.httprsp, httpreqdata.rsplen); } } else if(msg.status == SOCKET_CLOSED) { //socket closed, if it is unnormal case, notify upper layer. if(httpreqdata.httpstatus != HTTP_IDLE) { if(httpreqdata.callbackfn) { httpmsg.msgtype = HTTPREQ_CONN_ERROR; httpmsg.rsp = NULL; httpreqdata.callbackfn(&httpmsg); } httpreqdata.httpsock = -1; httpreqdata.httpstatus = HTTP_IDLE; } } } else if(ev == PROCESS_EVENT_TIMER) { //http response timeout, close socket and notify upper layer. tcpclose(httpreqdata.httpsock); httpreqdata.httpsock = -1; httpreqdata.httpstatus = HTTP_IDLE; if(httpreqdata.callbackfn) { httpmsg.msgtype = HTTPREQ_RSP_TIMEOUT; httpmsg.rsp = NULL; httpreqdata.callbackfn(&httpmsg); } } else if(ev == PROCESS_EVENT_EXIT) { break; } } PROCESS_END(); }