static void nc_conn_write_evt(int fd, short events, void *priv) { struct nc_conn *conn = priv; struct iovec *iov = NULL; unsigned int iov_len = 0; /* build list of outgoing data buffers */ nc_conn_build_iov(conn->write_q, conn->write_partial, &iov, &iov_len); /* send data to network */ ssize_t wrc = writev(conn->fd, iov, iov_len); free(iov); if (wrc < 0) { if (errno != EAGAIN && errno != EWOULDBLOCK) goto err_out; return; } /* handle partially and fully completed buffers */ nc_conn_written(conn, wrc); /* thaw read, if write fully drained */ if (!conn->write_q) { nc_conn_write_disable(conn); nc_conn_read_enable(conn); } return; err_out: nc_conn_kill(conn); }
/* connection begins */ static void nc_conn_evt_connected(int fd, short events, void *priv) { struct nc_conn *conn = priv; if ((events & EV_WRITE) == 0) { fprintf(plog, "net: %s connection timeout\n", conn->addr_str); goto err_out; } int err = 0; socklen_t len = sizeof(err); /* check success of connect(2) */ if ((getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &err, &len) < 0) || (err != 0)) { fprintf(plog, "net: connect %s failed: %s\n", conn->addr_str, strerror(err)); goto err_out; } if (debugging) fprintf(plog, "net: connected to %s\n", conn->addr_str); conn->connected = true; /* clear event used for watching connect(2) */ event_free(conn->ev); conn->ev = NULL; /* build and send "version" message */ cstring *msg_data = nc_version_build(conn); bool rc = nc_conn_send(conn, "version", msg_data->str, msg_data->len); cstr_free(msg_data, true); if (!rc) { fprintf(plog, "net: %s !conn_send\n", conn->addr_str); goto err_out; } /* switch to read-header state */ conn->msg_p = conn->hdrbuf; /* from message.c #define P2P_HDR_SZ (4 + 12 + 4 + 4)*/ conn->expected = P2P_HDR_SZ; conn->reading_hdr = true; if (!nc_conn_read_enable(conn)) { fprintf(plog, "net: %s read not enabled\n", conn->addr_str); goto err_out; } return; err_out: nc_conn_kill(conn); }
static void nc_conn_read_evt(int fd, short events, void *priv) { struct nc_conn *conn = priv; ssize_t rrc = read(fd, conn->msg_p, conn->expected); if (rrc <= 0) { if (rrc < 0) fprintf(plog, "llnet: %s read: %s\n", conn->addr_str, strerror(errno)); else fprintf(plog, "llnet: %s read EOF\n", conn->addr_str); goto err_out; } conn->msg_p += rrc; conn->expected -= rrc; /* execute our state machine at most twice */ unsigned int i; for (i = 0; i < 2; i++) { if (conn->expected == 0) { if (conn->reading_hdr) { if (!nc_conn_got_header(conn)) goto err_out; } else { if (!nc_conn_got_msg(conn)) goto err_out; } } } return; err_out: nc_conn_kill(conn); }
static void nc_conns_open(struct net_child_info *nci) { log_debug("net: open connections (have %zu, want %zu more)", nci->conns->len, NC_MAX_CONN - nci->conns->len); while ((bp_hashtab_size(nci->peers->map_addr) > 0) && (nci->conns->len < NC_MAX_CONN)) { /* delete peer from front of address list. it will be * re-added before writing peer file, if successful */ struct peer *peer = peerman_pop(nci->peers); struct nc_conn *conn = nc_conn_new(peer); conn->nci = nci; peer_free(peer); free(peer); log_debug("net: connecting to %s", conn->addr_str); /* are we already connected to this IP? */ if (nc_conn_ip_active(nci, conn->peer.addr.ip)) { log_info("net: already connected to %s", conn->addr_str); goto err_loop; } /* are we already connected to this network group? */ if (nc_conn_group_active(nci, &conn->peer)) { log_info("net: already grouped to %s", conn->addr_str); goto err_loop; } /* initiate non-blocking connect(2) */ if (!nc_conn_start(conn)) { log_info("net: failed to start connection to %s", conn->addr_str); goto err_loop; } /* add to our list of monitored event sources */ conn->ev = event_new(nci->eb, conn->fd, EV_WRITE, nc_conn_evt_connected, conn); if (!conn->ev) { log_info("net: event_new failed on %s", conn->addr_str); goto err_loop; } struct timeval timeout = { conn->nci->net_conn_timeout, }; if (event_add(conn->ev, &timeout) != 0) { log_info("net: event_add failed on %s", conn->addr_str); goto err_loop; } /* add to our list of active connections */ parr_add(nci->conns, conn); continue; err_loop: nc_conn_kill(conn); } }