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