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