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