]> andersk Git - libfaim.git/blob - aim_conn.c
- Fri Jun 30 00:04:47 UTC 2000
[libfaim.git] / aim_conn.c
1
2 /*
3  *  aim_conn.c
4  *
5  * Does all this gloriously nifty connection handling stuff...
6  *
7  */
8
9 #include <faim/aim.h> 
10
11 /*
12  * Clears out connection list, killing remaining connections.
13  */
14 void aim_connrst(struct aim_session_t *sess)
15 {
16   faim_mutex_init(&sess->connlistlock, NULL);
17   if (sess->connlist) {
18     struct aim_conn_t *cur = sess->connlist, *tmp;
19
20     while(cur) {
21       tmp = cur->next;
22       aim_conn_close(cur);
23       free(cur);
24       cur = tmp;
25     }
26   }
27   sess->connlist = NULL;
28   return;
29 }
30
31 /*
32  * Gets a new connection structure.
33  */
34 struct aim_conn_t *aim_conn_getnext(struct aim_session_t *sess)
35 {
36   struct aim_conn_t *newconn, *cur;
37
38   if (!(newconn = malloc(sizeof(struct aim_conn_t))))   
39     return NULL;
40
41   memset(newconn, 0, sizeof(struct aim_conn_t));
42   aim_conn_close(newconn);
43   newconn->next = NULL;
44
45   faim_mutex_lock(&sess->connlistlock);
46   if (sess->connlist == NULL)
47     sess->connlist = newconn;
48   else {
49     for (cur = sess->connlist; cur->next; cur = cur->next)
50       ;
51     cur->next = newconn;
52   }
53   faim_mutex_unlock(&sess->connlistlock);
54
55   return newconn;
56 }
57
58 void aim_conn_kill(struct aim_session_t *sess, struct aim_conn_t **deadconn)
59 {
60   struct aim_conn_t *cur;
61
62   if (!deadconn || !*deadconn)  
63     return;
64
65   faim_mutex_lock(&sess->connlistlock);
66   if (sess->connlist == NULL)
67     ;
68   else if (sess->connlist->next == NULL) {
69     if (sess->connlist == *deadconn)
70       sess->connlist = NULL;
71   } else {
72     cur = sess->connlist;
73     while (cur->next) {
74       if (cur->next == *deadconn) {
75         cur->next = cur->next->next;
76         break;
77       }
78       cur = cur->next;
79     }
80   }
81   faim_mutex_unlock(&sess->connlistlock);
82
83   /* XXX: do we need this for txqueue too? */
84   aim_rxqueue_cleanbyconn(sess, *deadconn);
85
86   aim_conn_close(*deadconn);
87   free(*deadconn);
88   deadconn = NULL;
89
90   return;
91 }
92
93 void aim_conn_close(struct aim_conn_t *deadconn)
94 {
95   if (deadconn->fd >= 3)
96     close(deadconn->fd);
97   deadconn->fd = -1;
98   deadconn->type = -1;
99   deadconn->seqnum = 0;
100   deadconn->lastactivity = 0;
101   deadconn->forcedlatency = 0;
102   if (deadconn->handlerlist)
103     aim_clearhandlers(deadconn);
104   deadconn->handlerlist = NULL;
105   if (deadconn->priv)
106     free(deadconn->priv);
107   deadconn->priv = NULL;
108   faim_mutex_init(&deadconn->active, NULL);
109   faim_mutex_init(&deadconn->seqnum_lock, NULL);
110 }
111
112 struct aim_conn_t *aim_getconn_type(struct aim_session_t *sess,
113                                     int type)
114 {
115   struct aim_conn_t *cur;
116
117   faim_mutex_lock(&sess->connlistlock);
118   for (cur = sess->connlist; cur; cur = cur->next) {
119     if (cur->type == type)
120       break;
121   }
122   faim_mutex_unlock(&sess->connlistlock);
123   return cur;
124 }
125
126 /*
127  * aim_newconn(type, dest)
128  *
129  * Opens a new connection to the specified dest host of type type.
130  *
131  * TODO: fix for proxies
132  * FIXME: Return errors in a more sane way.
133  *
134  */
135 struct aim_conn_t *aim_newconn(struct aim_session_t *sess,
136                                int type, char *dest)
137 {
138   struct aim_conn_t *connstruct;
139   int ret;
140   struct sockaddr_in sa;
141   struct hostent *hp;
142   u_short port = FAIM_LOGIN_PORT;
143   char *host = NULL;
144   int i=0;
145
146   if ((connstruct=aim_conn_getnext(sess))==NULL)
147     return NULL;
148
149   faim_mutex_lock(&connstruct->active);
150   
151   connstruct->type = type;
152
153   if (!dest) { /* just allocate a struct */
154     connstruct->fd = -1;
155     connstruct->status = 0;
156     faim_mutex_unlock(&connstruct->active);
157     return connstruct;
158   }
159
160   /* 
161    * As of 23 Jul 1999, AOL now sends the port number, preceded by a 
162    * colon, in the BOS redirect.  This fatally breaks all previous 
163    * libfaims.  Bad, bad AOL.
164    *
165    * We put this here to catch every case. 
166    *
167    */
168
169   for(i=0;i<strlen(dest);i++) {
170     if (dest[i] == ':') {
171       port = atoi(&(dest[i+1]));
172       break;
173     }
174   }
175   host = (char *)malloc(i+1);
176   strncpy(host, dest, i);
177   host[i] = '\0';
178
179   hp = gethostbyname(host);
180   free(host);
181
182   if (hp == NULL) {
183     connstruct->status = (h_errno | AIM_CONN_STATUS_RESOLVERR);
184     faim_mutex_unlock(&connstruct->active);
185     return connstruct;
186   }
187
188   memset(&sa.sin_zero, 0, 8);
189   sa.sin_port = htons(port);
190   memcpy(&sa.sin_addr, hp->h_addr, hp->h_length);
191   sa.sin_family = hp->h_addrtype;
192   
193   connstruct->fd = socket(hp->h_addrtype, SOCK_STREAM, 0);
194   ret = connect(connstruct->fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in));
195   if(ret < 0) {
196     connstruct->fd = -1;
197     connstruct->status = (errno | AIM_CONN_STATUS_CONNERR);
198     faim_mutex_unlock(&connstruct->active);
199     return connstruct;
200   }
201   
202   faim_mutex_unlock(&connstruct->active);
203
204   return connstruct;
205 }
206
207 int aim_conngetmaxfd(struct aim_session_t *sess)
208 {
209   int j = 0;
210   struct aim_conn_t *cur;
211
212   faim_mutex_lock(&sess->connlistlock);
213   for (cur = sess->connlist; cur; cur = cur->next) {
214     if (cur->fd > j)
215       j = cur->fd;
216   }
217   faim_mutex_unlock(&sess->connlistlock);
218
219   return j;
220 }
221
222 int aim_countconn(struct aim_session_t *sess)
223 {
224   int cnt = 0;
225   struct aim_conn_t *cur;
226
227   faim_mutex_lock(&sess->connlistlock);
228   for (cur = sess->connlist; cur; cur = cur->next)
229     cnt++;
230   faim_mutex_unlock(&sess->connlistlock);
231
232   return cnt;
233 }
234
235 /*
236  * aim_select(timeout)
237  *
238  * Waits for a socket with data or for timeout, whichever comes first.
239  * See select(2).
240  * 
241  * Return codes in *status:
242  *   -1  error in select() (NULL returned)
243  *    0  no events pending (NULL returned)
244  *    1  outgoing data pending (NULL returned)
245  *    2  incoming data pending (connection with pending data returned)
246  *
247  * XXX: we could probably stand to do a little courser locking here.
248  *
249  */ 
250 struct aim_conn_t *aim_select(struct aim_session_t *sess,
251                               struct timeval *timeout, int *status)
252 {
253   struct aim_conn_t *cur;
254   fd_set fds;
255   int maxfd = 0;
256   int i;
257
258   faim_mutex_lock(&sess->connlistlock);
259   if (sess->connlist == NULL) {
260     faim_mutex_unlock(&sess->connlistlock);
261     *status = -1;
262     return NULL;
263   }
264   faim_mutex_unlock(&sess->connlistlock);
265
266   /* 
267    * If we have data waiting to be sent, return immediatly
268    */
269   if (sess->queue_outgoing != NULL) {
270     *status = 1;
271     return NULL;
272   } 
273
274   FD_ZERO(&fds);
275   maxfd = 0;
276
277   faim_mutex_lock(&sess->connlistlock);
278   for (cur = sess->connlist; cur; cur = cur->next) {
279     FD_SET(cur->fd, &fds);
280     if (cur->fd > maxfd)
281       maxfd = cur->fd;
282   }
283   faim_mutex_unlock(&sess->connlistlock);
284
285   if ((i = select(maxfd+1, &fds, NULL, NULL, timeout))>=1) {
286     faim_mutex_lock(&sess->connlistlock);
287     for (cur = sess->connlist; cur; cur = cur->next) {
288       if (FD_ISSET(cur->fd, &fds)) {
289         *status = 2;
290         faim_mutex_unlock(&sess->connlistlock);
291         return cur;
292       }
293     }
294   }
295
296   faim_mutex_unlock(&sess->connlistlock);
297   *status = i; /* may be 0 or -1 */
298   return NULL;  /* no waiting or error, return */
299 }
300
301 int aim_conn_isready(struct aim_conn_t *conn)
302 {
303   if (conn)
304     return (conn->status & 0x0001);
305   return -1;
306 }
307
308 int aim_conn_setstatus(struct aim_conn_t *conn, int status)
309 {
310   int val;
311
312   if (!conn)
313     return -1;
314   
315   faim_mutex_lock(&conn->active);
316   val = conn->status ^= status;
317   faim_mutex_unlock(&conn->active);
318   return val;
319 }
320
321 int aim_conn_setlatency(struct aim_conn_t *conn, int newval)
322 {
323   if (!conn)
324     return -1;
325
326   faim_mutex_lock(&conn->active);
327   conn->forcedlatency = newval;
328   conn->lastactivity = 0; /* reset this just to make sure */
329   faim_mutex_unlock(&conn->active);
330
331   return 0;
332 }
333
334 void aim_session_init(struct aim_session_t *sess)
335 {
336   if (!sess)
337     return;
338
339   memset(sess, 0, sizeof(struct aim_session_t));
340   aim_connrst(sess);
341   sess->queue_outgoing = NULL;
342   sess->queue_incoming = NULL;
343   sess->pendingjoin = NULL;
344   sess->outstanding_snacs = NULL;
345   sess->snac_nextid = 0x00000001;
346
347   /*
348    * This must always be set.  Default to the queue-based
349    * version for back-compatibility.  
350    */
351   sess->tx_enqueue = &aim_tx_enqueue__queuebased;
352
353   return;
354 }
This page took 0.091051 seconds and 5 git commands to generate.