// Connect to the server, and send the first datagram void initiate_tx(void) { sockfd = Socket(AF_INET, SOCK_DGRAM, 0); if (conn->is_local) { set_dontroute(sockfd); } // Bind to port 0 Bind(sockfd, conn->cli_sa, (socklen_t)sizeof(SA)); struct sockaddr_in sin; UINT addrlen = sizeof(SA); // Fetch port number at which kernel bound this socket. Getsockname(sockfd, (SA *)&sin, &addrlen); cliport = ntohs(sin.sin_port); INFO("Client's ephemeral Port Number: %d\n", cliport); // Connect to the server. Connect(sockfd, conn->serv_sa, sizeof(SA)); // TODO // Do we need getpeername here? // Start a timer here to re-send the file name till we receive an // ACK. struct timeval timeout; timeout.tv_sec = 3; timeout.tv_usec = 0; fdset_init(&fds, timeout, ack_timeout); fdset_add(&fds, &fds.rev, sockfd, &sockfd, send_file); fdset_add(&fds, &fds.exev, sockfd, &sockfd, handle_tx_error); // Send the packet to the server INFO("Trying to send the SYN packet to the Server with the file name%s\n", ""); send_filename_pkt(); int r = fdset_poll2(&fds); if (r < 0) { perror("select"); ASSERT(errno != EINTR); exit(1); } }
void server_loop(void) { struct timeval timeout; int r; VERBOSE("server_loop()%s\n", ""); timeout.tv_sec = 10; // FIXME when we know better timeout.tv_usec = 0; fdset_init(&fds, timeout, NULL); fdset_add(&fds, &fds.rev, s.sockfd, &s.sockfd, on_recv); fdset_add(&fds, &fds.exev, s.sockfd, &s.sockfd, on_error); r = fdset_poll(&fds, &timeout, on_recv_timedout); if (r < 0) { perror("select"); ASSERT(errno != EINTR); exit(1); } }
static int tcp_event_accept(tcp_context_t *tcp, unsigned i) { /* Accept client. */ int fd = tcp->set.pfd[i].fd; int client = tcp_accept(fd); if (client >= 0) { /* Assign to fdset. */ int next_id = fdset_add(&tcp->set, client, POLLIN, NULL); if (next_id < 0) { close(client); return next_id; /* Contains errno. */ } /* Update watchdog timer. */ rcu_read_lock(); fdset_set_watchdog(&tcp->set, next_id, conf()->max_conn_hs); rcu_read_unlock(); } return KNOT_EOK; }
void send_file(void *opaque) { int portno; struct sockaddr sa; struct sockaddr_in *si = (struct sockaddr_in *) &sa; socklen_t sa_sz = sizeof(sa); packet_t pkt; int r; r = perhaps_recvfrom(sockfd, (void*)&pkt, sizeof(pkt), 0, &sa, &sa_sz); if (r < 0) { if (errno == EINTR || errno == ECONNREFUSED) { // We return from this function in the hope that the next time // 'sockfd' is read ready, we will be invoked again. return; } else { perror("recvfrom"); exit(1); } } packet_ntoh(&pkt, &pkt); pkt.data[pkt.datalen] = '\0'; sscanf(pkt.data, "%d", &portno); const char *serverIP = sa_data_str(&sa); INFO("Server endpoints {1} [%s:%d] & {2} [%s:%d]\n", serverIP, ntohs(si->sin_port), serverIP, portno); /* // Disconnect port association. sa.sa_family = AF_UNSPEC; Connect(sockfd, &sa, sizeof(SA)); // Bind to the port we were originally bound to, and connect this // socket to the new port number that the server sent us. struct sockaddr cli_sa; struct sockaddr_in *cli_si = (struct sockaddr_in*)&cli_sa; memset(&cli_sa, 0, sizeof(cli_sa)); memcpy(&cli_sa, conn->cli_sa, sizeof(struct sockaddr)); cli_si->sin_port = htons(cliport); Bind(sockfd, &cli_sa, (socklen_t)sizeof(struct sockaddr_in)); */ // We open a new socket and dup2() since nothing else seems to be // working on both Linux as well as Solaris. int new_sockfd = Socket(AF_INET, SOCK_DGRAM, 0); dup2(new_sockfd, sockfd); if (conn->is_local) { set_dontroute(sockfd); } // Bind to the port we were originally bound to, and connect this // socket to the new port number that the server sent us. struct sockaddr_in cli_si; memset(&cli_si, 0, sizeof(cli_si)); memcpy(&cli_si, conn->cli_sa, sizeof(struct sockaddr)); cli_si.sin_port = htons(cliport); Bind(sockfd, (struct sockaddr*)&cli_si, (socklen_t)sizeof(struct sockaddr_in)); sa = *(conn->serv_sa); si->sin_port = htons(portno); Connect(sockfd, &sa, sizeof(SA)); // Send an ACK to the server. pkt.flags = FLAG_ACK; pkt.ack = 1; pkt.rwinsz = cargs->sw_size; ++pkt.seq; pkt.datalen = 0; memset(pkt.data, 0, sizeof(pkt.data)); sprintf(pkt.data, "ACK:%d, RWINSZ: %d", pkt.ack, pkt.rwinsz); INFO("Sending %d bytes of data to the server\n", sizeof(pkt)); send_packet(&pkt); // Receive data from the socket till a packet with the FLAG_FIN flag // is received. if (pthread_create(&tid, NULL, (void *) (&consume_packets), (void *) (&rwin)) < 0) { err_sys("Could not spawn the consumer thread to read packets"); } while (1) { VERBOSE("Waiting on recv(2)...%s\n", ""); int r = recv_packet(&pkt); if (r < 0) { // Handle EINTR. if (errno == EINTR) { // Go back to waiting for a packet. continue; } else { if (errno == ECONNREFUSED) { INFO("http://memegenerator.net/instance/29609574%s\n", ""); } perror("recv"); exit(1); } } INFO("Received packet with SEQ#: %u\n", pkt.seq); packet_t *ack_pkt = rwindow_received_packet(&rwin, &pkt); INFO("ACK Packet will be sent with ACK: %u, Window Size: %d\n", ack_pkt->ack, ack_pkt->rwinsz); send_packet(ack_pkt); if (rwindow_received_all(&rwin)) { fdset_remove(&fds, &fds.rev, sockfd); fds.timeout_cb = fin_timeout; fdset_add(&fds, &fds.rev, sockfd, &sockfd, resend_fin_pkt); fds.timeout.tv_sec = 60; fds.timeout.tv_usec = 0; time_av_ms = 60*1000; at_select_ms = current_time_in_ms(); INFO("Entering the TIME_WAIT state%s\n", ""); INFO("File Transfer completed in %d sec\n", current_time_in_ms() / 1000); return; } free(ack_pkt); ack_pkt = NULL; } // while (1) }
int main(int argc, char *argv[]) { plan(12); /* 1. Create fdset. */ fdset_t set; int ret = fdset_init(&set, 32); is_int(0, ret, "fdset: init"); /* 2. Create pipe. */ int fds[2], tmpfds[2]; ret = pipe(fds); ok(ret >= 0, "fdset: pipe() works"); ret = pipe(tmpfds); ok(ret >= 0, "fdset: 2nd pipe() works"); /* 3. Add fd to set. */ ret = fdset_add(&set, fds[0], POLLIN, NULL); is_int(0, ret, "fdset: add to set works"); fdset_add(&set, tmpfds[0], POLLIN, NULL); /* Schedule write. */ struct timeval ts, te; gettimeofday(&ts, 0); pthread_t t; pthread_create(&t, 0, thr_action, &fds[1]); /* 4. Watch fdset. */ int nfds = poll(set.pfd, set.n, 60 * 1000); gettimeofday(&te, 0); size_t diff = timeval_diff(&ts, &te); ok(nfds > 0, "fdset: poll returned %d events in %zu ms", nfds, diff); /* 5. Prepare event set. */ ok(set.pfd[0].revents & POLLIN, "fdset: pipe is active"); /* 6. Receive data. */ char buf = 0x00; ret = read(set.pfd[0].fd, &buf, WRITE_PATTERN_LEN); ok(ret >= 0 && buf == WRITE_PATTERN, "fdset: contains valid data"); /* 7-9. Remove from event set. */ ret = fdset_remove(&set, 0); is_int(0, ret, "fdset: remove from fdset works"); close(fds[0]); close(fds[1]); ret = fdset_remove(&set, 0); close(tmpfds[1]); close(tmpfds[1]); is_int(0, ret, "fdset: remove from fdset works (2)"); ret = fdset_remove(&set, 0); ok(ret != 0, "fdset: removing nonexistent item"); /* 10. Crash test. */ fdset_init(0, 0); fdset_add(0, 1, 1, 0); fdset_add(0, 0, 1, 0); fdset_remove(0, 1); fdset_remove(0, 0); ok(1, "fdset: crash test successful"); /* 11. Destroy fdset. */ ret = fdset_clear(&set); is_int(0, ret, "fdset: destroyed"); /* Cleanup. */ pthread_join(t, 0); return 0; }