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