Mercurial > pidgin.yaz
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 } |