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