comparison src/protocols/oscar/conn.c @ 2270:d82efea341ef

[gaim-migrate @ 2280] new libfaim. stupid bugs. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Wed, 12 Sep 2001 00:39:51 +0000
parents 933346315b9b
children 8c75e59e4bdf
comparison
equal deleted inserted replaced
2269:7ff6170d84a0 2270:d82efea341ef
1 1
2 /* 2 /*
3 * aim_conn.c 3 * conn.c
4 * 4 *
5 * Does all this gloriously nifty connection handling stuff... 5 * Does all this gloriously nifty connection handling stuff...
6 * 6 *
7 */ 7 */
8 8
12 #ifndef _WIN32 12 #ifndef _WIN32
13 #include <netdb.h> 13 #include <netdb.h>
14 #include <sys/socket.h> 14 #include <sys/socket.h>
15 #include <netinet/in.h> 15 #include <netinet/in.h>
16 #endif 16 #endif
17
18 /*
19 * In OSCAR, every connection has a set of SNAC groups associated
20 * with it. These are the groups that you can send over this connection
21 * without being guarenteed a "Not supported" SNAC error.
22 *
23 * The grand theory of things says that these associations transcend
24 * what libfaim calls "connection types" (conn->type). You can probably
25 * see the elegance here, but since I want to revel in it for a bit, you
26 * get to hear it all spelled out.
27 *
28 * So let us say that you have your core BOS connection running. One
29 * of your modules has just given you a SNAC of the group 0x0004 to send
30 * you. Maybe an IM destined for some twit in Greenland. So you start
31 * at the top of your connection list, looking for a connection that
32 * claims to support group 0x0004. You find one. Why, that neat BOS
33 * connection of yours can do that. So you send it on its way.
34 *
35 * Now, say, that fellow from Greenland has friends and they all want to
36 * meet up with you in a lame chat room. This has landed you a SNAC
37 * in the family 0x000e and you have to admit you're a bit lost. You've
38 * searched your connection list for someone who wants to make your life
39 * easy and deliver this SNAC for you, but there isn't one there.
40 *
41 * Here comes the good bit. Without even letting anyone know, particularly
42 * the module that decided to send this SNAC, and definitly not that twit
43 * in Greenland, you send out a service request. In this request, you have
44 * marked the need for a connection supporting group 0x000e. A few seconds
45 * later, you receive a service redirect with an IP address and a cookie in
46 * it. Great, you say. Now I have something to do. Off you go, making
47 * that connection. One of the first things you get from this new server
48 * is a message saying that indeed it does support the group you were looking
49 * for. So you continue and send rate confirmation and all that.
50 *
51 * Then you remember you had that SNAC to send, and now you have a means to
52 * do it, and you do, and everyone is happy. Except the Greenlander, who is
53 * still stuck in the bitter cold.
54 *
55 * Oh, and this is useful for building the Migration SNACs, too. In the
56 * future, this may help convince me to implement rate limit mitigation
57 * for real. We'll see.
58 *
59 * Just to make me look better, I'll say that I've known about this great
60 * scheme for quite some time now. But I still haven't convinced myself
61 * to make libfaim work that way. It would take a fair amount of effort,
62 * and probably some client API changes as well. (Whenever I don't want
63 * to do something, I just say it would change the client API. Then I
64 * instantly have a couple of supporters of not doing it.)
65 *
66 * Generally, addgroup is only called by the internal handling of the
67 * server ready SNAC. So if you want to do something before that, you'll
68 * have to be more creative. That is done rather early, though, so I don't
69 * think you have to worry about it. Unless you're me. I care deeply
70 * about such inane things.
71 *
72 */
73 faim_internal void aim_conn_addgroup(aim_conn_t *conn, fu16_t group)
74 {
75 aim_conn_inside_t *ins = (aim_conn_inside_t *)conn->inside;
76 struct snacgroup *sg;
77
78 if (!(sg = malloc(sizeof(struct snacgroup))))
79 return;
80
81 faimdprintf(aim_conn_getsess(conn), 1, "adding group 0x%04x\n", group);
82 sg->group = group;
83
84 sg->next = ins->groups;
85 ins->groups = sg;
86
87 return;
88 }
89
90 faim_export aim_conn_t *aim_conn_findbygroup(aim_session_t *sess, fu16_t group)
91 {
92 aim_conn_t *cur;
93
94 for (cur = sess->connlist; cur; cur = cur->next) {
95 aim_conn_inside_t *ins = (aim_conn_inside_t *)cur->inside;
96 struct snacgroup *sg;
97
98 for (sg = ins->groups; sg; sg = sg->next) {
99 if (sg->group == group)
100 return cur;
101 }
102 }
103
104 return NULL;
105 }
106
107 static struct snacgroup *connkill_snacgroups(struct snacgroup *sg)
108 {
109
110 while (sg) {
111 struct snacgroup *tmp;
112
113 tmp = sg->next;
114 free(sg);
115 sg = tmp;
116 }
117
118 return NULL;
119 }
17 120
18 static void connkill_real(aim_session_t *sess, aim_conn_t **deadconn) 121 static void connkill_real(aim_session_t *sess, aim_conn_t **deadconn)
19 { 122 {
20 123
21 aim_rxqueue_cleanbyconn(sess, *deadconn); 124 aim_rxqueue_cleanbyconn(sess, *deadconn);
36 * This will free ->internal if it necessary... 139 * This will free ->internal if it necessary...
37 */ 140 */
38 if ((*deadconn)->type == AIM_CONN_TYPE_RENDEZVOUS) 141 if ((*deadconn)->type == AIM_CONN_TYPE_RENDEZVOUS)
39 aim_conn_kill_rend(sess, *deadconn); 142 aim_conn_kill_rend(sess, *deadconn);
40 143
144 if ((*deadconn)->inside) {
145 aim_conn_inside_t *inside = (aim_conn_inside_t *)(*deadconn)->inside;
146
147 inside->groups = connkill_snacgroups(inside->groups);
148
149 free(inside);
150 }
151
41 free(*deadconn); 152 free(*deadconn);
42 deadconn = NULL; 153 deadconn = NULL;
43 154
44 return; 155 return;
45 } 156 }
51 * Clears out the connection list and kills any connections left. 162 * Clears out the connection list and kills any connections left.
52 * 163 *
53 */ 164 */
54 static void aim_connrst(aim_session_t *sess) 165 static void aim_connrst(aim_session_t *sess)
55 { 166 {
56
57 faim_mutex_init(&sess->connlistlock);
58 167
59 if (sess->connlist) { 168 if (sess->connlist) {
60 aim_conn_t *cur = sess->connlist, *tmp; 169 aim_conn_t *cur = sess->connlist, *tmp;
61 170
62 while (cur) { 171 while (cur) {
91 deadconn->seqnum = 0; 200 deadconn->seqnum = 0;
92 deadconn->lastactivity = 0; 201 deadconn->lastactivity = 0;
93 deadconn->forcedlatency = 0; 202 deadconn->forcedlatency = 0;
94 deadconn->handlerlist = NULL; 203 deadconn->handlerlist = NULL;
95 deadconn->priv = NULL; 204 deadconn->priv = NULL;
96 faim_mutex_init(&deadconn->active); 205 memset(deadconn->inside, 0, sizeof(aim_conn_inside_t));
97 faim_mutex_init(&deadconn->seqnum_lock);
98 206
99 return; 207 return;
100 } 208 }
101 209
102 /** 210 /**
111 aim_conn_t *newconn; 219 aim_conn_t *newconn;
112 220
113 if (!(newconn = malloc(sizeof(aim_conn_t)))) 221 if (!(newconn = malloc(sizeof(aim_conn_t))))
114 return NULL; 222 return NULL;
115 memset(newconn, 0, sizeof(aim_conn_t)); 223 memset(newconn, 0, sizeof(aim_conn_t));
224
225 if (!(newconn->inside = malloc(sizeof(aim_conn_inside_t)))) {
226 free(newconn);
227 return NULL;
228 }
229 memset(newconn->inside, 0, sizeof(aim_conn_inside_t));
116 230
117 aim_conn_init(newconn); 231 aim_conn_init(newconn);
118 232
119 newconn->next = sess->connlist; 233 newconn->next = sess->connlist;
120 sess->connlist = newconn; 234 sess->connlist = newconn;
166 * 280 *
167 */ 281 */
168 faim_export void aim_conn_close(aim_conn_t *deadconn) 282 faim_export void aim_conn_close(aim_conn_t *deadconn)
169 { 283 {
170 284
171 faim_mutex_destroy(&deadconn->active);
172 faim_mutex_destroy(&deadconn->seqnum_lock);
173 if (deadconn->fd >= 3) 285 if (deadconn->fd >= 3)
174 close(deadconn->fd); 286 close(deadconn->fd);
175 deadconn->fd = -1; 287 deadconn->fd = -1;
176 if (deadconn->handlerlist) 288 if (deadconn->handlerlist)
177 aim_clearhandlers(deadconn); 289 aim_clearhandlers(deadconn);
178 if (deadconn->type == AIM_CONN_TYPE_RENDEZVOUS) 290 if (deadconn->type == AIM_CONN_TYPE_RENDEZVOUS)
179 aim_conn_close_rend((aim_session_t *)deadconn->sessv, deadconn); 291 aim_conn_close_rend((aim_session_t *)deadconn->sessv, deadconn);
180 292
181
182 return; 293 return;
183 } 294 }
184 295
185 /** 296 /**
186 * aim_getconn_type - Find a connection of a specific type 297 * aim_getconn_type - Find a connection of a specific type
189 * 300 *
190 * Searches for a connection of the specified type in the 301 * Searches for a connection of the specified type in the
191 * specified session. Returns the first connection of that 302 * specified session. Returns the first connection of that
192 * type found. 303 * type found.
193 * 304 *
305 * XXX except for RENDEZVOUS, all uses of this should be removed and
306 * use aim_conn_findbygroup() instead.
194 */ 307 */
195 faim_export aim_conn_t *aim_getconn_type(aim_session_t *sess, int type) 308 faim_export aim_conn_t *aim_getconn_type(aim_session_t *sess, int type)
196 { 309 {
197 aim_conn_t *cur; 310 aim_conn_t *cur;
198 311
199 faim_mutex_lock(&sess->connlistlock);
200 for (cur = sess->connlist; cur; cur = cur->next) { 312 for (cur = sess->connlist; cur; cur = cur->next) {
201 if ((cur->type == type) && 313 if ((cur->type == type) &&
202 !(cur->status & AIM_CONN_STATUS_INPROGRESS)) 314 !(cur->status & AIM_CONN_STATUS_INPROGRESS))
203 break; 315 break;
204 } 316 }
205 faim_mutex_unlock(&sess->connlistlock);
206 317
207 return cur; 318 return cur;
208 } 319 }
209 320
210 faim_export aim_conn_t *aim_getconn_type_all(aim_session_t *sess, int type) 321 faim_export aim_conn_t *aim_getconn_type_all(aim_session_t *sess, int type)
211 { 322 {
212 aim_conn_t *cur; 323 aim_conn_t *cur;
213 324
214 faim_mutex_lock(&sess->connlistlock);
215 for (cur = sess->connlist; cur; cur = cur->next) { 325 for (cur = sess->connlist; cur; cur = cur->next) {
216 if (cur->type == type) 326 if (cur->type == type)
217 break; 327 break;
218 } 328 }
219 faim_mutex_unlock(&sess->connlistlock);
220 329
221 return cur; 330 return cur;
222 } 331 }
223 332
224 /* If you pass -1 for the fd, you'll get what you ask for. Gibberish. */ 333 /* If you pass -1 for the fd, you'll get what you ask for. Gibberish. */
225 faim_export aim_conn_t *aim_getconn_fd(aim_session_t *sess, int fd) 334 faim_export aim_conn_t *aim_getconn_fd(aim_session_t *sess, int fd)
226 { 335 {
227 aim_conn_t *cur; 336 aim_conn_t *cur;
228 337
229 faim_mutex_lock(&sess->connlistlock);
230 for (cur = sess->connlist; cur; cur = cur->next) { 338 for (cur = sess->connlist; cur; cur = cur->next) {
231 if (cur->fd == fd) 339 if (cur->fd == fd)
232 break; 340 break;
233 } 341 }
234 faim_mutex_unlock(&sess->connlistlock);
235 342
236 return cur; 343 return cur;
237 } 344 }
238 345
239 /** 346 /**
423 aim_conn_t *conn; 530 aim_conn_t *conn;
424 531
425 if (!(conn = aim_conn_getnext(sess))) 532 if (!(conn = aim_conn_getnext(sess)))
426 return NULL; 533 return NULL;
427 534
428 faim_mutex_lock(&conn->active);
429
430 conn->fd = src->fd; 535 conn->fd = src->fd;
431 conn->type = src->type; 536 conn->type = src->type;
432 conn->subtype = src->subtype; 537 conn->subtype = src->subtype;
433 conn->seqnum = src->seqnum; 538 conn->seqnum = src->seqnum;
434 conn->priv = src->priv; 539 conn->priv = src->priv;
436 conn->lastactivity = src->lastactivity; 541 conn->lastactivity = src->lastactivity;
437 conn->forcedlatency = src->forcedlatency; 542 conn->forcedlatency = src->forcedlatency;
438 conn->sessv = src->sessv; 543 conn->sessv = src->sessv;
439 aim_clonehandlers(sess, conn, src); 544 aim_clonehandlers(sess, conn, src);
440 545
441 faim_mutex_unlock(&conn->active); 546 if (src->inside) {
547 /*
548 * XXX should clone this section as well, but since currently
549 * this function only gets called for some of that rendezvous
550 * crap, and not on SNAC connections, its probably okay for
551 * now.
552 *
553 */
554 }
442 555
443 return conn; 556 return conn;
444 } 557 }
445 558
446 /** 559 /**
465 int i, ret; 578 int i, ret;
466 579
467 if (!(connstruct = aim_conn_getnext(sess))) 580 if (!(connstruct = aim_conn_getnext(sess)))
468 return NULL; 581 return NULL;
469 582
470 faim_mutex_lock(&connstruct->active);
471
472 connstruct->sessv = (void *)sess; 583 connstruct->sessv = (void *)sess;
473 connstruct->type = type; 584 connstruct->type = type;
474 585
475 if (!dest) { /* just allocate a struct */ 586 if (!dest) { /* just allocate a struct */
476 connstruct->fd = -1; 587 connstruct->fd = -1;
477 connstruct->status = 0; 588 connstruct->status = 0;
478 faim_mutex_unlock(&connstruct->active);
479 return connstruct; 589 return connstruct;
480 } 590 }
481 591
482 /* 592 /*
483 * As of 23 Jul 1999, AOL now sends the port number, preceded by a 593 * As of 23 Jul 1999, AOL now sends the port number, preceded by a
501 611
502 if ((ret = aim_proxyconnect(sess, host, port, &connstruct->status)) < 0) { 612 if ((ret = aim_proxyconnect(sess, host, port, &connstruct->status)) < 0) {
503 connstruct->fd = -1; 613 connstruct->fd = -1;
504 connstruct->status = (errno | AIM_CONN_STATUS_CONNERR); 614 connstruct->status = (errno | AIM_CONN_STATUS_CONNERR);
505 free(host); 615 free(host);
506 faim_mutex_unlock(&connstruct->active);
507 return connstruct; 616 return connstruct;
508 } else 617 } else
509 connstruct->fd = ret; 618 connstruct->fd = ret;
510 619
511 faim_mutex_unlock(&connstruct->active);
512
513 free(host); 620 free(host);
514 621
515 return connstruct; 622 return connstruct;
516 } 623 }
517 624
526 faim_export int aim_conngetmaxfd(aim_session_t *sess) 633 faim_export int aim_conngetmaxfd(aim_session_t *sess)
527 { 634 {
528 int j; 635 int j;
529 aim_conn_t *cur; 636 aim_conn_t *cur;
530 637
531 faim_mutex_lock(&sess->connlistlock);
532 for (cur = sess->connlist, j = 0; cur; cur = cur->next) { 638 for (cur = sess->connlist, j = 0; cur; cur = cur->next) {
533 if (cur->fd > j) 639 if (cur->fd > j)
534 j = cur->fd; 640 j = cur->fd;
535 } 641 }
536 faim_mutex_unlock(&sess->connlistlock);
537 642
538 return j; 643 return j;
539 } 644 }
540 645
541 /** 646 /**
549 */ 654 */
550 faim_export int aim_conn_in_sess(aim_session_t *sess, aim_conn_t *conn) 655 faim_export int aim_conn_in_sess(aim_session_t *sess, aim_conn_t *conn)
551 { 656 {
552 aim_conn_t *cur; 657 aim_conn_t *cur;
553 658
554 faim_mutex_lock(&sess->connlistlock);
555 for (cur = sess->connlist; cur; cur = cur->next) { 659 for (cur = sess->connlist; cur; cur = cur->next) {
556 if (cur == conn) { 660 if (cur == conn)
557 faim_mutex_unlock(&sess->connlistlock);
558 return 1; 661 return 1;
559 } 662 }
560 }
561 faim_mutex_unlock(&sess->connlistlock);
562 663
563 return 0; 664 return 0;
564 } 665 }
565 666
566 /** 667 /**
576 * -1 error in select() (%NULL returned) 677 * -1 error in select() (%NULL returned)
577 * 0 no events pending (%NULL returned) 678 * 0 no events pending (%NULL returned)
578 * 1 outgoing data pending (%NULL returned) 679 * 1 outgoing data pending (%NULL returned)
579 * 2 incoming data pending (connection with pending data returned) 680 * 2 incoming data pending (connection with pending data returned)
580 * 681 *
581 * XXX: we could probably stand to do a little courser locking here.
582 *
583 */ 682 */
584 faim_export aim_conn_t *aim_select(aim_session_t *sess, struct timeval *timeout, int *status) 683 faim_export aim_conn_t *aim_select(aim_session_t *sess, struct timeval *timeout, int *status)
585 { 684 {
586 aim_conn_t *cur; 685 aim_conn_t *cur;
587 fd_set fds, wfds; 686 fd_set fds, wfds;
588 int maxfd, i, haveconnecting = 0; 687 int maxfd, i, haveconnecting = 0;
589 688
590 faim_mutex_lock(&sess->connlistlock);
591 if (!sess->connlist) { 689 if (!sess->connlist) {
592 faim_mutex_unlock(&sess->connlistlock);
593 *status = -1; 690 *status = -1;
594 return NULL; 691 return NULL;
595 } 692 }
596 faim_mutex_unlock(&sess->connlistlock);
597 693
598 FD_ZERO(&fds); 694 FD_ZERO(&fds);
599 FD_ZERO(&wfds); 695 FD_ZERO(&wfds);
600 696
601 faim_mutex_lock(&sess->connlistlock);
602 for (cur = sess->connlist, maxfd = 0; cur; cur = cur->next) { 697 for (cur = sess->connlist, maxfd = 0; cur; cur = cur->next) {
603 if (cur->fd == -1) { 698 if (cur->fd == -1) {
604 /* don't let invalid/dead connections sit around */ 699 /* don't let invalid/dead connections sit around */
605 *status = 2; 700 *status = 2;
606 faim_mutex_unlock(&sess->connlistlock);
607 return cur; 701 return cur;
608 } else if (cur->status & AIM_CONN_STATUS_INPROGRESS) { 702 } else if (cur->status & AIM_CONN_STATUS_INPROGRESS) {
609 FD_SET(cur->fd, &wfds); 703 FD_SET(cur->fd, &wfds);
610 704
611 haveconnecting++; 705 haveconnecting++;
612 } 706 }
613 FD_SET(cur->fd, &fds); 707 FD_SET(cur->fd, &fds);
614 if (cur->fd > maxfd) 708 if (cur->fd > maxfd)
615 maxfd = cur->fd; 709 maxfd = cur->fd;
616 } 710 }
617 faim_mutex_unlock(&sess->connlistlock);
618 711
619 /* 712 /*
620 * If we have data waiting to be sent, return 713 * If we have data waiting to be sent, return
621 * 714 *
622 * We have to not do this if theres at least one 715 * We have to not do this if theres at least one
634 *status = 1; 727 *status = 1;
635 return NULL; 728 return NULL;
636 } 729 }
637 730
638 if ((i = select(maxfd+1, &fds, &wfds, NULL, timeout))>=1) { 731 if ((i = select(maxfd+1, &fds, &wfds, NULL, timeout))>=1) {
639 faim_mutex_lock(&sess->connlistlock);
640 for (cur = sess->connlist; cur; cur = cur->next) { 732 for (cur = sess->connlist; cur; cur = cur->next) {
641 if ((FD_ISSET(cur->fd, &fds)) || 733 if ((FD_ISSET(cur->fd, &fds)) ||
642 ((cur->status & AIM_CONN_STATUS_INPROGRESS) && 734 ((cur->status & AIM_CONN_STATUS_INPROGRESS) &&
643 FD_ISSET(cur->fd, &wfds))) { 735 FD_ISSET(cur->fd, &wfds))) {
644 *status = 2; 736 *status = 2;
645 faim_mutex_unlock(&sess->connlistlock); 737 return cur;
646 return cur; /* XXX race condition here -- shouldnt unlock connlist */
647 } 738 }
648 } 739 }
649 *status = 0; /* shouldn't happen */ 740 *status = 0; /* shouldn't happen */
650 } else if ((i == -1) && (errno == EINTR)) /* treat interrupts as a timeout */ 741 } else if ((i == -1) && (errno == EINTR)) /* treat interrupts as a timeout */
651 *status = 0; 742 *status = 0;
652 else 743 else
653 *status = i; /* can be 0 or -1 */ 744 *status = i; /* can be 0 or -1 */
654 745
655 faim_mutex_unlock(&sess->connlistlock);
656
657 return NULL; /* no waiting or error, return */ 746 return NULL; /* no waiting or error, return */
658 } 747 }
659 748
660 /** 749 /**
661 * aim_conn_setlatency - Set a forced latency value for connection 750 * aim_conn_setlatency - Set a forced latency value for connection
675 { 764 {
676 765
677 if (!conn) 766 if (!conn)
678 return -1; 767 return -1;
679 768
680 faim_mutex_lock(&conn->active);
681 conn->forcedlatency = newval; 769 conn->forcedlatency = newval;
682 conn->lastactivity = 0; /* reset this just to make sure */ 770 conn->lastactivity = 0; /* reset this just to make sure */
683 faim_mutex_unlock(&conn->active);
684 771
685 return 0; 772 return 0;
686 } 773 }
687 774
688 /** 775 /**