/* If an entry already exists for an href, then return the entry. Else, return NULL. */ static entry *fetch_entry (char *href) { int hash = hash_url (href); entry *l; if (hash_table[hash].count) for (l = hash_table[hash].head; l != NULL; l = l->next) { if (!strcmp (l->href, href)) return l; } return NULL; }
/* We're making a new annotation to a url. Pass in the title, author, and text of the annotation. */ mo_status mo_new_pan (char *url, char *title, char *author, char *text) { entry *l = fetch_entry (url); int id = ++max_pan_id; if (!title || !*title) title = strdup ("Annotation with no title"); if (!author || !*author) author = strdup ("No author name"); /* Create a new entry if we have to. */ if (!l) l = new_entry (hash_url (url), url); /* Register the new annotation id with the entry. */ add_an_to_entry (l, id); mo_write_pan (id, title, author, text); return mo_succeed; }
static void mo_read_pan_file (char *filename) { FILE *fp; char line[MO_LINE_LENGTH]; char *status; entry *l; fp = fopen (filename, "r"); if (!fp) goto screwed_no_file; status = fgets (line, MO_LINE_LENGTH, fp); if (!status || !(*line)) goto screwed_with_file; /* See if it's our format. */ if (strncmp (line, NCSA_PAN_LOG_FORMAT_COOKIE_ONE, strlen (NCSA_PAN_LOG_FORMAT_COOKIE_ONE))) goto screwed_with_file; /* Go fetch the name on the next line. */ status = fgets (line, MO_LINE_LENGTH, fp); if (!status || !(*line)) goto screwed_with_file; /* Start grabbing documents and lists of annotations. */ while (1) { char *url; char *p; status = fgets (line, MO_LINE_LENGTH, fp); if (!status || !(*line)) goto done; url = strtok (line, " "); if (!url) goto screwed_with_file; url = strdup (url); /* We don't use the last-accessed date... yet. */ /* lastdate = strtok (NULL, "\n"); blah blah blah... */ l = new_entry (hash_url (url), url); free (url); while (p = strtok (NULL, " ")) { int a = atoi (p); if (a) { add_an_to_entry (l, a); if (a > max_pan_id) max_pan_id = a; } } } done: fclose (fp); return; screwed_with_file: fclose (fp); return; screwed_no_file: return; }
static void test_UrlHash(void) { hash_url(TEST_URL_1); hash_url(TEST_URL_2); hash_url(TEST_URL_3); }
int main(int argc, char *argv[]) { if (argc < 3) { // Checking for correct arquments printf("Useage: dhtnode own_hostname own_port\n"); exit(0); } char* my_url = argv[1]; char* my_port = argv[2]; sha1_t my_hash; // Create hash for own address hash_url(my_url, my_port, my_hash); fd_set master; fd_set rfds; int retval; int running = 1; int listensock = create_listen_socket(my_port); con_t server; memset(&server,0,sizeof server); con_t left; memset(&left,0,sizeof left); con_t right; memset(&right,0,sizeof right); FD_SET(STDIN_FILENO, &master); FD_SET(listensock, &master); int fdmax = listensock; struct timeval looptime; while (running) { looptime.tv_sec = 1; looptime.tv_usec = 0; rfds = master; retval = select(fdmax + 1, &rfds, NULL, NULL, &looptime); if (retval == -1) die("select failed"); else if (retval) { if (FD_ISSET(STDIN_FILENO, &rfds)) { int argcount; char** arguments = NULL; int cmd = getcommand(STDIN_FILENO, &argcount, &arguments); printf("got command\n"); if (cmd < 0) { //TODO handle different errors differently printf("error: %d\n", cmd); exit(-1); } switch (cmd) { case USER_EXIT: if(server.state != ST_EMPTY && (argcount == 0 || strcmp(arguments[0],"force"))){//remember strcmp returns 0 on match printf("trying to exit\n"); send_dht_pckt(server.socket,DHT_DEREGISTER_BEGIN,my_hash,my_hash,0,NULL); } else{ printf("exiting\n"); running = 0; } freeargs(argcount, arguments); break; case USER_CONNECT: if(argcount != 2){ printf("usage: connect url port\n"); freeargs(argcount,arguments); break; } if(server.state != ST_EMPTY){ printf("Already connected to the server. Use exit to disconnect.\n"); freeargs(argcount,arguments); break; } printf("connecting to %s:%s\n", arguments[0], arguments[1]); int sock = create_connection(arguments[0], arguments[1]); printf("connection made\n"); FD_SET(sock, &master); if(sock > fdmax) fdmax = sock; server.socket = sock; server.state = ST_WF_SER_SHAKE; freeargs(argcount, arguments); break; case USER_PRINT: printf("printing...\n"); for(int i = 0; i < argcount; i++){ printf("%s:\n",arguments[i]); if(!strcmp(arguments[i],"sockets")){ printf("server, %d %s\n",server.socket,(server.socket != 0 && FD_ISSET(server.socket,&master))? "is set":"not set"); printf("right, %d %s\n",right.socket,(right.socket != 0 && FD_ISSET(right.socket,&master))? "is set":"not set"); printf("left, %d %s\n",left.socket,(left.socket != 0 && FD_ISSET(left.socket,&master))? "is set":"not set"); } else if(!strcmp(arguments[i],"states")){ printf("server, %d\n",server.state); printf("right, %d\n",right.state); printf("left, %d\n",left.state); } } freeargs(argcount,arguments); break; case USER_UNKNW_CMD: printf("unknown command, line was:"); for (int i = 0; i < argcount; i++) { printf(" %s", arguments[i]); } printf("\n"); freeargs(argcount, arguments); break; } } //check for new connections if (FD_ISSET(listensock, &rfds)) { printf("someone is connecting\n"); if(right.state == ST_EMPTY){ right.socket = accept_connection(listensock); if(right.socket < 0){ die(strerror(errno)); } FD_SET(right.socket, &master); if(right.socket > fdmax) fdmax = right.socket; right.state = ST_WF_CLI_SHAKE; } else if (left.state == ST_EMPTY) { left.socket = accept_connection(listensock); if(left.socket < 0){ die(strerror(errno)); } FD_SET(left.socket, &master); if(left.socket > fdmax) fdmax = left.socket; left.state = ST_WF_CLI_SHAKE; } } //check for msg from server if(server.state != ST_EMPTY && FD_ISSET(server.socket, &rfds)){ int status; if(server.state == ST_WF_SER_SHAKE){ printf("getting shake\n"); status = recvdata(server.socket, NULL); if(status == NTW_SERVER_SHAKE){ printf("shaking back\n"); send_shake(server.socket, NTW_CLIENT_SHAKE); unsigned char formated_url[strlen(my_url)+3]; format_url(my_url, my_port, formated_url); printf("sending DHT_REGISTER_BEGIN\n"); send_dht_pckt(server.socket,DHT_REGISTER_BEGIN,my_hash,my_hash,strlen(my_url)+3,formated_url); server.state = ST_ONLINE; } //TODO error handling /*On correct shake shake back and send DHT_REGISTER_BEGIN with our sha1 as sender and target and our port+url as payload switch state to ST_ONLINE*/ } else{ DHT_t packet; memset(&packet, 0, sizeof packet); status = recvdata(server.socket, &packet); if(status != NTW_PACKET_OK){ switch(status){ case NTW_ERR_SERIOUS: die(strerror(errno)); break; case NTW_DISCONNECT: die("server disconnected"); break; default: printf("getting packet failed somehow\n"); memset(&packet, 0, sizeof packet); break; } } printf("received from server:\n"); print_dht_packet(&packet); //TODO error handling uint16_t reqt = ntohs(packet.req_type); if(server.state == ST_ONLINE && reqt == DHT_REGISTER_FAKE_ACK){ printf("fake ack received\n"); /*send DHT_REGISTER_DONE to server target and sender are both our hash state to ST_IDLING*/ int a = send_dht_pckt(server.socket, DHT_REGISTER_DONE, my_hash, my_hash, 0, NULL); if(a == 0) server.state = ST_IDLING; else exit(1); // or error handling } else if(server.state == ST_IDLING && reqt == DHT_REGISTER_BEGIN){ printf("dht_register_begin received\n"); /*open connection to the new node which port+url is in packet and send data + DHT_REGISTER_ACK our hash sender and target state to ST_WF_REG_DONE*/ char his_url[packet.pl_length-2]; strcpy(his_url,(char*)packet.payload+2); uint16_t* port = (uint16_t*)packet.payload; *port = ntohs(*port); char his_port[10]; sprintf(his_port,"%u",*port); int sock = create_connection(his_url,his_port); FD_SET(sock, &master); if(sock > fdmax) fdmax = sock; con_t* pal; pal = (right.state == ST_EMPTY) ? &right : &left; memcpy(pal->hash,packet.sender,20); pal->socket = sock; pal->state = ST_WF_SER_SHAKE; //server.state = ST_WF_REG_DONE; } else if(server.state == ST_IDLING && reqt == DHT_REGISTER_DONE){ printf("received reg done\n"); //server.state = ST_IDLING; /*dump old data and return to ST_IDLING*/ } else if(server.state == ST_IDLING && reqt == DHT_DEREGISTER_ACK){ printf("dereg ack received\n"); /*open connection to neighbours their urls are as payload of the package and send data and DHT_DEREGISTER_BEGIN (our hash as sender and target) change to ST_WF_DEREG_DONE*/ uint16_t port_buf = ((uint16_t*)packet.payload)[0]; port_buf = ntohs(port_buf); char port1[10]; sprintf(port1,"%u",port_buf); char url1[30]; strcpy(url1,(char*)(packet.payload+2)); port_buf = ((uint16_t*)(packet.payload+3+strlen(url1)))[0]; port_buf = ntohs(port_buf); char port2[10]; sprintf(port2,"%u",port_buf); char url2[30]; strcpy(url2,(char*)(packet.payload+5+strlen(url1))); printf("parsing got:\nurl1 = %s:%s\nurl2 = %s:%s\n", url1, port1, url2, port2); //connect to right neighbour right.socket = create_connection(url1,port1); FD_SET(right.socket, &master); if(right.socket > fdmax) fdmax = right.socket; hash_url(url1,port1,right.hash); right.state = ST_WF_SER_SHAKE; //connect to left neighbour left.socket = create_connection(url2,port2); FD_SET(left.socket, &master); if(left.socket > fdmax) fdmax = left.socket; hash_url(url2,port2,left.hash); left.state = ST_WF_SER_SHAKE; server.state = ST_WF_DEREG_DONE; } else if(server.state == ST_IDLING && reqt == DHT_DEREGISTER_DENY){ printf("dereg deny received\n"); /*tell user that leaving is impossible return to ST_IDLING*/ printf("Unable to exit. You are the last node. To over-ride this use exit force command.\n"); server.state = ST_IDLING; } else if(server.state == ST_WF_DEREG_DONE && reqt == DHT_DEREGISTER_DONE){ if(right.state == ST_DEREG_DATA_SENT && !memcmp(right.hash, packet.sender, 20)){ FD_CLR(right.socket, &master); close(right.socket); memset(&right,0,sizeof right); } else if(left.state == ST_DEREG_DATA_SENT && !memcmp(left.hash, packet.sender, 20)){ FD_CLR(left.socket, &master); close(left.socket); memset(&left,0,sizeof left); } if(left.state == ST_EMPTY && right.state == ST_EMPTY){ printf("leaving the network\n"); close(server.socket); FD_CLR(server.socket, &master); memset(&server,0,sizeof server); printf("left the network\n"); } /*close the connection to server state to ST_EMPTY*/ } } } } for(int i = 0; i<2;i++){ con_t* neighbour = (i == 0) ? &right : &left; //check for msg from right and left neighbour if(neighbour->state != ST_EMPTY && FD_ISSET(neighbour->socket, &rfds)){ int status; if(neighbour->state == ST_WF_CLI_SHAKE){ /* prepare to receive data switch state to ST_RCV_DATA_REG or ST_RCV_DATA_DEREG depending on server state*/ status = recvdata(neighbour->socket, NULL); if(status == NTW_CLIENT_SHAKE){ if(server.state == ST_ONLINE){ neighbour->state = ST_RCV_DATA_REG; } if(server.state == ST_IDLING){ neighbour->state = ST_RCV_DATA_DEREG; } } else { switch(status){ case NTW_ERR_SERIOUS: die(strerror(errno)); break; case NTW_DISCONNECT: printf("%s disconnected\n",(i)?"left":"right"); FD_CLR(neighbour->socket,&master); memset(neighbour,0,sizeof *neighbour); break; default: printf("getting shake failed somehow\n"); break; } } } else if (neighbour->state == ST_WF_SER_SHAKE){ /* answer with client shake and pump your data to the neighbour after that send DHT_REGISTER_ACK or DHT_DEREG_BEGIN either way after this the connection to neighbour can be disconnected*/ status = recvdata(neighbour->socket, NULL); if(status == NTW_SERVER_SHAKE){ printf("shaking back\n"); send_shake(neighbour->socket, NTW_CLIENT_SHAKE); if(server.state == ST_IDLING){ //we should end with DHT_REGISTER_ACK send_dht_pckt(neighbour->socket,DHT_REGISTER_ACK,my_hash,my_hash,0,NULL); FD_CLR(neighbour->socket, &master); close(neighbour->socket); memset(neighbour,0,sizeof *neighbour); } if(server.state == ST_WF_DEREG_DONE){ //we should end with DHT_DEREGISTER_BEGIN send_dht_pckt(neighbour->socket,DHT_DEREGISTER_BEGIN,my_hash,my_hash,0,NULL); FD_CLR(neighbour->socket, &master); close(neighbour->socket); neighbour->state = ST_DEREG_DATA_SENT; } } else { switch(status){ case NTW_ERR_SERIOUS: die(strerror(errno)); break; case NTW_DISCONNECT: die("neighbour disconnected"); break; default: printf("getting shake failed somehow\n"); break; } } } else{ DHT_t packet; memset(&packet, 0, sizeof packet); status = recvdata(neighbour->socket, &packet); printf("received package from %s:\n",(i)?"left":"right"); print_dht_packet(&packet); if(status != NTW_PACKET_OK){ switch(status){ case NTW_ERR_SERIOUS: die(strerror(errno)); break; case NTW_DISCONNECT: printf("%s neighbour disconnected.\n",(i)?"left":"right"); FD_CLR(neighbour->socket,&master); close(neighbour->socket); memset(neighbour,0,sizeof * neighbour); break; case NTW_ERR_TIMEOUT: printf("package from %s timed out!\n",(i)?"left":"right"); memset(&packet,0,sizeof packet); break; } } uint16_t reqt = ntohs(packet.req_type); if(neighbour->state == ST_RCV_DATA_REG && reqt == DHT_REGISTER_ACK){ /*all data is now received */ FD_CLR(neighbour->socket, &master); close(neighbour->socket); memset(neighbour,0,sizeof *neighbour); neighbour->state = ST_REG_DATA_RCVD; if(right.state == ST_REG_DATA_RCVD && left.state == ST_REG_DATA_RCVD){ send_dht_pckt(server.socket, DHT_REGISTER_DONE, my_hash, my_hash, 0, NULL); right.state = ST_EMPTY; left.state = ST_EMPTY; server.state = ST_IDLING; } } else if(neighbour->state == ST_RCV_DATA_DEREG && reqt == DHT_DEREGISTER_BEGIN){ send_dht_pckt(server.socket, DHT_DEREGISTER_DONE, packet.sender, my_hash, 0, NULL); FD_CLR(neighbour->socket, &master); close(neighbour->socket); memset(neighbour,0,sizeof *neighbour); } } } } } close(listensock); return 0; }