static int curl_glue_on_io(sd_event_source *s, int fd, uint32_t revents, void *userdata) { CurlGlue *g = userdata; int action, k = 0, translated_fd; assert(s); assert(g); translated_fd = PTR_TO_FD(hashmap_get(g->translate_fds, FD_TO_PTR(fd))); if ((revents & (EPOLLIN|EPOLLOUT)) == (EPOLLIN|EPOLLOUT)) action = CURL_POLL_INOUT; else if (revents & EPOLLIN) action = CURL_POLL_IN; else if (revents & EPOLLOUT) action = CURL_POLL_OUT; else action = 0; if (curl_multi_socket_action(g->curl, translated_fd, action, &k) < 0) { log_debug("Failed to propagate IO event."); return -EINVAL; } curl_glue_check_finished(g); return 0; }
CurlGlue *curl_glue_unref(CurlGlue *g) { sd_event_source *io; if (!g) return NULL; if (g->curl) curl_multi_cleanup(g->curl); while ((io = hashmap_steal_first(g->ios))) { int fd; fd = sd_event_source_get_io_fd(io); assert(fd >= 0); hashmap_remove(g->translate_fds, FD_TO_PTR(fd)); safe_close(fd); sd_event_source_unref(io); } hashmap_free(g->ios); sd_event_source_unref(g->timer); sd_event_unref(g->event); free(g); return NULL; }
int asynchronous_close(int fd) { int r; /* This is supposed to behave similar to safe_close(), but * actually invoke close() asynchronously, so that it will * never block. Ideally the kernel would have an API for this, * but it doesn't, so we work around it, and hide this as a * far away as we can. */ if (fd >= 0) { PROTECT_ERRNO; r = asynchronous_job(close_thread, FD_TO_PTR(fd)); if (r < 0) assert_se(close_nointr(fd) != -EBADF); } return -1; }
int fdset_remove(FDSet *s, int fd) { assert(s); assert(fd >= 0); return set_remove(MAKE_SET(s), FD_TO_PTR(fd)) ? fd : -ENOENT; }
bool fdset_contains(FDSet *s, int fd) { assert(s); assert(fd >= 0); return !!set_get(MAKE_SET(s), FD_TO_PTR(fd)); }
int fdset_put(FDSet *s, int fd) { assert(s); assert(fd >= 0); return set_put(MAKE_SET(s), FD_TO_PTR(fd)); }
static int curl_glue_socket_callback(CURLM *curl, curl_socket_t s, int action, void *userdata, void *socketp) { sd_event_source *io; CurlGlue *g = userdata; uint32_t events = 0; int r; assert(curl); assert(g); io = hashmap_get(g->ios, FD_TO_PTR(s)); if (action == CURL_POLL_REMOVE) { if (io) { int fd; fd = sd_event_source_get_io_fd(io); assert(fd >= 0); sd_event_source_set_enabled(io, SD_EVENT_OFF); sd_event_source_unref(io); hashmap_remove(g->ios, FD_TO_PTR(s)); hashmap_remove(g->translate_fds, FD_TO_PTR(fd)); safe_close(fd); } return 0; } r = hashmap_ensure_allocated(&g->ios, &trivial_hash_ops); if (r < 0) { log_oom(); return -1; } r = hashmap_ensure_allocated(&g->translate_fds, &trivial_hash_ops); if (r < 0) { log_oom(); return -1; } if (action == CURL_POLL_IN) events = EPOLLIN; else if (action == CURL_POLL_OUT) events = EPOLLOUT; else if (action == CURL_POLL_INOUT) events = EPOLLIN|EPOLLOUT; if (io) { if (sd_event_source_set_io_events(io, events) < 0) return -1; if (sd_event_source_set_enabled(io, SD_EVENT_ON) < 0) return -1; } else { _cleanup_close_ int fd = -1; /* When curl needs to remove an fd from us it closes * the fd first, and only then calls into us. This is * nasty, since we cannot pass the fd on to epoll() * anymore. Hence, duplicate the fds here, and keep a * copy for epoll which we control after use. */ fd = fcntl(s, F_DUPFD_CLOEXEC, 3); if (fd < 0) return -1; if (sd_event_add_io(g->event, &io, fd, events, curl_glue_on_io, g) < 0) return -1; (void) sd_event_source_set_description(io, "curl-io"); r = hashmap_put(g->ios, FD_TO_PTR(s), io); if (r < 0) { log_oom(); sd_event_source_unref(io); return -1; } r = hashmap_put(g->translate_fds, FD_TO_PTR(fd), FD_TO_PTR(s)); if (r < 0) { log_oom(); hashmap_remove(g->ios, FD_TO_PTR(s)); sd_event_source_unref(io); return -1; } fd = -1; } return 0; }