/* The user typed in a C<addr>:<port> command to connect to a peer. */ static void connect_command(struct file_info *fi, char *addr_port){ void try_connect(struct file_info *fi); if (fi->type != FI_FILE) { fprintf(stderr, "unexpected connect message\n"); return; } char *p = index(addr_port, ':'); if (p == 0) { fprintf(stderr, "do_connect: format is C<addr>:<port>\n"); return; } *p++ = 0; struct sockaddr_in addr; if (addr_get(&addr, addr_port, atoi(p)) < 0) { return; } *--p = ':'; fi = file_info_add(FI_OUTGOING, -1, 0, 0); fi->u.fi_outgoing.status = FI_CONNECTING; /* Even though we're connecting, you're allowed to connect using any address to * a peer (including a localhost address). So we have to wait for the Hello * message until we're certain who it is on the other side. Until then, we keep * the address we know for debugging purposes. */ fi->addr = addr; try_connect(fi); }
struct sockaddr_in* string_to_addr(char* string) { char *port = index(string, ':'); *port++ = 0; struct sockaddr_in* addr = calloc(1, sizeof(struct sockaddr_in)); addr_get(addr, string, atoi(port)); *--port = ':'; return addr; }
/* Received a H(ello) message of the form H<addr>:<port>. This is the first message * that's sent over a TCP connection (in both directions) so the peers can identify * one another. The port is the server port of the endpoint rather than the * connection's port. * * Sometimes accidentally peers try to connect to one another at the same time. * This code kills one of the connections. */ void hello_received(struct file_info *fi, char *addr_port){ char *p = index(addr_port, ':'); if (p == 0) { fprintf(stderr, "do_hello: format is H<addr>:<port>\n"); return; } *p++ = 0; struct sockaddr_in addr; if (addr_get(&addr, addr_port, atoi(p)) < 0) { return; } *--p = ':'; printf("Got hello from %s:%d on socket %d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), fi->fd); /* If a connection breaks and is re-established, a duplicate hello message is likely * to arrive, but we can ignore it as we already know the peer. */ if (fi->status == FI_KNOWN) { fprintf(stderr, "Duplicate hello (ignoring)\n"); if (addr_cmp(addr, fi->addr) != 0) { fprintf(stderr, "do_hello: address has changed???\n"); } return; } /* It is possible to set up a connection to self. We deal with it by ignoring the * Hello message but keeping the connection established. */ if (addr_cmp(addr, my_addr) == 0) { fprintf(stderr, "Got hello from self??? (ignoring)\n"); return; } /* Search the connections to see if there is already a connection to this peer. */ struct file_info *fi2; for (fi2 = file_info; fi2 != 0; fi2 = fi2->next) { if (fi2->type == FI_FREE || fi2->status != FI_KNOWN) { continue; } if (addr_cmp(fi2->addr, addr) != 0) { continue; } /* Found another connection. We're going to keep just one. First see if * this is actually an existing connection. It may have broken. */ if (fi2->fd == -1) { printf("Found a defunct connection---dropping that one\n"); if (fi2->type == FI_OUTGOING) { fi->type = FI_OUTGOING; fi->u.fi_outgoing = fi2->u.fi_outgoing; } fi2->type = FI_FREE; return; } /* Of the two, we keep the "lowest one". We identify a connection by the lowest * endpoint address. */ struct sockaddr_in mine, other; get_id(fi->fd, &mine); get_id(fi2->fd, &other); if (addr_cmp(mine, other) < 0) { /* We keep mine. */ printf("duplicate connection -- keep mine\n"); if (fi2->type == FI_OUTGOING) { fi->type = FI_OUTGOING; fi->u.fi_outgoing = fi2->u.fi_outgoing; } close(fi2->fd); fi2->type = FI_FREE; } else { printf("duplicate connection -- keep other\n"); /* The other one wins. */ if (fi->type == FI_OUTGOING) { fi2->type = FI_OUTGOING; fi2->u.fi_outgoing = fi->u.fi_outgoing; } close(fi->fd); fi->type = FI_FREE; return; } } /* No other connection. Keep this one. */ printf("New Connection\n"); fi->addr = addr; fi->status = FI_KNOWN; if(!nl) { nl = (struct node_list *) nl_create(); char *my_addr_str = addr_to_string(my_addr); nl_add(nl, my_addr_str); free(my_addr_str); } char *addr_str = addr_to_string(addr); nl_add(nl, addr_str); free(addr_str); updateGraph(); send_gossip(); }