// creates/reuses a single default block channel on the link link_t ext_block_send(link_t link, lob_t block) { channel3_t chan; if(!link || !block) return LOG("bad args"); if(!(chan = xht_get(link->index,"block"))) { // TODO create outgoing channel xht_set(link->index,"block",chan); } // break block into packets and send return link; }
net_serial_t net_serial_new(mesh_t mesh, lob_t options) { net_serial_t net; unsigned int pipes; if(!(net = malloc(sizeof (struct net_serial_struct)))) return LOG("OOM"); memset(net,0,sizeof (struct net_serial_struct)); pipes = lob_get_uint(options,"pipes"); if(!pipes) pipes = 3; // hashtable for active pipes net->pipes = xht_new(pipes); // connect us to this mesh net->mesh = mesh; xht_set(mesh->index, "net_serial", net); return net; }
net_tcp4_t net_tcp4_new(mesh_t mesh, lob_t options) { int port, sock, pipes, opt = 1; net_tcp4_t net; struct sockaddr_in sa; socklen_t size = sizeof(struct sockaddr_in); port = lob_get_int(options,"port"); pipes = lob_get_int(options,"pipes"); if(!pipes) pipes = 11; // hashtable for active pipes // create a udp socket if((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) ) < 0 ) return LOG("failed to create socket %s",strerror(errno)); memset(&sa,0,sizeof(sa)); sa.sin_family = AF_INET; sa.sin_port = htons(port); sa.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(sock, (struct sockaddr*)&sa, size) < 0) return LOG("bind failed %s",strerror(errno)); getsockname(sock, (struct sockaddr*)&sa, &size); if(listen(sock, 10) < 0) return LOG("listen failed %s",strerror(errno)); setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt , sizeof(int)); fcntl(sock, F_SETFL, O_NONBLOCK); if(!(net = malloc(sizeof (struct net_tcp4_struct)))) return LOG("OOM"); memset(net,0,sizeof (struct net_tcp4_struct)); net->server = sock; net->port = ntohs(sa.sin_port); net->pipes = xht_new(pipes); // connect us to this mesh net->mesh = mesh; xht_set(mesh->index, MUID, net); mesh_on_path(mesh, MUID, tcp4_path); // convenience net->path = lob_new(); lob_set(net->path,"type","tcp4"); lob_set(net->path,"ip","127.0.0.1"); lob_set_int(net->path,"port",net->port); return net; }
link_t link_new(mesh_t mesh, hashname_t id) { link_t link; if(!mesh || !id) return LOG("invalid args"); LOG("adding link %s",id->hashname); if(!(link = malloc(sizeof (struct link_struct)))) return (link_t)hashname_free(id); memset(link,0,sizeof (struct link_struct)); link->id = id; link->mesh = mesh; xht_set(mesh->index,id->hashname,link); // to size larger, app can xht_free(); link->channels = xht_new(BIGGER) at start itself link->channels = xht_new(5); // index of all channels link->index = xht_new(5); // index for active channels and extensions return link; }
pipe_t net_serial_add(net_serial_t net, const char *name, int (*read)(void), int (*write)(uint8_t *buf, size_t len), uint8_t buffer) { pipe_t pipe; pipe_serial_t to; // just sanity checks if(!net || !name || !read || !write) return NULL; pipe = xht_get(net->pipes, name); if(!pipe) { if(!(pipe = pipe_new("serial"))) return NULL; if(!(pipe->arg = to = malloc(sizeof (struct pipe_serial_struct)))) return pipe_free(pipe); memset(to,0,sizeof (struct pipe_serial_struct)); to->net = net; if(!(to->chunks = util_chunks_new(buffer))) { free(to); return pipe_free(pipe); } // set up pipe pipe->id = strdup(name); xht_set(net->pipes,pipe->id,pipe); pipe->send = serial_send; }else{ if(!(to = (pipe_serial_t)pipe->arg)) return NULL; } // these can be modified to->read = read; to->write = write; return pipe; }
// load in the key to existing link link_t link_load(link_t link, uint8_t csid, lob_t key) { char hex[3]; lob_t copy; if(!link || !csid || !key) return LOG("bad args"); if(link->x) return link; LOG("adding %x key to link %s",csid,link->id->hashname); // key must be bin if(key->body_len) { copy = lob_copy(key); }else{ util_hex(&csid,1,hex); copy = lob_get_base32(key,hex); } link->x = e3x_exchange_new(link->mesh->self, csid, copy); if(!link->x) { lob_free(copy); return LOG("invalid %x key %d %s",csid,key->body_len,lob_json(key)); } link->csid = csid; link->key = copy; // route packets to this token util_hex(e3x_exchange_token(link->x),16,link->token); xht_set(link->mesh->index,link->token,link); e3x_exchange_out(link->x, util_sys_seconds()); LOG("new session token %s to %s",link->token,link->id->hashname); return link; }
int main(int argc, char *argv[]) { mdnsd d; mdnsdr r; struct message m; unsigned long int ip; unsigned short int port; struct timeval *tv; int bsize, ssize = sizeof(struct sockaddr_in); unsigned char buf[MAX_PACKET_LEN]; struct sockaddr_in from, to; fd_set fds; int s; unsigned char *packet, hlocal[256], nlocal[256]; int len = 0; xht h; if(argc < 4) { printf("usage: mhttp 'unique name' 12.34.56.78 80 '/optionalpath'\n"); return; } ip = inet_addr(argv[2]); port = atoi(argv[3]); printf("Announcing .local site named '%s' to %s:%d and extra path '%s'\n",argv[1],inet_ntoa(ip),port,argv[4]); signal(SIGINT,done); signal(SIGHUP,done); signal(SIGQUIT,done); signal(SIGTERM,done); pipe(_zzz); _d = d = mdnsd_new(1,1000); if((s = msock()) == 0) { printf("can't create socket: %s\n",strerror(errno)); return 1; } sprintf(hlocal,"%s._http._tcp.local.",argv[1]); sprintf(nlocal,"http-%s.local.",argv[1]); r = mdnsd_shared(d,"_http._tcp.local.",QTYPE_PTR,120); mdnsd_set_host(d,r,hlocal); r = mdnsd_unique(d,hlocal,QTYPE_SRV,600,con,0); mdnsd_set_srv(d,r,0,0,port,nlocal); r = mdnsd_unique(d,nlocal,QTYPE_A,600,con,0); mdnsd_set_raw(d,r,(unsigned char *)&ip,4); r = mdnsd_unique(d,hlocal,16,600,con,0); h = xht_new(11); if(argc == 5 && argv[4] && strlen(argv[4]) > 0) xht_set(h,"path",argv[4]); packet = sd2txt(h, &len); xht_free(h); mdnsd_set_raw(d,r,packet,len); free(packet); while(1) { tv = mdnsd_sleep(d); FD_ZERO(&fds); FD_SET(_zzz[0],&fds); FD_SET(s,&fds); select(s+1,&fds,0,0,tv); // only used when we wake-up from a signal, shutting down if(FD_ISSET(_zzz[0],&fds)) read(_zzz[0],buf,MAX_PACKET_LEN); if(FD_ISSET(s,&fds)) { while((bsize = recvfrom(s,buf,MAX_PACKET_LEN,0,(struct sockaddr*)&from,&ssize)) > 0) { bzero(&m,sizeof(struct message)); message_parse(&m,buf); mdnsd_in(d,&m,(unsigned long int)from.sin_addr.s_addr,from.sin_port); } if(bsize < 0 && errno != EAGAIN) { printf("can't read from socket %d: %s\n",errno,strerror(errno)); return 1; } } while(mdnsd_out(d,&m,&ip,&port)) { bzero(&to, sizeof(to)); to.sin_family = AF_INET; to.sin_port = port; to.sin_addr.s_addr = ip; if(sendto(s,message_packet(&m),message_packet_len(&m),0,(struct sockaddr *)&to,sizeof(struct sockaddr_in)) != message_packet_len(&m)) { printf("can't write to socket: %s\n",strerror(errno)); return 1; } } if(_shutdown) break; } mdnsd_shutdown(d); mdnsd_free(d); return 0; }
void thtp_path(switch_t s, char *path, lob_t note) { thtp_t t = thtp_get(s); lob_set_str(note,"path",path); xht_set(t->index,lob_get_str(note,"path"),(void*)note); }