int fdset_sweep(fdset_t* set, fdset_sweep_cb_t cb, void *data) { if (set == NULL || cb == NULL) { return KNOT_EINVAL; } /* Get time threshold. */ timev_t now; if (time_now(&now) < 0) { return KNOT_ERROR; } unsigned i = 0; while (i < set->n) { /* Check sweep state, remove if requested. */ if (set->timeout[i] > 0 && set->timeout[i] <= now.tv_sec) { if (cb(set, i, data) == FDSET_SWEEP) { if (fdset_remove(set, i) == KNOT_EOK) continue; /* Stay on the index. */ } } /* Next descriptor. */ ++i; } return KNOT_EOK; }
static int tcp_wait_for_events(tcp_context_t *tcp) { /* Wait for events. */ fdset_t *set = &tcp->set; int nfds = poll(set->pfd, set->n, TCP_SWEEP_INTERVAL * 1000); /* Mark the time of last poll call. */ time_now(&tcp->last_poll_time); /* Process events. */ unsigned i = 0; while (nfds > 0 && i < set->n) { /* Terminate faulty connections. */ int fd = set->pfd[i].fd; /* Active sockets. */ if (set->pfd[i].revents & POLLIN) { --nfds; /* One less active event. */ /* Indexes <0, client_threshold) are master sockets. */ if (i < tcp->client_threshold) { /* Faulty master sockets shall be sorted later. */ (void) tcp_event_accept(tcp, i); } else { if (tcp_event_serve(tcp, i) != KNOT_EOK) { fdset_remove(set, i); close(fd); continue; /* Stay on the same index. */ } } } if (set->pfd[i].revents & (POLLERR|POLLHUP|POLLNVAL)) { --nfds; /* One less active event. */ fdset_remove(set, i); close(fd); continue; /* Stay on the same index. */ } /* Next socket. */ ++i; } return nfds; }
void fdset_add(fdset *fds, vector *v, int fd, void *opaque, ev_callback_t callback) { select_event_t se; se.fd = fd; se.opaque = opaque; se.callback = callback; fdset_remove(fds, v, fd); vector_push_back(v, &se); }
int server_restore_streams(Server *s, FDSet *fds) { _cleanup_closedir_ DIR *d = NULL; struct dirent *de; int r; d = opendir("/run/systemd/journal/streams"); if (!d) { if (errno == ENOENT) return 0; return log_warning_errno(errno, "Failed to enumerate /run/systemd/journal/streams: %m"); } FOREACH_DIRENT(de, d, goto fail) { unsigned long st_dev, st_ino; bool found = false; Iterator i; int fd; if (sscanf(de->d_name, "%lu:%lu", &st_dev, &st_ino) != 2) continue; FDSET_FOREACH(fd, fds, i) { struct stat st; if (fstat(fd, &st) < 0) return log_error_errno(errno, "Failed to stat %s: %m", de->d_name); if (S_ISSOCK(st.st_mode) && st.st_dev == st_dev && st.st_ino == st_ino) { found = true; break; } } if (!found) { /* No file descriptor? Then let's delete the state file */ log_debug("Cannot restore stream file %s", de->d_name); if (unlinkat(dirfd(d), de->d_name, 0) < 0) log_warning_errno(errno, "Failed to remove /run/systemd/journal/streams/%s: %m", de->d_name); continue; } fdset_remove(fds, fd); r = stdout_stream_restore(s, de->d_name, fd); if (r < 0) safe_close(fd); } return 0; fail: return log_error_errno(errno, "Failed to read streams directory: %m"); }
static int tcp_wait_for_events(tcp_context_t *tcp) { /* Wait for events. */ fdset_t *set = &tcp->set; int nfds = poll(set->pfd, set->n, TCP_SWEEP_INTERVAL * 1000); /* Mark the time of last poll call. */ time_now(&tcp->last_poll_time); bool is_throttled = (tcp->last_poll_time.tv_sec < tcp->throttle_end.tv_sec); if (!is_throttled) { /* Configuration limit, infer maximal pool size. */ rcu_read_lock(); conf_val_t *val = &conf()->cache.srv_max_tcp_clients; unsigned max_per_set = MAX(conf_int(val) / conf_tcp_threads(conf()), 1); rcu_read_unlock(); /* Subtract master sockets check limits. */ is_throttled = (set->n - tcp->client_threshold) >= max_per_set; } /* Process events. */ unsigned i = 0; while (nfds > 0 && i < set->n) { bool should_close = false; int fd = set->pfd[i].fd; if (set->pfd[i].revents & (POLLERR|POLLHUP|POLLNVAL)) { should_close = (i >= tcp->client_threshold); --nfds; } else if (set->pfd[i].revents & (POLLIN)) { /* Master sockets */ if (i < tcp->client_threshold) { if (!is_throttled && tcp_event_accept(tcp, i) == KNOT_EBUSY) { time_now(&tcp->throttle_end); tcp->throttle_end.tv_sec += tcp_throttle(); } /* Client sockets */ } else { if (tcp_event_serve(tcp, i) != KNOT_EOK) { should_close = true; } } --nfds; } /* Evaluate */ if (should_close) { fdset_remove(set, i); close(fd); } else { ++i; } } return nfds; }
static int busname_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { BusName *n = BUSNAME(u); assert(n); assert(key); assert(value); if (streq(key, "state")) { BusNameState state; state = busname_state_from_string(value); if (state < 0) log_unit_debug(u->id, "Failed to parse state value %s", value); else n->deserialized_state = state; } else if (streq(key, "result")) { BusNameResult f; f = busname_result_from_string(value); if (f < 0) log_unit_debug(u->id, "Failed to parse result value %s", value); else if (f != BUSNAME_SUCCESS) n->result = f; } else if (streq(key, "control-pid")) { pid_t pid; if (parse_pid(value, &pid) < 0) log_unit_debug(u->id, "Failed to parse control-pid value %s", value); else n->control_pid = pid; } else if (streq(key, "starter-fd")) { int fd; if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) log_unit_debug(u->id, "Failed to parse starter fd value %s", value); else { safe_close(n->starter_fd); n->starter_fd = fdset_remove(fds, fd); } } else log_unit_debug(u->id, "Unknown serialization key '%s'", key); return 0; }
static void test_fdset_remove(void) { _cleanup_close_ int fd = -1; FDSet *fdset = NULL; char name[] = "/tmp/test-fdset_remove.XXXXXX"; fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); assert_se(fd >= 0); fdset = fdset_new(); assert_se(fdset); assert_se(fdset_put(fdset, fd) >= 0); assert_se(fdset_remove(fdset, fd) >= 0); assert_se(!fdset_contains(fdset, fd)); fdset_free(fdset); assert_se(fcntl(fd, F_GETFD) >= 0); unlink(name); }
static int automount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { Automount *a = AUTOMOUNT(u); int r; assert(a); assert(fds); if (streq(key, "state")) { AutomountState state; state = automount_state_from_string(value); if (state < 0) log_unit_debug(u, "Failed to parse state value: %s", value); else a->deserialized_state = state; } else if (streq(key, "result")) { AutomountResult f; f = automount_result_from_string(value); if (f < 0) log_unit_debug(u, "Failed to parse result value: %s", value); else if (f != AUTOMOUNT_SUCCESS) a->result = f; } else if (streq(key, "dev-id")) { unsigned d; if (safe_atou(value, &d) < 0) log_unit_debug(u, "Failed to parse dev-id value: %s", value); else a->dev_id = (unsigned) d; } else if (streq(key, "token")) { unsigned token; if (safe_atou(value, &token) < 0) log_unit_debug(u, "Failed to parse token value: %s", value); else { r = set_ensure_allocated(&a->tokens, NULL); if (r < 0) { log_oom(); return 0; } r = set_put(a->tokens, UINT_TO_PTR(token)); if (r < 0) log_unit_error_errno(u, r, "Failed to add token to set: %m"); } } else if (streq(key, "expire-token")) { unsigned token; if (safe_atou(value, &token) < 0) log_unit_debug(u, "Failed to parse token value: %s", value); else { r = set_ensure_allocated(&a->expire_tokens, NULL); if (r < 0) { log_oom(); return 0; } r = set_put(a->expire_tokens, UINT_TO_PTR(token)); if (r < 0) log_unit_error_errno(u, r, "Failed to add expire token to set: %m"); } } else if (streq(key, "pipe-fd")) { int fd; if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) log_unit_debug(u, "Failed to parse pipe-fd value: %s", value); else { safe_close(a->pipe_fd); a->pipe_fd = fdset_remove(fds, fd); } } else log_unit_debug(u, "Unknown serialization key: %s", key); return 0; }
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; }
static int automount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { Automount *a = AUTOMOUNT(u); int r; assert(a); assert(fds); if (streq(key, "state")) { AutomountState state; state = automount_state_from_string(value); if (state < 0) log_debug_unit(u->id, "Failed to parse state value %s", value); else a->deserialized_state = state; } else if (streq(key, "result")) { AutomountResult f; f = automount_result_from_string(value); if (f < 0) log_debug_unit(u->id, "Failed to parse result value %s", value); else if (f != AUTOMOUNT_SUCCESS) a->result = f; } else if (streq(key, "dev-id")) { unsigned d; if (safe_atou(value, &d) < 0) log_debug_unit(u->id, "Failed to parse dev-id value %s", value); else a->dev_id = (unsigned) d; } else if (streq(key, "token")) { unsigned token; if (safe_atou(value, &token) < 0) log_debug_unit(u->id, "Failed to parse token value %s", value); else { if (!a->tokens) if (!(a->tokens = set_new(trivial_hash_func, trivial_compare_func))) return -ENOMEM; r = set_put(a->tokens, UINT_TO_PTR(token)); if (r < 0) return r; } } else if (streq(key, "pipe-fd")) { int fd; if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) log_debug_unit(u->id, "Failed to parse pipe-fd value %s", value); else { if (a->pipe_fd >= 0) close_nointr_nofail(a->pipe_fd); a->pipe_fd = fdset_remove(fds, fd); } } else log_debug_unit(u->id, "Unknown serialization key '%s'", key); return 0; }