// 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); } }
int tcp_master(dthread_t *thread) { if (!thread || !thread->data) { return KNOT_EINVAL; } iohandler_t *handler = (iohandler_t *)thread->data; unsigned *iostate = &handler->thread_state[dt_get_id(thread)]; int ret = KNOT_EOK; ref_t *ref = NULL; tcp_context_t tcp; memset(&tcp, 0, sizeof(tcp_context_t)); /* Create big enough memory cushion. */ knot_mm_t mm; mm_ctx_mempool(&mm, 16 * MM_DEFAULT_BLKSIZE); /* Create TCP answering context. */ tcp.server = handler->server; tcp.thread_id = handler->thread_id[dt_get_id(thread)]; tcp.overlay.mm = &mm; /* Prepare structures for bound sockets. */ conf_val_t val = conf_get(conf(), C_SRV, C_LISTEN); fdset_init(&tcp.set, conf_val_count(&val) + CONF_XFERS); /* Create iovec abstraction. */ for (unsigned i = 0; i < 2; ++i) { tcp.iov[i].iov_len = KNOT_WIRE_MAX_PKTSIZE; tcp.iov[i].iov_base = malloc(tcp.iov[i].iov_len); if (tcp.iov[i].iov_base == NULL) { ret = KNOT_ENOMEM; goto finish; } } /* Initialize sweep interval. */ timev_t next_sweep = {0}; time_now(&next_sweep); next_sweep.tv_sec += TCP_SWEEP_INTERVAL; for(;;) { /* Check handler state. */ if (unlikely(*iostate & ServerReload)) { *iostate &= ~ServerReload; /* Cancel client connections. */ for (unsigned i = tcp.client_threshold; i < tcp.set.n; ++i) { close(tcp.set.pfd[i].fd); } ref_release(ref); ref = server_set_ifaces(handler->server, &tcp.set, IO_TCP, tcp.thread_id); if (tcp.set.n == 0) { break; /* Terminate on zero interfaces. */ } tcp.client_threshold = tcp.set.n; } /* Check for cancellation. */ if (dt_is_cancelled(thread)) { break; } /* Serve client requests. */ tcp_wait_for_events(&tcp); /* Sweep inactive clients. */ if (tcp.last_poll_time.tv_sec >= next_sweep.tv_sec) { fdset_sweep(&tcp.set, &tcp_sweep, NULL); time_now(&next_sweep); next_sweep.tv_sec += TCP_SWEEP_INTERVAL; } } finish: free(tcp.iov[0].iov_base); free(tcp.iov[1].iov_base); mp_delete(mm.ctx); fdset_clear(&tcp.set); ref_release(ref); return ret; }
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; }