Mercurial > pidgin
comparison src/proxy.c @ 4434:6b83a532eeb2
[gaim-migrate @ 4709]
Async DNS was leaking 2 file desriptors per lost DNS child. It also
corrects the async DNS function interface.
thanks niqueco
committer: Tailor Script <tailor@pidgin.im>
| author | Nathan Walp <nwalp@pidgin.im> |
|---|---|
| date | Mon, 27 Jan 2003 07:51:05 +0000 |
| parents | 3fa2941a5323 |
| children | 1f9cd40abb4a |
comparison
equal
deleted
inserted
replaced
| 4433:289efc79a242 | 4434:6b83a532eeb2 |
|---|---|
| 141 * a free child process. | 141 * a free child process. |
| 142 */ | 142 */ |
| 143 typedef struct { | 143 typedef struct { |
| 144 char *host; | 144 char *host; |
| 145 int port; | 145 int port; |
| 146 int socktype; | |
| 147 dns_callback_t callback; | 146 dns_callback_t callback; |
| 148 gpointer data; | 147 gpointer data; |
| 149 gint inpa; | 148 gint inpa; |
| 150 int fd_in, fd_out; | 149 int fd_in, fd_out; |
| 151 pid_t dns_pid; | 150 pid_t dns_pid; |
| 159 const int MAX_DNS_CHILDREN = 2; | 158 const int MAX_DNS_CHILDREN = 2; |
| 160 | 159 |
| 161 typedef struct { | 160 typedef struct { |
| 162 char hostname[512]; | 161 char hostname[512]; |
| 163 int port; | 162 int port; |
| 164 int socktype; | |
| 165 } dns_params_t; | 163 } dns_params_t; |
| 166 | 164 |
| 167 typedef struct { | 165 typedef struct { |
| 168 dns_params_t params; | 166 dns_params_t params; |
| 169 dns_callback_t callback; | 167 dns_callback_t callback; |
| 170 gpointer data; | 168 gpointer data; |
| 171 } queued_dns_request_t; | 169 } queued_dns_request_t; |
| 172 | 170 |
| 171 static void req_free(pending_dns_request_t *req) | |
| 172 { | |
| 173 g_return_if_fail(req != NULL); | |
| 174 if(req->host) | |
| 175 g_free(req->host); | |
| 176 close(req->fd_in); | |
| 177 close(req->fd_out); | |
| 178 g_free(req); | |
| 179 number_of_dns_children--; | |
| 180 } | |
| 181 | |
| 173 static int send_dns_request_to_child(pending_dns_request_t *req, dns_params_t *dns_params) | 182 static int send_dns_request_to_child(pending_dns_request_t *req, dns_params_t *dns_params) |
| 174 { | 183 { |
| 175 char ch; | 184 char ch; |
| 176 int rc; | 185 int rc; |
| 177 | 186 |
| 183 | 192 |
| 184 /* Let's contact this lost child! */ | 193 /* Let's contact this lost child! */ |
| 185 rc = write(req->fd_in, dns_params, sizeof(*dns_params)); | 194 rc = write(req->fd_in, dns_params, sizeof(*dns_params)); |
| 186 if(rc<0) { | 195 if(rc<0) { |
| 187 debug_printf("Error writing to DNS child %d: %s\n", req->dns_pid, strerror(errno)); | 196 debug_printf("Error writing to DNS child %d: %s\n", req->dns_pid, strerror(errno)); |
| 197 close(req->fd_in); | |
| 188 return -1; | 198 return -1; |
| 189 } | 199 } |
| 190 | 200 |
| 191 g_return_val_if_fail(rc == sizeof(*dns_params), -1); | 201 g_return_val_if_fail(rc == sizeof(*dns_params), -1); |
| 192 | 202 |
| 205 static void host_resolved(gpointer data, gint source, GaimInputCondition cond); | 215 static void host_resolved(gpointer data, gint source, GaimInputCondition cond); |
| 206 | 216 |
| 207 static void release_dns_child(pending_dns_request_t *req) | 217 static void release_dns_child(pending_dns_request_t *req) |
| 208 { | 218 { |
| 209 g_free(req->host); | 219 g_free(req->host); |
| 220 req->host=NULL; | |
| 210 | 221 |
| 211 if(queued_requests && !g_queue_is_empty(queued_requests)) { | 222 if(queued_requests && !g_queue_is_empty(queued_requests)) { |
| 212 queued_dns_request_t *r = g_queue_pop_head(queued_requests); | 223 queued_dns_request_t *r = g_queue_pop_head(queued_requests); |
| 213 req->host = g_strdup(r->params.hostname); | 224 req->host = g_strdup(r->params.hostname); |
| 214 req->port = r->params.port; | 225 req->port = r->params.port; |
| 215 req->socktype = r->params.socktype; | |
| 216 req->callback = r->callback; | 226 req->callback = r->callback; |
| 217 req->data = r->data; | 227 req->data = r->data; |
| 218 | 228 |
| 219 debug_printf("Processing queued DNS query for '%s' with child %d\n", req->host, req->dns_pid); | 229 debug_printf("Processing queued DNS query for '%s' with child %d\n", req->host, req->dns_pid); |
| 220 | 230 |
| 221 if(send_dns_request_to_child(req, &(r->params)) != 0) { | 231 if(send_dns_request_to_child(req, &(r->params)) != 0) { |
| 222 g_free(req->host); | 232 req_free(req); |
| 223 g_free(req); | |
| 224 req = NULL; | 233 req = NULL; |
| 225 number_of_dns_children--; | |
| 226 | |
| 227 debug_printf("Intent of process queued query of '%s' failed, requeing...\n", | 234 debug_printf("Intent of process queued query of '%s' failed, requeing...\n", |
| 228 r->params.hostname); | 235 r->params.hostname); |
| 229 g_queue_push_head(queued_requests, r); | 236 g_queue_push_head(queued_requests, r); |
| 230 } else { | 237 } else { |
| 231 req->inpa = gaim_input_add(req->fd_out, GAIM_INPUT_READ, host_resolved, req); | 238 req->inpa = gaim_input_add(req->fd_out, GAIM_INPUT_READ, host_resolved, req); |
| 274 } | 281 } |
| 275 if(rc==-1) { | 282 if(rc==-1) { |
| 276 char message[1024]; | 283 char message[1024]; |
| 277 g_snprintf(message, sizeof(message), "Error reading from DNS child: %s",strerror(errno)); | 284 g_snprintf(message, sizeof(message), "Error reading from DNS child: %s",strerror(errno)); |
| 278 debug_printf("%s\n",message); | 285 debug_printf("%s\n",message); |
| 279 close(req->fd_out); | |
| 280 req->callback(NULL, 0, req->data, message); | 286 req->callback(NULL, 0, req->data, message); |
| 281 g_free(req->host); | 287 req_free(req); |
| 282 g_free(req); | |
| 283 number_of_dns_children--; | |
| 284 return; | 288 return; |
| 285 } | 289 } |
| 286 if(rc==0) { | 290 if(rc==0) { |
| 287 char message[1024]; | 291 char message[1024]; |
| 288 g_snprintf(message, sizeof(message), "EOF reading from DNS child"); | 292 g_snprintf(message, sizeof(message), "EOF reading from DNS child"); |
| 289 close(req->fd_out); | 293 close(req->fd_out); |
| 290 debug_printf("%s\n",message); | 294 debug_printf("%s\n",message); |
| 291 req->callback(NULL, 0, req->data, message); | 295 req->callback(NULL, 0, req->data, message); |
| 292 g_free(req->host); | 296 req_free(req); |
| 293 g_free(req); | |
| 294 number_of_dns_children--; | |
| 295 return; | 297 return; |
| 296 } | 298 } |
| 297 | 299 |
| 298 /* wait4(req->dns_pid, NULL, WNOHANG, NULL); */ | 300 /* wait4(req->dns_pid, NULL, WNOHANG, NULL); */ |
| 299 | 301 |
| 341 gethostbyname("x.x.x.x.x"); | 343 gethostbyname("x.x.x.x.x"); |
| 342 } | 344 } |
| 343 #endif | 345 #endif |
| 344 } | 346 } |
| 345 | 347 |
| 346 int gaim_gethostbyname_async(const char *hostname, int port, int socktype, dns_callback_t callback, gpointer data) | 348 int gaim_gethostbyname_async(const char *hostname, int port, dns_callback_t callback, gpointer data) |
| 347 { | 349 { |
| 348 pending_dns_request_t *req = NULL; | 350 pending_dns_request_t *req = NULL; |
| 349 dns_params_t dns_params; | 351 dns_params_t dns_params; |
| 350 | 352 |
| 351 strncpy(dns_params.hostname, hostname, sizeof(dns_params.hostname)-1); | 353 strncpy(dns_params.hostname, hostname, sizeof(dns_params.hostname)-1); |
| 352 dns_params.hostname[sizeof(dns_params.hostname)-1] = '\0'; | 354 dns_params.hostname[sizeof(dns_params.hostname)-1] = '\0'; |
| 353 dns_params.port = port; | 355 dns_params.port = port; |
| 354 dns_params.socktype = socktype; | |
| 355 | 356 |
| 356 /* Is there a free available child? */ | 357 /* Is there a free available child? */ |
| 357 while(free_dns_children && !req) { | 358 while(free_dns_children && !req) { |
| 358 GSList *l = free_dns_children; | 359 GSList *l = free_dns_children; |
| 359 free_dns_children = g_slist_remove_link(free_dns_children, l); | 360 free_dns_children = g_slist_remove_link(free_dns_children, l); |
| 360 req = l->data; | 361 req = l->data; |
| 361 g_slist_free(l); | 362 g_slist_free(l); |
| 362 | 363 |
| 363 if(send_dns_request_to_child(req, &dns_params) != 0) { | 364 if(send_dns_request_to_child(req, &dns_params) != 0) { |
| 364 g_free(req); | 365 req_free(req); |
| 365 req = NULL; | 366 req = NULL; |
| 366 number_of_dns_children--; | |
| 367 continue; | 367 continue; |
| 368 } | 368 } |
| 369 | 369 |
| 370 } | 370 } |
| 371 | 371 |
| 450 } | 450 } |
| 451 | 451 |
| 452 #ifdef HAVE_GETADDRINFO | 452 #ifdef HAVE_GETADDRINFO |
| 453 g_snprintf(servname, sizeof(servname), "%d", dns_params.port); | 453 g_snprintf(servname, sizeof(servname), "%d", dns_params.port); |
| 454 memset(&hints,0,sizeof(hints)); | 454 memset(&hints,0,sizeof(hints)); |
| 455 hints.ai_socktype = dns_params.socktype; | 455 |
| 456 /* This is only used to convert a service | |
| 457 * name to a port number. As we know we are | |
| 458 * passing a number already, we know this | |
| 459 * value will not be really used by the C | |
| 460 * library. | |
| 461 */ | |
| 462 hints.ai_socktype = SOCK_STREAM; | |
| 456 rc = getaddrinfo(dns_params.hostname, servname, &hints, &res); | 463 rc = getaddrinfo(dns_params.hostname, servname, &hints, &res); |
| 457 if(rc) { | 464 if(rc) { |
| 458 write(child_out[1], &rc, sizeof(int)); | 465 write(child_out[1], &rc, sizeof(int)); |
| 459 close(child_out[1]); | 466 close(child_out[1]); |
| 460 if(opt_debug) | 467 if(opt_debug) |
| 529 g_free(req->addr); | 536 g_free(req->addr); |
| 530 g_free(req); | 537 g_free(req); |
| 531 return FALSE; | 538 return FALSE; |
| 532 } | 539 } |
| 533 | 540 |
| 534 int gaim_gethostbyname_async(const char *hostname, int port, int socktype, dns_callback_t callback, gpointer data) | 541 int gaim_gethostbyname_async(const char *hostname, int port, dns_callback_t callback, gpointer data) |
| 535 { | 542 { |
| 536 struct sockaddr_in sin; | 543 struct sockaddr_in sin; |
| 537 pending_dns_request_t *req; | 544 pending_dns_request_t *req; |
| 538 | 545 |
| 539 if (!inet_aton(hostname, &sin.sin_addr)) { | 546 if (!inet_aton(hostname, &sin.sin_addr)) { |
| 1183 g_free(phb->host); | 1190 g_free(phb->host); |
| 1184 g_free(phb); | 1191 g_free(phb); |
| 1185 return -1; | 1192 return -1; |
| 1186 } | 1193 } |
| 1187 | 1194 |
| 1188 gaim_gethostbyname_async(connecthost, connectport, SOCK_STREAM, connection_host_resolved, phb); | 1195 gaim_gethostbyname_async(connecthost, connectport, connection_host_resolved, phb); |
| 1189 return 1; | 1196 return 1; |
| 1190 } | 1197 } |
