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