static void query_resolve_cb(EV_P_ ev_timer *watcher, int revents) { int err; struct addrinfo *result, *rp; struct query_ctx *query_ctx = (struct query_ctx *)((void*)watcher); asyncns_t *asyncns = query_ctx->server_ctx->asyncns; asyncns_query_t *query = query_ctx->query; if (asyncns == NULL || query == NULL) { LOGE("invalid dns query."); close_and_free_query(EV_A_ query_ctx); return; } if (asyncns_wait(asyncns, 0) == -1) { // asyncns error FATAL("asyncns exit unexpectedly."); } if (!asyncns_isdone(asyncns, query)) { // wait reolver return; } if (verbose) { LOGD("[udp] asyncns resolved."); } ev_timer_stop(EV_A_ watcher); err = asyncns_getaddrinfo_done(asyncns, query, &result); if (err) { ERROR("getaddrinfo"); } else { // Use IPV4 address if possible for (rp = result; rp != NULL; rp = rp->ai_next) { if (rp->ai_family == AF_INET) break; } if (rp == NULL) { rp = result; } int remotefd = create_remote_socket(rp->ai_family == AF_INET6); if (remotefd != -1) { setnonblocking(remotefd); #ifdef SO_NOSIGPIPE int opt = 1; setsockopt(remotefd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif #ifdef SET_INTERFACE if (query_ctx->server_ctx->iface) setinterface(remotefd, query_ctx->server_ctx->iface); #endif struct remote_ctx *remote_ctx = new_remote(remotefd, query_ctx->server_ctx); remote_ctx->src_addr = query_ctx->src_addr; remote_ctx->dst_addr = *rp->ai_addr; remote_ctx->server_ctx = query_ctx->server_ctx; remote_ctx->addr_header_len = query_ctx->addr_header_len; memcpy(remote_ctx->addr_header, query_ctx->addr_header, query_ctx->addr_header_len); // Add to conn cache char *key = hash_key(remote_ctx->addr_header, remote_ctx->addr_header_len, &remote_ctx->src_addr); cache_insert(query_ctx->server_ctx->conn_cache, key, (void *)remote_ctx); ev_io_start(EV_A_ &remote_ctx->io); int s = sendto(remote_ctx->fd, query_ctx->buf, query_ctx->buf_len, 0, &remote_ctx->dst_addr, sizeof(remote_ctx->dst_addr)); if (s == -1) { ERROR("udprelay_sendto_remote"); close_and_free_remote(EV_A_ remote_ctx); } } else { ERROR("udprelay bind() error.."); } } // clean up asyncns_freeaddrinfo(result); close_and_free_query(EV_A_ query_ctx); }
int main(int argc, char *argv[]) { asyncns_t* asyncns = NULL; asyncns_query_t *q1, *q2, *q3; int r = 1, ret; struct addrinfo *ai, hints; struct sockaddr_in sa; char host[NI_MAXHOST] = "", serv[NI_MAXSERV] = ""; unsigned char *srv; signal(SIGCHLD, SIG_IGN); if (!(asyncns = asyncns_new(2))) { fprintf(stderr, "asyncns_new() failed\n"); goto fail; } /* Make a name -> address query */ memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; q1 = asyncns_getaddrinfo(asyncns, argc >= 2 ? argv[1] : "www.heise.de", NULL, &hints); if (!q1) fprintf(stderr, "asyncns_getaddrinfo(): %s\n", strerror(errno)); /* Make an address -> name query */ memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_addr.s_addr = inet_addr(argc >= 3 ? argv[2] : "193.99.144.71"); sa.sin_port = htons(80); q2 = asyncns_getnameinfo(asyncns, (struct sockaddr*) &sa, sizeof(sa), 0, 1, 1); if (!q2) fprintf(stderr, "asyncns_getnameinfo(): %s\n", strerror(errno)); /* Make a res_query() call */ q3 = asyncns_res_query(asyncns, "_xmpp-client._tcp.gmail.com", C_IN, T_SRV); if (!q3) fprintf(stderr, "asyncns_res_query(): %s\n", strerror(errno)); /* Wait until the three queries are completed */ while (!asyncns_isdone(asyncns, q1) || !asyncns_isdone(asyncns, q2) || !asyncns_isdone(asyncns, q3)) { if (asyncns_wait(asyncns, 1) < 0) { fprintf(stderr, "asyncns_wait(): %s\n", strerror(errno)); goto fail; } } /* Interpret the result of the name -> addr query */ if ((ret = asyncns_getaddrinfo_done(asyncns, q1, &ai))) fprintf(stderr, "error: %s %i\n", gai_strerror(ret), ret); else { struct addrinfo *i; for (i = ai; i; i = i->ai_next) { char t[256]; const char *p = NULL; if (i->ai_family == PF_INET) p = inet_ntop(AF_INET, &((struct sockaddr_in*) i->ai_addr)->sin_addr, t, sizeof(t)); else if (i->ai_family == PF_INET6) p = inet_ntop(AF_INET6, &((struct sockaddr_in6*) i->ai_addr)->sin6_addr, t, sizeof(t)); printf("%s\n", p); } asyncns_freeaddrinfo(ai); } /* Interpret the result of the addr -> name query */ if ((ret = asyncns_getnameinfo_done(asyncns, q2, host, sizeof(host), serv, sizeof(serv)))) fprintf(stderr, "error: %s %i\n", gai_strerror(ret), ret); else printf("%s -- %s\n", host, serv); /* Interpret the result of the SRV lookup */ if ((ret = asyncns_res_done(asyncns, q3, &srv)) < 0) { fprintf(stderr, "error: %s %i\n", strerror(errno), ret); } else if (ret == 0) { fprintf(stderr, "No reply for SRV lookup\n"); } else { int qdcount; int ancount; int len; const unsigned char *pos = srv + sizeof(HEADER); unsigned char *end = srv + ret; HEADER *head = (HEADER *)srv; char name[256]; qdcount = ntohs(head->qdcount); ancount = ntohs(head->ancount); printf("%d answers for srv lookup:\n", ancount); /* Ignore the questions */ while (qdcount-- > 0 && (len = dn_expand(srv, end, pos, name, 255)) >= 0) { assert(len >= 0); pos += len + QFIXEDSZ; } /* Parse the answers */ while (ancount-- > 0 && (len = dn_expand(srv, end, pos, name, 255)) >= 0) { /* Ignore the initial string */ uint16_t pref, weight, port; assert(len >= 0); pos += len; /* Ignore type, ttl, class and dlen */ pos += 10; GETSHORT(pref, pos); GETSHORT(weight, pos); GETSHORT(port, pos); len = dn_expand(srv, end, pos, name, 255); printf("\tpreference: %2d weight: %2d port: %d host: %s\n", pref, weight, port, name); pos += len; } asyncns_freeanswer(srv); } r = 0; fail: if (asyncns) asyncns_free(asyncns); return r; }
static void server_resolve_cb(EV_P_ ev_io *w, int revents) { int err; struct addrinfo *result, *rp; struct listen_ctx *listen_ctx = (struct listen_ctx *)w; asyncns_t *asyncns = listen_ctx->asyncns; err = asyncns_handle(asyncns); if (err == ASYNCNS_HANDLE_AGAIN) { // try again return; } else if (err == ASYNCNS_HANDLE_ERROR) { // asyncns error FATAL("asyncns exit unexpectedly."); } asyncns_query_t *query = asyncns_getnext(asyncns); struct server *server= (struct server*) asyncns_getuserdata(asyncns, query); if (!asyncns_isdone(asyncns, query)) { // wait for reolver return; } server->query = NULL; if (verbose) { LOGD("asyncns resolved."); } err = asyncns_getaddrinfo_done(asyncns, query, &result); if (err) { ERROR("getaddrinfo"); close_and_free_server(EV_A_ server); } else { // Use IPV4 address if possible for (rp = result; rp != NULL; rp = rp->ai_next) { if (rp->ai_family == AF_INET) break; } if (rp == NULL) { rp = result; } struct remote *remote = connect_to_remote(rp, server->listen_ctx->iface); if (remote == NULL) { LOGE("connect error."); close_and_free_server(EV_A_ server); } else { server->remote = remote; remote->server = server; // XXX: should handel buffer carefully if (server->buf_len > 0) { memcpy(remote->buf, server->buf + server->buf_idx, server->buf_len); remote->buf_len = server->buf_len; remote->buf_idx = 0; server->buf_len = 0; server->buf_idx = 0; } // listen to remote connected event ev_io_start(EV_A_ &remote->send_ctx->io); } } // release addrinfo asyncns_freeaddrinfo(result); }
static void server_resolve_cb(EV_P_ ev_timer *watcher, int revents) { int err; struct addrinfo *result, *rp; struct server_ctx *server_ctx = (struct server_ctx *) (((void*)watcher) - sizeof(ev_io)); struct server *server = server_ctx->server; asyncns_t *asyncns = server->listen_ctx->asyncns; asyncns_query_t *query = server->query; if (asyncns == NULL || query == NULL) { LOGE("invalid dns query."); close_and_free_server(EV_A_ server); return; } if (asyncns_wait(asyncns, 0) == -1) { // asyncns error FATAL("asyncns exit unexpectedly."); } if (!asyncns_isdone(asyncns, query)) { // wait for reolver return; } if (verbose) { LOGD("asyncns resolved."); } ev_timer_stop(EV_A_ watcher); err = asyncns_getaddrinfo_done(asyncns, query, &result); if (err) { ERROR("getaddrinfo"); close_and_free_server(EV_A_ server); } else { // Use IPV4 address if possible for (rp = result; rp != NULL; rp = rp->ai_next) { if (rp->ai_family == AF_INET) break; } if (rp == NULL) { rp = result; } struct remote *remote = connect_to_remote(rp, server->listen_ctx->iface); if (remote == NULL) { LOGE("connect error."); close_and_free_server(EV_A_ server); } else { server->remote = remote; remote->server = server; // XXX: should handel buffer carefully if (server->buf_len > 0) { memcpy(remote->buf, server->buf + server->buf_idx, server->buf_len); remote->buf_len = server->buf_len; remote->buf_idx = 0; server->buf_len = 0; server->buf_idx = 0; } // listen to remote connected event ev_io_start(EV_A_ &remote->send_ctx->io); } } // release addrinfo asyncns_freeaddrinfo(result); }
int main(int argc, char **argv) { asyncns_t *asyncns; asyncns_query_t *query; struct addrinfo *result; struct pollfd pollfd = { .events = POLLIN }; int status; asyncns = asyncns_new(10); assert(asyncns); assert(asyncns_getnqueries(asyncns) == 0); assert(asyncns_getnext(asyncns) == NULL); pollfd.fd = asyncns_fd(asyncns); assert(pollfd.fd > 2); query = asyncns_getaddrinfo(asyncns, "127.0.0.1", NULL, NULL); assert(query); assert(asyncns_getnqueries(asyncns) == 1); assert(asyncns_getnext(asyncns) == NULL); asyncns_cancel(asyncns, query); query = NULL; assert(asyncns_getnqueries(asyncns) == 0); assert(asyncns_getnext(asyncns) == NULL); query = asyncns_getaddrinfo(asyncns, "127.0.0.1", NULL, NULL); assert(query); assert(asyncns_getnqueries(asyncns) == 1); assert(asyncns_getnext(asyncns) == NULL); usleep(100000); status = poll(&pollfd, 1, 0); assert(status == 1); status = asyncns_wait(asyncns, 0); assert(status == 0); assert(asyncns_isdone(asyncns, query)); assert(asyncns_getnqueries(asyncns) == 1); assert(asyncns_getnext(asyncns) == query); status = poll(&pollfd, 1, 100); assert(status == 0); status = asyncns_getaddrinfo_done(asyncns, query, &result); assert(asyncns_getnqueries(asyncns) == 0); /* Intuitively, this should not be needed but the docs state that * a call to `asyncns_wait()` is necessary so that `asyncns_getnext()` * provides meaningful results. */ status = asyncns_wait(asyncns, 0); assert(status == 0); /* There were two queries issued, one of which has been cancelled * and the other has been freed afterwards. As none of them can be * returned, the only meaningful result of `asyncns_getnext()` is * NULL. */ assert(asyncns_getnext(asyncns) == NULL); asyncns_free(asyncns); asyncns_freeaddrinfo(result); return EXIT_SUCCESS; }
static void query_resolve_cb(EV_P_ ev_io *w, int revents) { int err; struct addrinfo *result, *rp; struct resolve_ctx *resolve_ctx = (struct resolve_ctx *)w; asyncns_t *asyncns = resolve_ctx->asyncns; err = asyncns_handle(asyncns); if (err == ASYNCNS_HANDLE_AGAIN) { // try again return; } else if (err == ASYNCNS_HANDLE_ERROR) { // asyncns error FATAL("[udp] asyncns exit unexpectedly."); } asyncns_query_t *query = asyncns_getnext(asyncns); struct query_ctx *query_ctx = (struct query_ctx *)asyncns_getuserdata( asyncns, query); if (!asyncns_isdone(asyncns, query)) { // wait reolver return; } if (verbose) { LOGD("[udp] asyncns resolved."); } query_ctx->query = NULL; err = asyncns_getaddrinfo_done(asyncns, query, &result); if (err) { ERROR("[udp] asysncns_getaddrinfo"); } else { // Use IPV4 address if possible for (rp = result; rp != NULL; rp = rp->ai_next) { if (rp->ai_family == AF_INET) { break; } } if (rp == NULL) { rp = result; } int remotefd = create_remote_socket(rp->ai_family == AF_INET6); if (remotefd != -1) { setnonblocking(remotefd); #ifdef SO_BROADCAST set_broadcast(remotefd); #endif #ifdef SO_NOSIGPIPE set_nosigpipe(remotefd); #endif #ifdef SET_INTERFACE if (query_ctx->server_ctx->iface) { setinterface(remotefd, query_ctx->server_ctx->iface); } #endif struct remote_ctx *remote_ctx = new_remote(remotefd, query_ctx->server_ctx); remote_ctx->src_addr = query_ctx->src_addr; remote_ctx->dst_addr = *((struct sockaddr_storage *)rp->ai_addr); remote_ctx->server_ctx = query_ctx->server_ctx; remote_ctx->addr_header_len = query_ctx->addr_header_len; memcpy(remote_ctx->addr_header, query_ctx->addr_header, query_ctx->addr_header_len); size_t addr_len = sizeof(struct sockaddr_in); if (remote_ctx->dst_addr.ss_family == AF_INET6) { addr_len = sizeof(struct sockaddr_in6); } int s = sendto(remote_ctx->fd, query_ctx->buf, query_ctx->buf_len, 0, (struct sockaddr *)&remote_ctx->dst_addr, addr_len); if (s == -1) { ERROR("[udp] sendto_remote"); close_and_free_remote(EV_A_ remote_ctx); } else { // Add to conn cache char *key = hash_key(remote_ctx->addr_header, remote_ctx->addr_header_len, &remote_ctx->src_addr); cache_insert(query_ctx->server_ctx->conn_cache, key, (void *)remote_ctx); ev_io_start(EV_A_ & remote_ctx->io); } } else { ERROR("[udp] bind() error.."); } } // clean up asyncns_freeaddrinfo(result); close_and_free_query(EV_A_ query_ctx); }