| 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); |
| 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 /** |
| 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 |