void first_whisper(void* chan) { long *v = (long *)go_malloc(sizeof(long)); *v = 1; chan_send(chan, v); }
void whisper(void* args) { long *r = (long *)go_malloc(sizeof(long)); /*channels *chans = (channels *)args;*/ channels *chans; writebarrierptr((void**)&chans, args); *r = *(long *)chan_recv(chans->right); *r += 1; chan_send(chans->left, r); }
int main(void) { switch_t s; chan_t c; packet_t p; path_t in; int sock; crypt_init(); s = switch_new(0); if(util_loadjson(s) != 0 || (sock = util_server(0,1000)) <= 0) { printf("failed to startup %s or %s\n", strerror(errno), crypt_err()); return -1; } printf("loaded hashname %s\n",s->id->hexname); // create/send a ping packet c = chan_new(s, bucket_get(s->seeds, 0), "link", 0); p = chan_packet(c); chan_send(c, p); util_sendall(s,sock); in = path_new("ipv4"); while(util_readone(s, sock, in) == 0) { switch_loop(s); while((c = switch_pop(s))) { printf("channel active %d %s %s\n",c->state,c->hexid,c->to->hexname); if(util_cmp(c->type,"connect") == 0) ext_connect(c); if(util_cmp(c->type,"link") == 0) ext_link(c); if(util_cmp(c->type,"path") == 0) ext_path(c); while((p = chan_pop(c))) { printf("unhandled channel packet %.*s\n", p->json_len, p->json); packet_free(p); } if(c->state == ENDED) chan_free(c); } util_sendall(s,sock); } perror("exiting"); return 0; }
// chunk the packet out void thtp_send(chan_t c, lob_t req) { lob_t chunk; unsigned char *raw; unsigned short len, space; if(!c || !req) return; DEBUG_PRINTF("THTP sending %.*s %.*s",req->json_len,req->json,req->body_len,req->body); raw = lob_raw(req); len = lob_len(req); while(len) { chunk = chan_packet(c); if(!chunk) return; // TODO backpressure space = lob_space(chunk); if(space > len) space = len; lob_body(chunk,raw,space); if(len==space) lob_set(chunk,"end","true",4); chan_send(c,chunk); raw+=space; len-=space; } }
// A select statement chooses which of a set of possible send or receive // operations will proceed. The return value indicates which channel's // operation has proceeded. If more than one operation can proceed, one is // selected randomly. If none can proceed, -1 is returned. Select is intended // to be used in conjunction with a switch statement. In the case of a receive // operation, the received value will be pointed to by the provided pointer. In // the case of a send, the value at the same index as the channel will be sent. int chan_select(chan_t* recv_chans[], int recv_count, void** recv_out, chan_t* send_chans[], int send_count, void* send_msgs[]) { // TODO: Add support for blocking selects. select_op_t candidates[recv_count + send_count]; int count = 0; int i; // Determine receive candidates. for (i = 0; i < recv_count; i++) { chan_t* chan = recv_chans[i]; if (chan_can_recv(chan)) { select_op_t op; op.recv = 1; op.chan = chan; op.index = i; candidates[count++] = op; } } // Determine send candidates. for (i = 0; i < send_count; i++) { chan_t* chan = send_chans[i]; if (chan_can_send(chan)) { select_op_t op; op.recv = 0; op.chan = chan; op.msg_in = send_msgs[i]; op.index = i + recv_count; candidates[count++] = op; } } if (count == 0) { return -1; } // Seed rand using current time in nanoseconds. struct timespec ts; current_utc_time(&ts); srand(ts.tv_nsec); // Select candidate and perform operation. select_op_t select = candidates[rand() % count]; if (select.recv && chan_recv(select.chan, recv_out) != 0) { return -1; } else if (!select.recv && chan_send(select.chan, select.msg_in) != 0) { return -1; } return select.index; }
void lt_main(void *arg) { int fd, opt = 1; proxy_server *srv = (proxy_server*)arg; lthread_t *lt_accept = NULL; struct sockaddr cin = {0}; socklen_t addrlen = sizeof(struct sockaddr); proxy_conn_t *proxy = NULL; DEFINE_LTHREAD; lthread_detach(); srv->listen_fd = create_listener("0.0.0.0", 9000); if(srv->listen_fd < 0) { exit(1); } fprintf(stderr, "listener creating :9000\n"); lthread_create(<_accept, (void*)lt_accept_loop, (void*)srv); while(!srv->is_die) { fd = lthread_accept(srv->listen_fd, &cin, &addrlen); if(fd < 0) { perror("accept error"); break; } if(srv->quiting) { lthread_close(fd); break; } if(srv->is_die) { //already die, close and break lthread_close(fd); fprintf(stderr, "server already die :9000\n"); break; } if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)) == -1) { perror("failed to set SOREUSEADDR on socket"); break; } fprintf(stderr, "accept new client\n"); proxy = proxy_conn_create(fd, 0); if(0 != chan_send(srv->accepts_ch, proxy)) { //send failed, free proxy proxy_conn_free(proxy); break; } //yield myself lthread_sleep((uint64_t)0); } if(-1 != srv->listen_fd) { close(srv->listen_fd); srv->listen_fd = -1; } if(!srv->is_die) { srv->is_die = 1; chan_close(srv->die_ch); fprintf(stderr, "srv die\n"); } fprintf(stderr, "lt_accept end\n"); lthread_join(lt_accept, NULL, LTHREAD_FOREVER); //server release server_release(srv); }