int main() { int ret; int fd_A[2]; if (pipe(fd_A) == -1) { perror("pipe"); exit(1); } ret = fork(); if (ret < 0) { perror("fork"); exit(1); } else if (ret == 0) { /* I am the child and I will write only, so close reading end of pipe */ // STEP 1: Add the close call below if XXX { perror("close"); exit(1); } write_to_parent(fd_A[1]); exit(0); } /* I am the parent only so close writing end of pipe to child A */ // STEP 1: Add the close call below read_from_child(fd_A[0]); return 0; }
G_GNUC_NORETURN static void purple_dnsquery_resolver_run(int child_out, int child_in, gboolean show_debug) { dns_params_t dns_params; const size_t zero = 0; int rc; #ifdef HAVE_GETADDRINFO struct addrinfo hints, *res, *tmp; char servname[20]; #else struct sockaddr_in sin; const size_t addrlen = sizeof(sin); #endif char *hostname; #ifdef HAVE_SIGNAL_H purple_restore_default_signal_handlers(); signal(SIGTRAP, trap_gdb_bug); #endif /* * We resolve 1 host name for each iteration of this * while loop. * * The top half of this reads in the hostname and port * number from the socket with our parent. The bottom * half of this resolves the IP (blocking) and sends * the result back to our parent, when finished. */ while (1) { fd_set fds; struct timeval tv = { .tv_sec = 20, .tv_usec = 0 }; FD_ZERO(&fds); FD_SET(child_in, &fds); rc = select(child_in + 1, &fds, NULL, NULL, &tv); if (!rc) { if (show_debug) printf("dns[%d]: nobody needs me... =(\n", getpid()); break; } rc = read(child_in, &dns_params, sizeof(dns_params_t)); if (rc < 0) { fprintf(stderr, "dns[%d]: Error: Could not read dns_params: " "%s\n", getpid(), strerror(errno)); break; } if (rc == 0) { if (show_debug) printf("dns[%d]: Oops, father has gone, wait for me, wait...!\n", getpid()); _exit(0); } if (dns_params.hostname[0] == '\0') { fprintf(stderr, "dns[%d]: Error: Parent requested resolution " "of an empty hostname (port = %d)!!!\n", getpid(), dns_params.port); _exit(1); } #ifdef USE_IDN if (!dns_str_is_ascii(dns_params.hostname)) { rc = purple_network_convert_idn_to_ascii(dns_params.hostname, &hostname); if (rc != 0) { write_to_parent(child_out, &rc, sizeof(rc)); if (show_debug) fprintf(stderr, "dns[%d] Error: IDN conversion returned " "%d\n", getpid(), rc); dns_params.hostname[0] = '\0'; break; } } else /* intentional to execute the g_strdup */ #endif hostname = g_strdup(dns_params.hostname); /* We have the hostname and port, now resolve the IP */ #ifdef HAVE_GETADDRINFO g_snprintf(servname, sizeof(servname), "%d", dns_params.port); memset(&hints, 0, sizeof(hints)); /* This is only used to convert a service * name to a port number. As we know we are * passing a number already, we know this * value will not be really used by the C * library. */ hints.ai_socktype = SOCK_STREAM; #ifdef AI_ADDRCONFIG hints.ai_flags |= AI_ADDRCONFIG; #endif /* AI_ADDRCONFIG */ rc = getaddrinfo(hostname, servname, &hints, &res); write_to_parent(child_out, &rc, sizeof(rc)); if (rc != 0) { if (show_debug) printf("dns[%d] Error: getaddrinfo returned %d\n", getpid(), rc); dns_params.hostname[0] = '\0'; g_free(hostname); hostname = NULL; break; } tmp = res; while (res) { size_t ai_addrlen = res->ai_addrlen; write_to_parent(child_out, &ai_addrlen, sizeof(ai_addrlen)); write_to_parent(child_out, res->ai_addr, res->ai_addrlen); res = res->ai_next; } freeaddrinfo(tmp); #else struct hostent *hp; if (!(hp = gethostbyname(hostname))) { write_to_parent(child_out, &h_errno, sizeof(int)); close(child_out); if (show_debug) printf("DNS Error: %d\n", h_errno); _exit(0); } memset(&sin, 0, sizeof(struct sockaddr_in)); memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); sin.sin_family = hp->h_addrtype; sin.sin_port = htons(dns_params.port); rc = 0; write_to_parent(child_out, &rc, sizeof(rc)); write_to_parent(child_out, &addrlen, sizeof(addrlen)); write_to_parent(child_out, &sin, addrlen); #endif write_to_parent(child_out, &zero, sizeof(zero)); dns_params.hostname[0] = '\0'; g_free(hostname); hostname = NULL; } close(child_out); close(child_in); _exit(0); } /* * End the DNS resolver child process functions. */ /* * Begin the functions for dealing with the DNS child processes. */ static void cope_with_gdb_brokenness(void) { #ifdef __linux__ static gboolean already_done = FALSE; char s[256], e[512]; int n; pid_t ppid; if(already_done) return; already_done = TRUE; ppid = getppid(); g_snprintf(s, sizeof(s), "/proc/%d/exe", ppid); n = readlink(s, e, sizeof(e)); if(n < 0) return; e[MIN((gsize)n,sizeof(e)-1)] = '\0'; if(strstr(e,"gdb")) { purple_debug_info("dns", "Debugger detected, performing useless query...\n"); gethostbyname("x.x.x.x.x"); } #endif } static void purple_dnsquery_resolver_destroy(PurpleDnsQueryResolverProcess *resolver) { g_return_if_fail(resolver != NULL); /* Keep this before the kill() call below. */ if (resolver->inpa != 0) { purple_input_remove(resolver->inpa); resolver->inpa = 0; } /* * We might as well attempt to kill our child process. It really * doesn't matter if this fails, because children will expire on * their own after a few seconds. */ if (resolver->dns_pid > 0) kill(resolver->dns_pid, SIGKILL); close(resolver->fd_in); close(resolver->fd_out); g_free(resolver); number_of_dns_children--; }