static void report_error_cb(void *user_context, bool retry, void *user_data) { struct connman_peer *peer = user_context; if (retry) { int err; err = peer_connect(peer); if (err == 0 || err == -EINPROGRESS) return; } reply_pending(peer, ENOTCONN); peer_disconnect(peer); if (!peer->connection_master) { __connman_dhcp_stop(peer->ipconfig); __connman_ipconfig_disable(peer->ipconfig); } else stop_dhcp_server(peer); peer->connection_master = false; peer->sub_device = NULL; }
/** * Initiator - Send Connection Request. * Tries to connect to the remote peer's socket. If the connection is refused, the new * state is I_Rcv_Conn_NAck, else I_Rcv_Conn_Ack. * \note Must be called with a lock on the peer. * @param p - peer to send to * @returns the new state for the peer */ peer_state_t I_Snd_Conn_Req(peer *p) { LM_INFO("I_Snd_Conn_Req(): Peer %.*s \n", p->fqdn.len,p->fqdn.s); if (p->I_sock>0) close(p->I_sock); p->I_sock = -1; p->I_sock = peer_connect(p); if (p->I_sock<0){ return I_Rcv_Conn_NAck; } return I_Rcv_Conn_Ack; }
static DBusMessage *connect_peer(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct connman_peer *peer = user_data; GList *list, *start; int err; DBG("peer %p", peer); if (peer->pending) return __connman_error_in_progress(msg); list = g_hash_table_get_values(peers_table); start = list; for (; list; list = list->next) { struct connman_peer *temp = list->data; if (temp == peer || temp->device != peer->device) continue; if (is_connecting(temp) || is_connected(temp)) { if (peer_disconnect(temp) == -EINPROGRESS) { g_list_free(start); return __connman_error_in_progress(msg); } } } g_list_free(start); peer->pending = dbus_message_ref(msg); err = peer_connect(peer); if (err == -EINPROGRESS) return NULL; if (err < 0) { dbus_message_unref(peer->pending); peer->pending = NULL; return __connman_error_failed(msg, -err); } return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); }
END_TEST START_TEST(test_peer_connect) { char host[100] = "127.0.0.1"; char port[6] = TEST_PORT; char hostport[107]; sprintf(hostport, "%s:%s", host, port); peer * p = peer_create("local", hostport); /* creating server for test */ int server_sock = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP); struct addrinfo * ainfo, hint; memset(&hint, 0, sizeof(struct addrinfo)); hint.ai_family = AF_UNSPEC; hint.ai_socktype = SOCK_STREAM; hint.ai_flags = AI_PASSIVE; /* for NULLed host */ hint.ai_protocol = IPPROTO_TCP; hint.ai_canonname = NULL; hint.ai_addr = NULL; hint.ai_next = NULL; ck_assert_int_eq(getaddrinfo(host, port, &hint, &ainfo), 0); ck_assert_int_eq(bind(server_sock, ainfo->ai_addr, ainfo->ai_addrlen), 0); ck_assert_int_eq(listen(server_sock, 10), 0); ck_assert_int_eq(peer_connect(p), 0); int client_sock = accept(server_sock, NULL, NULL); char * msg = "testmsg"; send(p->sock, msg, 8, MSG_DONTWAIT); char buf[25]; recv(client_sock, buf, 8, MSG_DONTWAIT); ck_assert_str_eq(buf, "testmsg"); close(p->sock); close(client_sock); close(server_sock); }
/* Return 0 for a request that is pending or if all slots are full, otherwise return the value of peer_sendreq or peer_connect respectively... */ static void request_add(struct request_t *r) { uint pos = r->id % MAX_REQUESTS; // XXX r->id is unchecked struct peer_t *dst_peer; unsigned short int *ul; time_t ct = time(NULL); struct request_t *req_in_table = 0; for (;;) { if (requests[pos].id == 0) { // this one is unused, take it req_in_table = &requests[pos]; break; } else { if (requests[pos].id == r->id) { if (memcmp((char*)&r->a, (char*)&requests[pos].a, sizeof(r->a)) == 0) { // a request for the same id and url already exists // do not process the new request return; } else { // ids are same but the queried urls are different. // this is weird. we rather drop the package before // we do some black magic that blows up on us. // one failed ns request is not that bad. // clients usually repeat them anyways. /* do { r->id = ((rand()>>16) % 0xffff); } while (r->id < 1); pos = r->id % MAX_REQUESTS; //printf("NATing id (id was %d now is %d)\n", r->rid, r->id); continue; */ log_packet(r->id, DROP_IN, UDP, REQ_IP(r), REQ_PORT(r)); return; } } else if ((requests[pos].timeout + MAX_TIME) > ct) { // request timed out, take it req_in_table = &requests[pos]; break; } else { pos++; pos %= MAX_REQUESTS; if (pos == (r->id % MAX_REQUESTS)) { // we are at our capacities. drop the request log_packet(r->id, DROP_IN, UDP, REQ_IP(r), REQ_PORT(r)); return; } } } } r->timeout = time(NULL); /* REFACTOR not ct? sloppy */ // update id ul = (unsigned short int*)(r->b + 2); *ul = htons(r->id); if ( req_in_table == NULL ) { return; } else { memcpy((char*)req_in_table, (char*)r, sizeof(*req_in_table)); } dst_peer = peer_select(); if (dst_peer->con == CONNECTED) { peer_sendreq(dst_peer, req_in_table); } else if (dst_peer->con != CONNECTING) { // The request will be sent by peer_handleoutstanding when the // connection is established. Actually (see QUASIBUG notice // earlier) when *any* connection is established. peer_connect(dst_peer, ns_select()); } }
int main(int argc, char *argv[]) { char c; fd_set rset; int i, err, sd, maxsd; struct hostent *phost; // the FQDN of this host struct sockaddr_in self; // the address of this host int npeers; pte_t pte[PR_MAXPEERS], redirected; // a 2-entry peer table char pnamebuf[PR_MAXPEERS*(PR_MAXFQDN+1)] = { 0 }; // space to hold 2 FQDNs char *pname[PR_MAXPEERS]; // pointers to above spaces pmsg_t msg; // init npeers=0; memset((char *) &self, 0, sizeof(struct sockaddr_in)); for (i=0; i < PR_MAXPEERS; i++) { pname[i] = &pnamebuf[i*(PR_MAXFQDN+1)]; pte[i].pte_sd = PR_UNINIT_SD; } // parse args, see the comments for peer_args() if (peer_args(argc, argv, pname[0], &pte[0].pte_peer.peer_port)) { peer_usage(argv[0]); } #ifdef _WIN32 WSADATA wsa; err = WSAStartup(MAKEWORD(2,2), &wsa); // winsock 2.2 net_assert(err, "peer: WSAStartup"); #endif #ifndef _WIN32 signal(SIGPIPE, SIG_IGN); /* don't die if peer is dead */ #endif /* if pname is provided, connect to peer */ if (*pname[0]) { pte[0].pte_pname = pname[0]; /* Task 2: YOUR CODE HERE * * Given the peer whose FQDN is stored in pname[0], * get peer's address and stores it in the first entry * of the peer table (pte[0]). */ struct hostent *sp; sp = gethostbyname(pname[0]); memcpy(&pte[0].pte_peer.peer_addr, sp->h_addr, sp->h_length); /* connect to peer in pte[0] */ peer_connect(pte); // Task 2: fill in the peer_connect() function above /* Task 2: YOUR CODE HERE * * Upon return from peer_connect(), the socket descriptor in * pte[0] should have been initialized and connected to the peer. * Obtain the ephemeral port assigned by the OS kernel to this * socket and store it in the variable "self" (along with the * peer's address). */ socklen_t len = sizeof(self); if(getsockname(pte[0].pte_sd, (struct sockaddr *)&self, &len) < 0) abort(); npeers++; /* inform user of connection to peer */ fprintf(stderr, "Connected to peer %s:%d\n", pname[0], ntohs(pte[0].pte_peer.peer_port)); } /* setup and listen on connection */ sd = peer_setup(self.sin_port); // Task 1: fill in the peer_setup() function above if (!self.sin_port) { /* Task 1: YOUR CODE HERE If a peer was not provided in the command line using "-p", the port number will be 0 and the socket sd would have been assigned an ephemeral port when calling bind() in peer_setup(). Obtain the ephemeral port and store it in the variable "self" (along with peer's address) by copying the same chunk of code you just wrote at the end of the if statement block above. */ socklen_t len = sizeof(self); if (getsockname(sd, (struct sockaddr *) &self, &len) < 0) abort(); } /* Task 1: YOUR CODE HERE Find out the FQDN of the current host (use pname[1] as scratch space to put the name). Use gethostname(), it is sufficient most of the time. */ gethostname (pname[1], PR_MAXFQDN+1); /* inform user which port this peer is listening on */ fprintf(stderr, "This peer address is %s:%d\n", pname[1], ntohs(self.sin_port)); do { /* determine the largest socket descriptor */ maxsd = (sd > pte[0].pte_sd ? sd : pte[0].pte_sd); if (maxsd < pte[1].pte_sd) { maxsd = pte[1].pte_sd; } /* set all the descriptors to select() on */ FD_ZERO(&rset); #ifndef _WIN32 FD_SET(STDIN_FILENO, &rset); // wait for input from std input, // Winsock only works with socket and stdin is not a socket #endif FD_SET(sd, &rset); // or the listening socket, for (i = 0; i < PR_MAXPEERS; i++) { if (pte[i].pte_sd > 0) { FD_SET(pte[i].pte_sd, &rset); // or the peer connected sockets } } /* Task 1: YOUR CODE HERE Call select() to wait for any activity on any of the above descriptors. */ select(maxsd+1, &rset, NULL, NULL, NULL); #ifndef _WIN32 if (FD_ISSET(STDIN_FILENO, &rset)) { // user input: if getchar() returns EOF or if user hits q, quit, // else flush input and go back to waiting if (((c = getchar()) == EOF) || (c == 'q') || (c == 'Q')) { fprintf(stderr, "Bye!\n"); break; } fflush(stdin); } #endif if (FD_ISSET(sd, &rset)) { // a connection is made to this host at the listened to socket if (npeers < PR_MAXPEERS) { /* Peer table is not full. Accept the peer, send a welcome * message. if we are connected to another peer, also sends * back the peer's address+port# */ // Task 1: fill in the functions peer_accept() and peer_ack() above peer_accept(sd, &pte[npeers]); err = peer_ack(pte[npeers].pte_sd, PM_WELCOME, (npeers > 0 ? &pte[0].pte_peer : 0)); err = (err != sizeof(pmsg_t)); net_assert(err, "peer: peer_ack welcome"); pte[npeers].pte_pname = pname[npeers]; /* log connection */ /* get the host entry info on the connected host. */ phost = gethostbyaddr((char *) &pte[npeers].pte_peer.peer_addr, sizeof(struct in_addr), AF_INET); strcpy(pname[npeers], ((phost && phost->h_name) ? phost->h_name: inet_ntoa(pte[npeers].pte_peer.peer_addr))); /* inform user of new peer */ fprintf(stderr, "Connected from peer %s:%d\n", pname[npeers], ntohs(pte[npeers].pte_peer.peer_port)); npeers++; } else { // Peer table full. Accept peer, send a redirect message. // Task 1: the functions peer_accept() and peer_ack() you wrote // must work without error in this case also. peer_accept(sd, &redirected); err = peer_ack(redirected.pte_sd, PM_RDIRECT, (npeers > 0 ? &pte[0].pte_peer : 0)); err = (err != sizeof(pmsg_t)); net_assert(err, "peer: peer_ack redirect"); /* log connection */ /* get the host entry info on the connected host. */ phost = gethostbyaddr((char *) &redirected.pte_peer.peer_addr, sizeof(struct in_addr), AF_INET); /* inform user of peer redirected */ fprintf(stderr, "Peer table full: %s:%d redirected\n", ((phost && phost->h_name) ? phost->h_name: inet_ntoa(redirected.pte_peer.peer_addr)), ntohs(redirected.pte_peer.peer_port)); /* closes connection */ close(redirected.pte_sd); } } for (i = 0; i < PR_MAXPEERS; i++) { if (pte[i].pte_sd > 0 && FD_ISSET(pte[i].pte_sd, &rset)) { // a message arrived from a connected peer, receive it err = peer_recv(pte[i].pte_sd, &msg); // Task 2: fill in the functions peer_recv() above net_assert((err < 0), "peer: peer_recv"); if (err == 0) { // if connection closed by peer, reset peer table entry pte[i].pte_sd = PR_UNINIT_SD; } else { // if connection closed by peer, reset peer table entry fprintf(stderr, "Received ack from %s:%d\n", pte[i].pte_pname, ntohs(pte[i].pte_peer.peer_port)); if (msg.pm_vers != PM_VERS) { fprintf(stderr, "unknown message version.\n"); } else { if (msg.pm_npeers) { // if message contains a peer address, inform user of // the peer two hops away phost = gethostbyaddr((char *) &msg.pm_peer.peer_addr, sizeof(struct in_addr), AF_INET); fprintf(stderr, " which is peered with: %s:%d\n", ((phost && phost->h_name) ? phost->h_name : inet_ntoa(msg.pm_peer.peer_addr)), ntohs(msg.pm_peer.peer_port)); } if (msg.pm_type == PM_RDIRECT) { // inform user if message is a redirection fprintf(stderr, "Join redirected, try to connect to the peer above.\n"); } } } } } } while (1); #ifdef _WIN32 WSACleanup(); #endif exit(0); }