| 127 /* debug_printf("CLOSURE: removing input watcher %d\n", tag); */ |
129 /* debug_printf("CLOSURE: removing input watcher %d\n", tag); */ |
| 128 if (tag > 0) |
130 if (tag > 0) |
| 129 g_source_remove(tag); |
131 g_source_remove(tag); |
| 130 } |
132 } |
| 131 |
133 |
| 132 static struct sockaddr_in *gaim_gethostbyname(char *host, int port) |
134 |
| 133 { |
135 typedef void (*dns_callback_t)(struct sockaddr *addr, size_t addrlen, |
| 134 static struct sockaddr_in sin; |
136 gpointer data, const char *error_message); |
| 135 |
137 |
| 136 if (!inet_aton(host, &sin.sin_addr)) { |
138 #ifdef __unix__ |
| |
139 |
| |
140 /* This structure represents both a pending DNS request and |
| |
141 * a free child process. |
| |
142 */ |
| |
143 typedef struct { |
| |
144 char *host; |
| |
145 int port; |
| |
146 int socktype; |
| |
147 dns_callback_t callback; |
| |
148 gpointer data; |
| |
149 gint inpa; |
| |
150 int fd_in, fd_out; |
| |
151 pid_t dns_pid; |
| |
152 } pending_dns_request_t; |
| |
153 |
| |
154 static GSList *free_dns_children = NULL; |
| |
155 static GQueue *queued_requests = NULL; |
| |
156 |
| |
157 static int number_of_dns_children = 0; |
| |
158 |
| |
159 const int MAX_DNS_CHILDREN = 2; |
| |
160 |
| |
161 typedef struct { |
| |
162 char hostname[512]; |
| |
163 int port; |
| |
164 int socktype; |
| |
165 } dns_params_t; |
| |
166 |
| |
167 typedef struct { |
| |
168 dns_params_t params; |
| |
169 dns_callback_t callback; |
| |
170 gpointer data; |
| |
171 } queued_dns_request_t; |
| |
172 |
| |
173 static int send_dns_request_to_child(pending_dns_request_t *req, dns_params_t *dns_params) |
| |
174 { |
| |
175 char ch; |
| |
176 int rc; |
| |
177 |
| |
178 /* Are you alive? */ |
| |
179 if(kill(req->dns_pid, 0) != 0) { |
| |
180 debug_printf("DNS child %d no longer exists\n", req->dns_pid); |
| |
181 return -1; |
| |
182 } |
| |
183 |
| |
184 /* Let's contact this lost child! */ |
| |
185 rc = write(req->fd_in, dns_params, sizeof(*dns_params)); |
| |
186 if(rc<0) { |
| |
187 debug_printf("Error writing to DNS child %d: %s\n", req->dns_pid, strerror(errno)); |
| |
188 return -1; |
| |
189 } |
| |
190 |
| |
191 g_return_val_if_fail(rc == sizeof(*dns_params), -1); |
| |
192 |
| |
193 /* Did you hear me? (This avoids some race conditions) */ |
| |
194 rc = read(req->fd_out, &ch, 1); |
| |
195 if(rc != 1 || ch!='Y') { |
| |
196 debug_printf("DNS child %d not responding: killing it!\n", req->dns_pid); |
| |
197 kill(req->dns_pid, SIGKILL); |
| |
198 return -1; |
| |
199 } |
| |
200 |
| |
201 debug_printf("Successfuly sent DNS request to child %d\n", req->dns_pid); |
| |
202 return 0; |
| |
203 } |
| |
204 |
| |
205 static void host_resolved(gpointer data, gint source, GaimInputCondition cond); |
| |
206 |
| |
207 static void release_dns_child(pending_dns_request_t *req) |
| |
208 { |
| |
209 g_free(req->host); |
| |
210 |
| |
211 if(queued_requests && !g_queue_is_empty(queued_requests)) { |
| |
212 queued_dns_request_t *r = g_queue_pop_head(queued_requests); |
| |
213 req->host = g_strdup(r->params.hostname); |
| |
214 req->port = r->params.port; |
| |
215 req->socktype = r->params.socktype; |
| |
216 req->callback = r->callback; |
| |
217 req->data = r->data; |
| |
218 |
| |
219 debug_printf("Processing queued DNS query for '%s' with child %d\n", req->host, req->dns_pid); |
| |
220 |
| |
221 if(send_dns_request_to_child(req, &(r->params)) != 0) { |
| |
222 g_free(req->host); |
| |
223 g_free(req); |
| |
224 req = NULL; |
| |
225 number_of_dns_children--; |
| |
226 |
| |
227 debug_printf("Intent of process queued query of '%s' failed, requeing...\n", |
| |
228 r->params.hostname); |
| |
229 g_queue_push_head(queued_requests, r); |
| |
230 } else { |
| |
231 req->inpa = gaim_input_add(req->fd_out, GAIM_INPUT_READ, host_resolved, req); |
| |
232 g_free(r); |
| |
233 } |
| |
234 |
| |
235 } else { |
| |
236 req->host = NULL; |
| |
237 req->callback = NULL; |
| |
238 req->data = NULL; |
| |
239 free_dns_children = g_slist_append(free_dns_children, req); |
| |
240 } |
| |
241 } |
| |
242 |
| |
243 static void host_resolved(gpointer data, gint source, GaimInputCondition cond) |
| |
244 { |
| |
245 pending_dns_request_t *req = (pending_dns_request_t*)data; |
| |
246 int rc, err; |
| |
247 struct sockaddr *addr = NULL; |
| |
248 socklen_t addrlen; |
| |
249 |
| |
250 debug_printf("Host '%s' resolved\n", req->host); |
| |
251 gaim_input_remove(req->inpa); |
| |
252 |
| |
253 rc=read(req->fd_out, &err, sizeof(err)); |
| |
254 if((rc==4) && (err!=0)) { |
| |
255 char message[1024]; |
| |
256 g_snprintf(message, sizeof(message), "DNS error: %s (pid=%d)", |
| |
257 #ifdef HAVE_GETADDRINFO |
| |
258 gai_strerror(err), |
| |
259 #else |
| |
260 hstrerror(err), |
| |
261 #endif |
| |
262 req->dns_pid); |
| |
263 debug_printf("%s\n",message); |
| |
264 req->callback(NULL, 0, req->data, message); |
| |
265 release_dns_child(req); |
| |
266 return; |
| |
267 } |
| |
268 if(G_LIKELY(rc>0)) { |
| |
269 rc=read(req->fd_out, &addrlen, sizeof(addrlen)); |
| |
270 if(G_LIKELY(rc>0)) { |
| |
271 addr=g_malloc(addrlen); |
| |
272 rc=read(req->fd_out, addr, addrlen); |
| |
273 } |
| |
274 } |
| |
275 if(G_UNLIKELY(rc==-1)) { |
| |
276 char message[1024]; |
| |
277 g_snprintf(message, sizeof(message), "Error reading from DNS child: %s",strerror(errno)); |
| |
278 debug_printf("%s\n",message); |
| |
279 close(req->fd_out); |
| |
280 req->callback(NULL, 0, req->data, message); |
| |
281 g_free(req->host); |
| |
282 g_free(req); |
| |
283 number_of_dns_children--; |
| |
284 return; |
| |
285 } |
| |
286 if(G_UNLIKELY(rc==0)) { |
| |
287 char message[1024]; |
| |
288 g_snprintf(message, sizeof(message), "EOF reading from DNS child"); |
| |
289 close(req->fd_out); |
| |
290 debug_printf("%s\n",message); |
| |
291 req->callback(NULL, 0, req->data, message); |
| |
292 g_free(req->host); |
| |
293 g_free(req); |
| |
294 number_of_dns_children--; |
| |
295 return; |
| |
296 } |
| |
297 |
| |
298 /* wait4(req->dns_pid, NULL, WNOHANG, NULL); */ |
| |
299 |
| |
300 req->callback(addr, addrlen, req->data, NULL); |
| |
301 |
| |
302 g_free(addr); |
| |
303 |
| |
304 release_dns_child(req); |
| |
305 } |
| |
306 |
| |
307 static void trap_gdb_bug() |
| |
308 { |
| |
309 const char *message = |
| |
310 "Gaim's DNS child got a SIGTRAP signal. \n" |
| |
311 "This can be caused by trying to run gaim into gdb.\n" |
| |
312 "There's a known gdb bug which prevent this, supposedly gaim\n" |
| |
313 "should have detected you were using gdb and use an ugly hack,\n" |
| |
314 "check cope_with_gdb_brokenness() in proxy.c.\n\n" |
| |
315 "For more info about the bug check http://sources.redhat.com/ml/gdb/2001-07/msg00349.html\n"; |
| |
316 fputs("\n* * *\n",stderr); |
| |
317 fputs(message,stderr); |
| |
318 fputs("* * *\n\n",stderr); |
| |
319 execlp("xmessage","xmessage","-center", message, NULL); |
| |
320 _exit(1); |
| |
321 } |
| |
322 |
| |
323 static void cope_with_gdb_brokenness() |
| |
324 { |
| |
325 static gboolean already_done = FALSE; |
| |
326 char s[300], e[300]; |
| |
327 int n; |
| |
328 pid_t ppid; |
| |
329 |
| |
330 #ifdef __linux__ |
| |
331 if(already_done) |
| |
332 return; |
| |
333 already_done = TRUE; |
| |
334 ppid = getppid(); |
| |
335 sprintf(s,"/proc/%d/exe", ppid); |
| |
336 n = readlink(s, e, sizeof(e)); |
| |
337 e[MAX(n,sizeof(e)-1)] = '\0'; |
| |
338 |
| |
339 if(strstr(e,"gdb")) { |
| |
340 debug_printf("Debugger detected, performing useless query...\n"); |
| |
341 gethostbyname("x.x.x.x.x"); |
| |
342 } |
| |
343 #endif |
| |
344 } |
| |
345 |
| |
346 int gaim_gethostbyname_async(const char *hostname, int port, int socktype, dns_callback_t callback, gpointer data) |
| |
347 { |
| |
348 pending_dns_request_t *req = NULL; |
| |
349 dns_params_t dns_params; |
| |
350 |
| |
351 strncpy(dns_params.hostname, hostname, sizeof(dns_params.hostname)-1); |
| |
352 dns_params.hostname[sizeof(dns_params.hostname)-1] = '\0'; |
| |
353 dns_params.port = port; |
| |
354 dns_params.socktype = socktype; |
| |
355 |
| |
356 /* Is there a free available child? */ |
| |
357 while(free_dns_children && !req) { |
| |
358 GSList *l = free_dns_children; |
| |
359 free_dns_children = g_slist_remove_link(free_dns_children, l); |
| |
360 req = l->data; |
| |
361 g_slist_free(l); |
| |
362 |
| |
363 if(send_dns_request_to_child(req, &dns_params) != 0) { |
| |
364 g_free(req); |
| |
365 req = NULL; |
| |
366 number_of_dns_children--; |
| |
367 continue; |
| |
368 } |
| |
369 |
| |
370 } |
| |
371 |
| |
372 if(!req) { |
| |
373 int child_out[2], child_in[2]; |
| |
374 |
| |
375 if(number_of_dns_children >= MAX_DNS_CHILDREN) { |
| |
376 queued_dns_request_t *r = g_new(queued_dns_request_t, 1); |
| |
377 memcpy(&(r->params), &dns_params, sizeof(dns_params)); |
| |
378 r->callback = callback; |
| |
379 r->data = data; |
| |
380 if(!queued_requests) |
| |
381 queued_requests = g_queue_new(); |
| |
382 g_queue_push_tail(queued_requests, r); |
| |
383 debug_printf("DNS query for '%s' queued\n", hostname); |
| |
384 return 0; |
| |
385 } |
| |
386 |
| |
387 if(pipe(child_out) || pipe(child_in)) { |
| |
388 debug_printf("Could not create pipes: %s",strerror(errno)); |
| |
389 return -1; |
| |
390 } |
| |
391 |
| |
392 /* We need to create a new child. */ |
| |
393 req = g_new(pending_dns_request_t,1); |
| |
394 |
| |
395 cope_with_gdb_brokenness(); |
| |
396 |
| |
397 req->dns_pid=fork(); |
| |
398 if(req->dns_pid==0) { |
| |
399 const int zero = 0; |
| |
400 #ifdef HAVE_GETADDRINFO |
| |
401 struct addrinfo hints, *res; |
| |
402 char servname[20]; |
| |
403 int rc; |
| |
404 #else |
| |
405 struct sockaddr_in sin; |
| |
406 const socklen_t addrlen = sizeof(sin); |
| |
407 #endif |
| |
408 #ifdef HAVE_SIGNAL_H |
| |
409 signal(SIGHUP, SIG_DFL); |
| |
410 signal(SIGINT, SIG_DFL); |
| |
411 signal(SIGQUIT, SIG_DFL); |
| |
412 signal(SIGCHLD, SIG_DFL); |
| |
413 signal(SIGTERM, SIG_DFL); |
| |
414 signal(SIGTRAP, trap_gdb_bug); |
| |
415 #endif |
| |
416 |
| |
417 |
| |
418 close(child_out[0]); |
| |
419 close(child_in[1]); |
| |
420 |
| |
421 while(1) { |
| |
422 if(dns_params.hostname[0] == '\0') { |
| |
423 const char Y = 'Y'; |
| |
424 fd_set fds; |
| |
425 struct timeval tv = { .tv_sec = 40 , .tv_usec = 0 }; |
| |
426 FD_ZERO(&fds); |
| |
427 FD_SET(child_in[0], &fds); |
| |
428 rc = select(child_in[0]+1, &fds, NULL, NULL, &tv); |
| |
429 if(!rc) { |
| |
430 if(opt_debug) |
| |
431 fprintf(stderr,"dns[%d]: nobody needs me... =(\n", getpid()); |
| |
432 break; |
| |
433 } |
| |
434 rc = read(child_in[0], &dns_params, sizeof(dns_params)); |
| |
435 if(rc < 0) { |
| |
436 perror("read()"); |
| |
437 break; |
| |
438 } |
| |
439 if(rc==0) { |
| |
440 if(opt_debug) |
| |
441 fprintf(stderr,"dns[%d]: Ops, father has gone, wait for me, wait...!\n", getpid()); |
| |
442 _exit(0); |
| |
443 } |
| |
444 if(dns_params.hostname[0] == '\0') { |
| |
445 fprintf(stderr, "dns[%d]: hostname = \"\" (port = %d)!!!\n", getpid(), dns_params.port); |
| |
446 _exit(1); |
| |
447 } |
| |
448 write(child_out[1], &Y, 1); |
| |
449 } |
| |
450 |
| |
451 #ifdef HAVE_GETADDRINFO |
| |
452 g_snprintf(servname, sizeof(servname), "%d", dns_params.port); |
| |
453 memset(&hints,0,sizeof(hints)); |
| |
454 hints.ai_socktype = dns_params.socktype; |
| |
455 rc = getaddrinfo(dns_params.hostname, servname, &hints, &res); |
| |
456 if(rc) { |
| |
457 write(child_out[1], &rc, sizeof(int)); |
| |
458 close(child_out[1]); |
| |
459 if(opt_debug) |
| |
460 fprintf(stderr,"dns[%d] Error: getaddrinfo returned %d\n", |
| |
461 getpid(), rc); |
| |
462 dns_params.hostname[0] = '\0'; |
| |
463 continue; |
| |
464 } |
| |
465 write(child_out[1], &zero, sizeof(zero)); |
| |
466 write(child_out[1], &(res->ai_addrlen), sizeof(res->ai_addrlen)); |
| |
467 write(child_out[1], res->ai_addr, res->ai_addrlen); |
| |
468 freeaddrinfo(res); |
| |
469 #else |
| |
470 if (!inet_aton(hostname, &sin.sin_addr)) { |
| |
471 struct hostent *hp; |
| |
472 if(!(hp = gethostbyname(dns_params.hostname))) { |
| |
473 write(child_out[1], &h_errno, sizeof(int)); |
| |
474 close(child_out[1]); |
| |
475 if(opt_debug) |
| |
476 fprintf(stderr,"DNS Error: %s\n",hstrerror(h_errno)); |
| |
477 _exit(0); |
| |
478 } |
| |
479 memset(&sin, 0, sizeof(struct sockaddr_in)); |
| |
480 memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); |
| |
481 sin.sin_family = hp->h_addrtype; |
| |
482 } else |
| |
483 sin.sin_family = AF_INET; |
| |
484 sin.sin_port = htons(dns_params.port); |
| |
485 write(child_out[1], &zero, sizeof(zero)); |
| |
486 write(child_out[1], &addrlen, sizeof(addrlen)); |
| |
487 write(child_out[1], &sin, addrlen); |
| |
488 #endif |
| |
489 dns_params.hostname[0] = '\0'; |
| |
490 } |
| |
491 close(child_out[1]); |
| |
492 close(child_in[0]); |
| |
493 _exit(0); |
| |
494 } |
| |
495 close(child_out[1]); |
| |
496 close(child_in[0]); |
| |
497 if(req->dns_pid==-1) { |
| |
498 debug_printf("Could not create child process for DNS: %s\n",strerror(errno)); |
| |
499 g_free(req); |
| |
500 return -1; |
| |
501 } |
| |
502 req->fd_in = child_in[1]; |
| |
503 req->fd_out = child_out[0]; |
| |
504 number_of_dns_children++; |
| |
505 debug_printf("Created new DNS child %d, there are now %d children.\n", |
| |
506 req->dns_pid, number_of_dns_children); |
| |
507 } |
| |
508 req->host=g_strdup(hostname); |
| |
509 req->port=port; |
| |
510 req->callback=callback; |
| |
511 req->data=data; |
| |
512 req->inpa = gaim_input_add(req->fd_out, GAIM_INPUT_READ, host_resolved, req); |
| |
513 return 0; |
| |
514 } |
| |
515 #else |
| |
516 |
| |
517 typedef struct { |
| |
518 gpointer data; |
| |
519 size_t addrlen; |
| |
520 struct sockaddr *addr; |
| |
521 dns_callback_t callback; |
| |
522 } pending_dns_request_t; |
| |
523 |
| |
524 static gboolean host_resolved(gpointer data) |
| |
525 { |
| |
526 pending_dns_request_t *req = (pending_dns_request_t*)data; |
| |
527 req->callback(req->addr, req->addrlen, req->data, NULL); |
| |
528 g_free(req->addr); |
| |
529 g_free(req); |
| |
530 return FALSE; |
| |
531 } |
| |
532 |
| |
533 int gaim_gethostbyname_async(const char *hostname, int port, int socktype, dns_callback_t callback, gpointer data) |
| |
534 { |
| |
535 struct sockaddr_in sin; |
| |
536 pending_dns_request_t *req; |
| |
537 |
| |
538 if (!inet_aton(hostname, &sin.sin_addr)) { |
| 137 struct hostent *hp; |
539 struct hostent *hp; |
| 138 if(!(hp = gethostbyname(host))) { |
540 if(!(hp = gethostbyname(hostname))) { |
| 139 debug_printf("gaim_gethostbyname(\"%s\", %d) failed: %s", |
541 debug_printf("gaim_gethostbyname(\"%s\", %d) failed: %s", |
| 140 host, port, hstrerror(h_errno)); |
542 hostname, port, hstrerror(h_errno)); |
| 141 return NULL; |
543 return -1; |
| 142 } |
544 } |
| 143 memset(&sin, 0, sizeof(struct sockaddr_in)); |
545 memset(&sin, 0, sizeof(struct sockaddr_in)); |
| 144 memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); |
546 memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); |
| 145 sin.sin_family = hp->h_addrtype; |
547 sin.sin_family = hp->h_addrtype; |
| 146 } else |
548 } else |
| 147 sin.sin_family = AF_INET; |
549 sin.sin_family = AF_INET; |
| 148 sin.sin_port = htons(port); |
550 sin.sin_port = htons(port); |
| 149 |
551 |
| 150 return &sin; |
552 req = g_new(pending_dns_request_t, 1); |
| 151 } |
553 req->addr = (struct sockaddr*) g_memdup(&sin, sizeof(sin)); |
| |
554 req->addrlen = sizeof(sin); |
| |
555 req->data = data; |
| |
556 req->callback = callback; |
| |
557 g_timeout_add(10, host_resolved, req); |
| |
558 return 0; |
| |
559 } |
| |
560 |
| |
561 #endif |
| 152 |
562 |
| 153 static void no_one_calls(gpointer data, gint source, GaimInputCondition cond) |
563 static void no_one_calls(gpointer data, gint source, GaimInputCondition cond) |
| 154 { |
564 { |
| 155 struct PHB *phb = data; |
565 struct PHB *phb = data; |
| 156 unsigned int len; |
566 unsigned int len; |
| 161 len = sizeof(error); |
571 len = sizeof(error); |
| 162 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { |
572 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { |
| 163 close(source); |
573 close(source); |
| 164 gaim_input_remove(phb->inpa); |
574 gaim_input_remove(phb->inpa); |
| 165 phb->func(phb->data, -1, GAIM_INPUT_READ); |
575 phb->func(phb->data, -1, GAIM_INPUT_READ); |
| |
576 g_free(phb->host); |
| 166 g_free(phb); |
577 g_free(phb); |
| 167 return; |
578 return; |
| 168 } |
579 } |
| 169 fcntl(source, F_SETFL, 0); |
580 fcntl(source, F_SETFL, 0); |
| 170 gaim_input_remove(phb->inpa); |
581 gaim_input_remove(phb->inpa); |
| 171 phb->func(phb->data, source, GAIM_INPUT_READ); |
582 phb->func(phb->data, source, GAIM_INPUT_READ); |
| |
583 g_free(phb->host); |
| 172 g_free(phb); |
584 g_free(phb); |
| 173 } |
585 } |
| 174 |
586 |
| 175 static gboolean clean_connect(gpointer data) |
587 static gboolean clean_connect(gpointer data) |
| 176 { |
588 { |
| 177 struct PHB *phb = data; |
589 struct PHB *phb = data; |
| 178 |
590 |
| 179 phb->func(phb->data, phb->port, GAIM_INPUT_READ); |
591 phb->func(phb->data, phb->port, GAIM_INPUT_READ); |
| |
592 g_free(phb->host); |
| 180 g_free(phb); |
593 g_free(phb); |
| 181 |
594 |
| 182 return FALSE; |
595 return FALSE; |
| 183 } |
596 } |
| 184 |
597 |
| 185 |
598 |
| 186 static int proxy_connect_none(char *host, unsigned short port, struct PHB *phb) |
599 static int proxy_connect_none(struct PHB *phb, struct sockaddr *addr, socklen_t addrlen) |
| 187 { |
600 { |
| 188 struct sockaddr_in *sin; |
|
| 189 int fd = -1; |
601 int fd = -1; |
| 190 |
602 |
| 191 debug_printf("connecting to %s:%d with no proxy\n", host, port); |
603 debug_printf("connecting to %s:%d with no proxy\n", phb->host, phb->port); |
| 192 |
604 |
| 193 if (!(sin = gaim_gethostbyname(host, port))) { |
605 if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) { |
| 194 debug_printf("gethostbyname failed\n"); |
606 debug_printf("unable to create socket: %s\n", strerror(errno)); |
| |
607 g_free(phb->host); |
| 195 g_free(phb); |
608 g_free(phb); |
| 196 return -1; |
609 return -1; |
| 197 } |
610 } |
| 198 |
|
| 199 if ((fd = socket(sin->sin_family, SOCK_STREAM, 0)) < 0) { |
|
| 200 debug_printf("unable to create socket\n"); |
|
| 201 g_free(phb); |
|
| 202 return -1; |
|
| 203 } |
|
| 204 fcntl(fd, F_SETFL, O_NONBLOCK); |
611 fcntl(fd, F_SETFL, O_NONBLOCK); |
| 205 |
612 |
| 206 if (connect(fd, (struct sockaddr *)sin, sizeof(*sin)) < 0) { |
613 if (connect(fd, (struct sockaddr *)addr, addrlen) < 0) { |
| 207 if ((errno == EINPROGRESS) || (errno == EINTR)) { |
614 if ((errno == EINPROGRESS) || (errno == EINTR)) { |
| 208 debug_printf("Connect would have blocked\n"); |
615 debug_printf("Connect would have blocked\n"); |
| 209 phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, no_one_calls, phb); |
616 phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, no_one_calls, phb); |
| 210 } else { |
617 } else { |
| 211 debug_printf("connect failed (errno %d)\n", errno); |
618 debug_printf("connect failed (errno %d)\n", errno); |
| 212 close(fd); |
619 close(fd); |
| |
620 g_free(phb->host); |
| 213 g_free(phb); |
621 g_free(phb); |
| 214 return -1; |
622 return -1; |
| 215 } |
623 } |
| 216 } else { |
624 } else { |
| 217 unsigned int len; |
625 unsigned int len; |
| 287 phb->func(phb->data, -1, GAIM_INPUT_READ); |
714 phb->func(phb->data, -1, GAIM_INPUT_READ); |
| 288 g_free(phb->host); |
715 g_free(phb->host); |
| 289 g_free(phb); |
716 g_free(phb); |
| 290 return; |
717 return; |
| 291 } |
718 } |
| 292 fcntl(source, F_SETFL, 0); |
719 request_len = g_snprintf(request, sizeof(request), "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n", phb->host, phb->port, |
| 293 g_snprintf(cmd, sizeof(cmd), "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n", phb->host, phb->port, |
|
| 294 phb->host, phb->port); |
720 phb->host, phb->port); |
| 295 if (send(source, cmd, strlen(cmd), 0) < 0) { |
|
| 296 close(source); |
|
| 297 phb->func(phb->data, -1, GAIM_INPUT_READ); |
|
| 298 g_free(phb->host); |
|
| 299 g_free(phb); |
|
| 300 return; |
|
| 301 } |
|
| 302 |
721 |
| 303 if (proxyuser) { |
722 if (proxyuser) { |
| 304 char *t1, *t2; |
723 char *t1, *t2; |
| 305 t1 = g_strdup_printf("%s:%s", proxyuser, proxypass); |
724 t1 = g_strdup_printf("%s:%s", proxyuser, proxypass); |
| 306 t2 = tobase64(t1); |
725 t2 = tobase64(t1); |
| 307 g_free(t1); |
726 g_free(t1); |
| 308 g_snprintf(cmd, sizeof(cmd), "Proxy-Authorization: Basic %s\r\n", t2); |
727 g_return_if_fail(request_len < sizeof(request)); |
| |
728 request_len += g_snprintf(request + request_len, sizeof(request) - request_len, "Proxy-Authorization: Basic %s\r\n", t2); |
| 309 g_free(t2); |
729 g_free(t2); |
| 310 if (send(source, cmd, strlen(cmd), 0) < 0) { |
730 } |
| 311 close(source); |
731 |
| 312 phb->func(phb->data, -1, GAIM_INPUT_READ); |
732 g_return_if_fail(request_len < sizeof(request)); |
| 313 g_free(phb->host); |
733 strcpy(request + request_len, "\r\n"); |
| 314 g_free(phb); |
734 request_len += 2; |
| 315 return; |
735 |
| 316 } |
736 if (write(source, request, request_len) < 0) { |
| 317 } |
|
| 318 |
|
| 319 g_snprintf(cmd, sizeof(cmd), "\r\n"); |
|
| 320 if (send(source, cmd, strlen(cmd), 0) < 0) { |
|
| 321 close(source); |
737 close(source); |
| 322 phb->func(phb->data, -1, GAIM_INPUT_READ); |
738 phb->func(phb->data, -1, GAIM_INPUT_READ); |
| 323 g_free(phb->host); |
739 g_free(phb->host); |
| 324 g_free(phb); |
740 g_free(phb); |
| 325 return; |
741 return; |
| 326 } |
742 } |
| 327 |
743 |
| 328 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, http_canread, phb); |
744 phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, http_canread, phb); |
| 329 } |
745 } |
| 330 |
746 |
| 331 static int proxy_connect_http(char *host, unsigned short port, struct PHB *phb) |
747 static int proxy_connect_http(struct PHB *phb, struct sockaddr *addr, socklen_t addrlen) |
| 332 { |
748 { |
| 333 struct sockaddr_in *sin; |
|
| 334 int fd = -1; |
749 int fd = -1; |
| 335 |
750 |
| 336 debug_printf("connecting to %s:%d via %s:%d using HTTP\n", host, port, proxyhost, proxyport); |
751 debug_printf("connecting to %s:%d via %s:%d using HTTP\n", phb->host, phb->port, proxyhost, proxyport); |
| 337 |
752 |
| 338 if (!(sin = gaim_gethostbyname(proxyhost, proxyport))) { |
753 if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) { |
| |
754 g_free(phb->host); |
| 339 g_free(phb); |
755 g_free(phb); |
| 340 return -1; |
756 return -1; |
| 341 } |
757 } |
| 342 |
758 |
| 343 if ((fd = socket(sin->sin_family, SOCK_STREAM, 0)) < 0) { |
|
| 344 g_free(phb); |
|
| 345 return -1; |
|
| 346 } |
|
| 347 |
|
| 348 phb->host = g_strdup(host); |
|
| 349 phb->port = port; |
|
| 350 |
|
| 351 fcntl(fd, F_SETFL, O_NONBLOCK); |
759 fcntl(fd, F_SETFL, O_NONBLOCK); |
| 352 |
760 |
| 353 if (connect(fd, (struct sockaddr *)sin, sizeof(*sin)) < 0) { |
761 if (connect(fd, addr, addrlen) < 0) { |
| 354 if ((errno == EINPROGRESS) || (errno == EINTR)) { |
762 if ((errno == EINPROGRESS) || (errno == EINTR)) { |
| 355 debug_printf("Connect would have blocked\n"); |
763 debug_printf("Connect would have blocked\n"); |
| 356 phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, http_canwrite, phb); |
764 phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, http_canwrite, phb); |
| 357 } else { |
765 } else { |
| 358 close(fd); |
766 close(fd); |