/** * Callback function for inputevt_add(). This function pipes the query to * the server using the pipe in non-blocking mode, partial writes are handled * appropriately. In case of an unrecoverable error the query pipe will be * closed and the blocking adns_fallback() will be invoked. */ static void adns_query_callback(void *data, int dest, inputevt_cond_t condition) { adns_async_write_t *remain = data; g_assert(NULL != remain); g_assert(NULL != remain->buf); g_assert(remain->pos < remain->size); g_assert(dest == adns_query_fd); g_assert(0 != adns_query_event_id); if (condition & INPUT_EVENT_EXCEPTION) { g_warning("%s: write exception", G_STRFUNC); goto abort; } while (remain->pos < remain->size) { ssize_t ret; size_t n; n = remain->size - remain->pos; ret = write(dest, &remain->buf[remain->pos], n); if (0 == ret) { errno = ECONNRESET; ret = (ssize_t) -1; } /* FALL THROUGH */ if ((ssize_t) -1 == ret) { if (!is_temporary_error(errno)) goto error; return; } g_assert(ret > 0); g_assert(UNSIGNED(ret) <= n); remain->pos += (size_t) ret; } g_assert(remain->pos == remain->size); inputevt_remove(&adns_query_event_id); goto done; error: g_warning("%s: write() failed: %m", G_STRFUNC); abort: g_warning("%s: removed myself", G_STRFUNC); inputevt_remove(&adns_query_event_id); fd_close(&adns_query_fd); g_warning("%s: using fallback", G_STRFUNC); adns_fallback(&remain->req); done: adns_async_write_free(remain); return; }
/** * Change the monitoring condition on the socket. */ static void tls_socket_evt_change(struct gnutella_socket *s, inputevt_cond_t cond) { socket_check(s); g_assert(socket_with_tls(s)); /* No USES yet, may not have handshaked */ g_assert(INPUT_EVENT_EXCEPTION != cond); if (0 == s->gdk_tag) return; if (cond != s->tls.cb_cond) { int saved_errno = errno; if (GNET_PROPERTY(tls_debug) > 1) { int fd = socket_evt_fd(s); g_debug("tls_socket_evt_change: fd=%d, cond=%s -> %s", fd, inputevt_cond_to_string(s->tls.cb_cond), inputevt_cond_to_string(cond)); } inputevt_remove(&s->gdk_tag); socket_evt_set(s, cond, s->tls.cb_handler, s->tls.cb_data); errno = saved_errno; } }
/** * Callback function for inputevt_add(). This function invokes the callback * function given in DNS query on the client-side i.e., gtk-gnutella itself. * It handles partial reads if necessary. In case of an unrecoverable error * the reply pipe will be closed and the callback will be lost. */ static void adns_reply_callback(void *data, int source, inputevt_cond_t condition) { static struct adns_response ans; static void *buf; static size_t size, pos; g_assert(NULL == data); g_assert(condition & INPUT_EVENT_RX); /* * Consume all the data available in the pipe, potentially handling * several pending replies. */ for (;;) { ssize_t ret; size_t n; if (pos == size) { pos = 0; if (cast_to_pointer(&ans.common) == buf) { /* * Finished reading the generic reply header, now read * the specific part. */ g_assert(ADNS_COMMON_MAGIC == ans.common.magic); if (ans.common.reverse) { buf = &ans.reply.reverse; size = sizeof ans.reply.reverse; } else { buf = &ans.reply.by_addr; size = sizeof ans.reply.by_addr; } } else { if (buf) { /* * Completed reading the specific part of the reply. * Inform issuer of request by invoking the user callback. */ adns_reply_ready(&ans); } /* * Continue reading the next reply, if any, which will start * by the generic header. */ buf = &ans.common; size = sizeof ans.common; ans.common.magic = 0; } } g_assert(buf); g_assert(size > 0); g_assert(pos < size); n = size - pos; ret = read(source, cast_to_gchar_ptr(buf) + pos, n); if ((ssize_t) -1 == ret) { if (!is_temporary_error(errno)) { g_warning("%s: read() failed: %m", G_STRFUNC); goto error; } break; } else if (0 == ret) { g_warning("%s: read() failed: EOF", G_STRFUNC); goto error; } else { g_assert(ret > 0); g_assert(UNSIGNED(ret) <= n); pos += (size_t) ret; } } return; error: inputevt_remove(&adns_reply_event_id); g_warning("%s: removed myself", G_STRFUNC); fd_close(&source); }