]> andersk Git - libfaim.git/blob - src/conn.c
- Fri Mar 23 05:42:11 UTC 2001
[libfaim.git] / src / conn.c
1
2 /*
3  *  aim_conn.c
4  *
5  * Does all this gloriously nifty connection handling stuff...
6  *
7  */
8
9 #define FAIM_INTERNAL
10 #include <aim.h> 
11
12 #ifndef _WIN32
13 #include <netdb.h>
14 #include <sys/socket.h>
15 #include <netinet/in.h>
16 #endif
17
18 /**
19  * aim_connrst - Clears out connection list, killing remaining connections.
20  * @sess: Session to be cleared
21  *
22  * Clears out the connection list and kills any connections left.
23  *
24  */
25 faim_internal void aim_connrst(struct aim_session_t *sess)
26 {
27   faim_mutex_init(&sess->connlistlock);
28   if (sess->connlist) {
29     struct aim_conn_t *cur = sess->connlist, *tmp;
30
31     while(cur) {
32       tmp = cur->next;
33       aim_conn_close(cur);
34       free(cur);
35       cur = tmp;
36     }
37   }
38   sess->connlist = NULL;
39   return;
40 }
41
42 /**
43  * aim_conn_init - Reset a connection to default values.
44  * @deadconn: Connection to be reset
45  *
46  * Initializes and/or resets a connection structure.
47  *
48  */
49 static void aim_conn_init(struct aim_conn_t *deadconn)
50 {
51   if (!deadconn)
52     return;
53
54   deadconn->fd = -1;
55   deadconn->subtype = -1;
56   deadconn->type = -1;
57   deadconn->seqnum = 0;
58   deadconn->lastactivity = 0;
59   deadconn->forcedlatency = 0;
60   deadconn->handlerlist = NULL;
61   deadconn->priv = NULL;
62   faim_mutex_init(&deadconn->active);
63   faim_mutex_init(&deadconn->seqnum_lock);
64   
65   return;
66 }
67
68 /**
69  * aim_conn_getnext - Gets a new connection structure.
70  * @sess: Session
71  *
72  * Allocate a new empty connection structure.
73  *
74  */
75 faim_internal struct aim_conn_t *aim_conn_getnext(struct aim_session_t *sess)
76 {
77   struct aim_conn_t *newconn, *cur;
78
79   if (!(newconn = malloc(sizeof(struct aim_conn_t))))   
80     return NULL;
81
82   memset(newconn, 0, sizeof(struct aim_conn_t));
83   aim_conn_init(newconn);
84   newconn->next = NULL;
85
86   faim_mutex_lock(&sess->connlistlock);
87   if (sess->connlist == NULL)
88     sess->connlist = newconn;
89   else {
90     for (cur = sess->connlist; cur->next; cur = cur->next)
91       ;
92     cur->next = newconn;
93   }
94   faim_mutex_unlock(&sess->connlistlock);
95
96   return newconn;
97 }
98
99 /**
100  * aim_conn_kill - Close and free a connection.
101  * @sess: Session for the connection
102  * @deadconn: Connection to be freed
103  *
104  * Close, clear, and free a connection structure. Should never be
105  * called from within libfaim.
106  *
107  */
108 faim_export void aim_conn_kill(struct aim_session_t *sess, struct aim_conn_t **deadconn)
109 {
110   struct aim_conn_t *cur;
111
112   if (!deadconn || !*deadconn)  
113     return;
114
115   aim_tx_cleanqueue(sess, *deadconn);
116
117   faim_mutex_lock(&sess->connlistlock);
118   if (sess->connlist == NULL)
119     ;
120   else if (sess->connlist->next == NULL) {
121     if (sess->connlist == *deadconn)
122       sess->connlist = NULL;
123   } else {
124     cur = sess->connlist;
125     while (cur->next) {
126       if (cur->next == *deadconn) {
127         cur->next = cur->next->next;
128         break;
129       }
130       cur = cur->next;
131     }
132   }
133   faim_mutex_unlock(&sess->connlistlock);
134
135   /* XXX: do we need this for txqueue too? */
136   aim_rxqueue_cleanbyconn(sess, *deadconn);
137
138   if ((*deadconn)->fd != -1) 
139     aim_conn_close(*deadconn);
140   if ((*deadconn)->priv)
141     free((*deadconn)->priv);
142   free(*deadconn);
143   deadconn = NULL;
144
145   return;
146 }
147
148 /**
149  * aim_conn_close - Close a connection
150  * @deadconn: Connection to close
151  *
152  * Close (but not free) a connection.
153  *
154  * This leaves everything untouched except for clearing the 
155  * handler list and setting the fd to -1 (used to recognize
156  * dead connections).
157  *
158  */
159 faim_export void aim_conn_close(struct aim_conn_t *deadconn)
160 {
161
162   faim_mutex_destroy(&deadconn->active);
163   faim_mutex_destroy(&deadconn->seqnum_lock);
164   if (deadconn->fd >= 3)
165     close(deadconn->fd);
166   deadconn->fd = -1;
167   if (deadconn->handlerlist)
168     aim_clearhandlers(deadconn);
169
170   return;
171 }
172
173 /**
174  * aim_getconn_type - Find a connection of a specific type
175  * @sess: Session to search
176  * @type: Type of connection to look for
177  *
178  * Searches for a connection of the specified type in the 
179  * specified session.  Returns the first connection of that
180  * type found.
181  *
182  */
183 faim_export struct aim_conn_t *aim_getconn_type(struct aim_session_t *sess,
184                                                 int type)
185 {
186   struct aim_conn_t *cur;
187
188   faim_mutex_lock(&sess->connlistlock);
189   for (cur = sess->connlist; cur; cur = cur->next) {
190     if ((cur->type == type) && !(cur->status & AIM_CONN_STATUS_INPROGRESS))
191       break;
192   }
193   faim_mutex_unlock(&sess->connlistlock);
194   return cur;
195 }
196
197 /**
198  * aim_proxyconnect - An extrememly quick and dirty SOCKS5 interface. 
199  * @sess: Session to connect
200  * @host: Host to connect to
201  * @port: Port to connect to
202  * @statusret: Return value of the connection
203  *
204  * Attempts to connect to the specified host via the configured
205  * proxy settings, if present.  If no proxy is configured for
206  * this session, the connection is done directly.
207  *
208  */
209 static int aim_proxyconnect(struct aim_session_t *sess, 
210                             char *host, unsigned short port,
211                             int *statusret)
212 {
213   int fd = -1;
214
215   if (strlen(sess->socksproxy.server)) { /* connecting via proxy */
216     int i;
217     unsigned char buf[512];
218     struct sockaddr_in sa;
219     struct hostent *hp;
220     char *proxy;
221     unsigned short proxyport = 1080;
222
223     for(i=0;i<(int)strlen(sess->socksproxy.server);i++) {
224       if (sess->socksproxy.server[i] == ':') {
225         proxyport = atoi(&(sess->socksproxy.server[i+1]));
226         break;
227       }
228     }
229     proxy = (char *)malloc(i+1);
230     strncpy(proxy, sess->socksproxy.server, i);
231     proxy[i] = '\0';
232
233     if (!(hp = gethostbyname(proxy))) {
234       faimdprintf(sess, 0, "proxyconnect: unable to resolve proxy name\n");
235       *statusret = (h_errno | AIM_CONN_STATUS_RESOLVERR);
236       return -1;
237     }
238     free(proxy);
239
240     memset(&sa.sin_zero, 0, 8);
241     sa.sin_port = htons(proxyport);
242     memcpy(&sa.sin_addr, hp->h_addr, hp->h_length);
243     sa.sin_family = hp->h_addrtype;
244   
245     fd = socket(hp->h_addrtype, SOCK_STREAM, 0);
246     if (connect(fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) {
247       faimdprintf(sess, 0, "proxyconnect: unable to connect to proxy\n");
248       close(fd);
249       return -1;
250     }
251
252     i = 0;
253     buf[0] = 0x05; /* SOCKS version 5 */
254     if (strlen(sess->socksproxy.username)) {
255       buf[1] = 0x02; /* two methods */
256       buf[2] = 0x00; /* no authentication */
257       buf[3] = 0x02; /* username/password authentication */
258       i = 4;
259     } else {
260       buf[1] = 0x01;
261       buf[2] = 0x00;
262       i = 3;
263     }
264
265     if (write(fd, buf, i) < i) {
266       *statusret = errno;
267       close(fd);
268       return -1;
269     }
270
271     if (read(fd, buf, 2) < 2) {
272       *statusret = errno;
273       close(fd);
274       return -1;
275     }
276
277     if ((buf[0] != 0x05) || (buf[1] == 0xff)) {
278       *statusret = EINVAL;
279       close(fd);
280       return -1;
281     }
282
283     /* check if we're doing username authentication */
284     if (buf[1] == 0x02) {
285       i  = aimutil_put8(buf, 0x01); /* version 1 */
286       i += aimutil_put8(buf+i, strlen(sess->socksproxy.username));
287       i += aimutil_putstr(buf+i, sess->socksproxy.username, strlen(sess->socksproxy.username));
288       i += aimutil_put8(buf+i, strlen(sess->socksproxy.password));
289       i += aimutil_putstr(buf+i, sess->socksproxy.password, strlen(sess->socksproxy.password));
290       if (write(fd, buf, i) < i) {
291         *statusret = errno;
292         close(fd);
293         return -1;
294       }
295       if (read(fd, buf, 2) < 2) {
296         *statusret = errno;
297         close(fd);
298         return -1;
299       }
300       if ((buf[0] != 0x01) || (buf[1] != 0x00)) {
301         *statusret = EINVAL;
302         close(fd);
303         return -1;
304       }
305     }
306
307     i  = aimutil_put8(buf, 0x05);
308     i += aimutil_put8(buf+i, 0x01); /* CONNECT */
309     i += aimutil_put8(buf+i, 0x00); /* reserved */
310     i += aimutil_put8(buf+i, 0x03); /* address type: host name */
311     i += aimutil_put8(buf+i, strlen(host));
312     i += aimutil_putstr(buf+i, host, strlen(host));
313     i += aimutil_put16(buf+i, port);
314
315     if (write(fd, buf, i) < i) {
316       *statusret = errno;
317       close(fd);
318       return -1;
319     }
320     if (read(fd, buf, 10) < 10) {
321       *statusret = errno;
322       close(fd);
323       return -1;
324     }
325     if ((buf[0] != 0x05) || (buf[1] != 0x00)) {
326       *statusret = EINVAL;
327       close(fd);
328       return -1;
329     }
330
331   } else { /* connecting directly */
332     struct sockaddr_in sa;
333     struct hostent *hp;
334
335     if (!(hp = gethostbyname(host))) {
336       *statusret = (h_errno | AIM_CONN_STATUS_RESOLVERR);
337       return -1;
338     }
339
340     memset(&sa, 0, sizeof(struct sockaddr_in));
341     sa.sin_port = htons(port);
342     memcpy(&sa.sin_addr, hp->h_addr, hp->h_length);
343     sa.sin_family = hp->h_addrtype;
344   
345     fd = socket(hp->h_addrtype, SOCK_STREAM, 0);
346
347     if (sess->flags & AIM_SESS_FLAGS_NONBLOCKCONNECT)
348       fcntl(fd, F_SETFL, O_NONBLOCK); /* XXX save flags */
349
350     if (connect(fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) {
351       if (sess->flags & AIM_SESS_FLAGS_NONBLOCKCONNECT) {
352         if ((errno == EINPROGRESS) || (errno == EINTR)) {
353           if (statusret)
354             *statusret |= AIM_CONN_STATUS_INPROGRESS;
355           return fd;
356         }
357       }
358       close(fd);
359       fd = -1;
360     }
361   }
362   return fd;
363 }
364
365 /**
366  * aim_cloneconn - clone an aim_conn_t
367  * @sess: session containing parent
368  * @src: connection to clone
369  *
370  * A new connection is allocated, and the values are filled in
371  * appropriately. Note that this function sets the new connnection's
372  * ->priv pointer to be equal to that of its parent: only the pointer
373  * is copied, not the data it points to.
374  *
375  * This function returns a pointer to the new aim_conn_t, or %NULL on
376  * error
377  */
378 faim_internal struct aim_conn_t *aim_cloneconn(struct aim_session_t *sess,
379                                                struct aim_conn_t *src)
380 {
381   struct aim_conn_t *conn;
382     struct aim_rxcblist_t *cur;
383
384   if (!(conn = aim_conn_getnext(sess)))
385     return NULL;
386
387   faim_mutex_lock(&conn->active);
388
389   conn->fd = src->fd;
390   conn->type = src->type;
391   conn->subtype = src->subtype;
392   conn->seqnum = src->seqnum;
393   conn->priv = src->priv;
394   conn->lastactivity = src->lastactivity;
395   conn->forcedlatency = src->forcedlatency;
396
397   /* clone handler list */
398   for (cur = src->handlerlist; cur; cur = cur->next) {
399     aim_conn_addhandler(sess, conn, cur->family, cur->type, 
400                         cur->handler, cur->flags);
401   }
402
403   faim_mutex_unlock(&conn->active);
404
405   return conn;
406 }
407
408 /**
409  * aim_newconn - Open a new connection
410  * @sess: Session to create connection in
411  * @type: Type of connection to create
412  * @dest: Host to connect to (in "host:port" syntax)
413  *
414  * Opens a new connection to the specified dest host of specified
415  * type, using the proxy settings if available.  If @host is %NULL,
416  * the connection is allocated and returned, but no connection 
417  * is made.
418  *
419  * FIXME: Return errors in a more sane way.
420  *
421  */
422 faim_export struct aim_conn_t *aim_newconn(struct aim_session_t *sess,
423                                            int type, char *dest)
424 {
425   struct aim_conn_t *connstruct;
426   int ret;
427   u_short port = FAIM_LOGIN_PORT;
428   char *host = NULL;
429   int i=0;
430
431   if ((connstruct=aim_conn_getnext(sess))==NULL)
432     return NULL;
433
434   faim_mutex_lock(&connstruct->active);
435   
436   connstruct->type = type;
437
438   if (!dest) { /* just allocate a struct */
439     connstruct->fd = -1;
440     connstruct->status = 0;
441     faim_mutex_unlock(&connstruct->active);
442     return connstruct;
443   }
444
445   /* 
446    * As of 23 Jul 1999, AOL now sends the port number, preceded by a 
447    * colon, in the BOS redirect.  This fatally breaks all previous 
448    * libfaims.  Bad, bad AOL.
449    *
450    * We put this here to catch every case. 
451    *
452    */
453
454   for(i=0;i<(int)strlen(dest);i++) {
455     if (dest[i] == ':') {
456       port = atoi(&(dest[i+1]));
457       break;
458     }
459   }
460   host = (char *)malloc(i+1);
461   strncpy(host, dest, i);
462   host[i] = '\0';
463
464   if ((ret = aim_proxyconnect(sess, host, port, &connstruct->status)) < 0) {
465     connstruct->fd = -1;
466     connstruct->status = (errno | AIM_CONN_STATUS_CONNERR);
467     free(host);
468     faim_mutex_unlock(&connstruct->active);
469     return connstruct;
470   } else
471     connstruct->fd = ret;
472   
473   faim_mutex_unlock(&connstruct->active);
474
475   free(host);
476
477   return connstruct;
478 }
479
480 /**
481  * aim_conngetmaxfd - Return the highest valued file discriptor in session
482  * @sess: Session to search
483  *
484  * Returns the highest valued filed descriptor of all open 
485  * connections in @sess.
486  *
487  */
488 faim_export int aim_conngetmaxfd(struct aim_session_t *sess)
489 {
490   int j = 0;
491   struct aim_conn_t *cur;
492
493   faim_mutex_lock(&sess->connlistlock);
494   for (cur = sess->connlist; cur; cur = cur->next) {
495     if (cur->fd > j)
496       j = cur->fd;
497   }
498   faim_mutex_unlock(&sess->connlistlock);
499
500   return j;
501 }
502
503 /**
504  * aim_conn_in_sess - Predicate to test the precense of a connection in a sess
505  * @sess: Session to look in
506  * @conn: Connection to look for
507  *
508  * Searches @sess for the passed connection.  Returns 1 if its present,
509  * zero otherwise.
510  *
511  */
512 faim_export int aim_conn_in_sess(struct aim_session_t *sess, struct aim_conn_t *conn)
513 {
514   struct aim_conn_t *cur;
515
516   faim_mutex_lock(&sess->connlistlock);
517   for(cur = sess->connlist; cur; cur = cur->next)
518     if(cur == conn) {
519       faim_mutex_unlock(&sess->connlistlock);
520       return 1;
521     }
522   faim_mutex_unlock(&sess->connlistlock);
523   return 0;
524 }
525
526 /**
527  * aim_select - Wait for a socket with data or timeout
528  * @sess: Session to wait on
529  * @timeout: How long to wait
530  * @status: Return status
531  *
532  * Waits for a socket with data or for timeout, whichever comes first.
533  * See select(2).
534  * 
535  * Return codes in *status:
536  *   -1  error in select() (%NULL returned)
537  *    0  no events pending (%NULL returned)
538  *    1  outgoing data pending (%NULL returned)
539  *    2  incoming data pending (connection with pending data returned)
540  *
541  * XXX: we could probably stand to do a little courser locking here.
542  *
543  */ 
544 faim_export struct aim_conn_t *aim_select(struct aim_session_t *sess,
545                                           struct timeval *timeout, 
546                                           int *status)
547 {
548   struct aim_conn_t *cur;
549   fd_set fds, wfds;
550   int maxfd = 0;
551   int i, haveconnecting = 0;
552
553   faim_mutex_lock(&sess->connlistlock);
554   if (sess->connlist == NULL) {
555     faim_mutex_unlock(&sess->connlistlock);
556     *status = -1;
557     return NULL;
558   }
559   faim_mutex_unlock(&sess->connlistlock);
560
561   FD_ZERO(&fds);
562   FD_ZERO(&wfds);
563   maxfd = 0;
564
565   faim_mutex_lock(&sess->connlistlock);
566   for (cur = sess->connlist; cur; cur = cur->next) {
567     if (cur->fd == -1) {
568       /* don't let invalid/dead connections sit around */
569       *status = 2;
570       faim_mutex_unlock(&sess->connlistlock);
571       return cur;
572     } else if (cur->status & AIM_CONN_STATUS_INPROGRESS) {
573       FD_SET(cur->fd, &wfds);
574       
575       haveconnecting++;
576     }
577     FD_SET(cur->fd, &fds);
578     if (cur->fd > maxfd)
579       maxfd = cur->fd;
580   }
581   faim_mutex_unlock(&sess->connlistlock);
582
583   /* 
584    * If we have data waiting to be sent, return
585    *
586    * We have to not do this if theres at least one
587    * connection thats still connecting, since that connection
588    * may have queued data and this return would prevent
589    * the connection from ever completing!  This is a major
590    * inadequacy of the libfaim way of doing things.  It means
591    * that nothing can transmit as long as there's connecting
592    * sockets. Evil.
593    *
594    * But its still better than having blocking connects.
595    *
596    */
597   if (!haveconnecting && (sess->queue_outgoing != NULL)) {
598     *status = 1;
599     return NULL;
600   } 
601
602   if ((i = select(maxfd+1, &fds, &wfds, NULL, timeout))>=1) {
603     faim_mutex_lock(&sess->connlistlock);
604     for (cur = sess->connlist; cur; cur = cur->next) {
605       if ((FD_ISSET(cur->fd, &fds)) || 
606           ((cur->status & AIM_CONN_STATUS_INPROGRESS) && 
607            FD_ISSET(cur->fd, &wfds))) {
608         *status = 2;
609         faim_mutex_unlock(&sess->connlistlock);
610         return cur; /* XXX race condition here -- shouldnt unlock connlist */
611       }
612     }
613     *status = 0; /* shouldn't happen */
614   } else if ((i == -1) && (errno == EINTR)) /* treat interrupts as a timeout */
615     *status = 0;
616   else
617     *status = i; /* can be 0 or -1 */
618
619   faim_mutex_unlock(&sess->connlistlock);
620
621   return NULL;  /* no waiting or error, return */
622 }
623
624 /**
625  * aim_conn_isready - Test if a connection is marked ready
626  * @conn: Connection to test
627  *
628  * Returns true if the connection is ready, false otherwise.
629  * Returns -1 if the connection is invalid.
630  *
631  * XXX: This is deprecated.
632  *
633  */
634 faim_export int aim_conn_isready(struct aim_conn_t *conn)
635 {
636   if (conn)
637     return (conn->status & 0x0001);
638   return -1;
639 }
640
641 /**
642  * aim_conn_setstatus - Set the status of a connection
643  * @conn: Connection
644  * @status: New status
645  *
646  * @newstatus is %XOR'd with the previous value of the connection
647  * status and returned.  Returns -1 if the connection is invalid.
648  *
649  * This isn't real useful.
650  *
651  */
652 faim_export int aim_conn_setstatus(struct aim_conn_t *conn, int status)
653 {
654   int val;
655
656   if (!conn)
657     return -1;
658   
659   faim_mutex_lock(&conn->active);
660   val = conn->status ^= status;
661   faim_mutex_unlock(&conn->active);
662
663   return val;
664 }
665
666 /**
667  * aim_conn_setlatency - Set a forced latency value for connection
668  * @conn: Conn to set latency for
669  * @newval: Number of seconds to force between transmits
670  *
671  * Causes @newval seconds to be spent between transmits on a connection.
672  *
673  * This is my lame attempt at overcoming not understanding the rate
674  * limiting. 
675  *
676  * XXX: This should really be replaced with something that scales and
677  * backs off like the real rate limiting does.
678  *
679  */
680 faim_export int aim_conn_setlatency(struct aim_conn_t *conn, int newval)
681 {
682   if (!conn)
683     return -1;
684
685   faim_mutex_lock(&conn->active);
686   conn->forcedlatency = newval;
687   conn->lastactivity = 0; /* reset this just to make sure */
688   faim_mutex_unlock(&conn->active);
689
690   return 0;
691 }
692
693 /**
694  * aim_setupproxy - Configure a proxy for this session
695  * @sess: Session to set proxy for
696  * @server: SOCKS server
697  * @username: SOCKS username
698  * @password: SOCKS password
699  *
700  * Call this with your SOCKS5 proxy server parameters before
701  * the first call to aim_newconn().  If called with all %NULL
702  * args, it will clear out a previously set proxy.  
703  *
704  * Set username and password to %NULL if not applicable.
705  *
706  */
707 faim_export void aim_setupproxy(struct aim_session_t *sess, char *server, char *username, char *password)
708 {
709   /* clear out the proxy info */
710   if (!server || !strlen(server)) {
711     memset(sess->socksproxy.server, 0, sizeof(sess->socksproxy.server));
712     memset(sess->socksproxy.username, 0, sizeof(sess->socksproxy.username));
713     memset(sess->socksproxy.password, 0, sizeof(sess->socksproxy.password));
714     return;
715   }
716
717   strncpy(sess->socksproxy.server, server, sizeof(sess->socksproxy.server));
718   if (username && strlen(username)) 
719     strncpy(sess->socksproxy.username, username, sizeof(sess->socksproxy.username));
720   if (password && strlen(password))
721     strncpy(sess->socksproxy.password, password, sizeof(sess->socksproxy.password));
722   return;
723 }
724
725 static void defaultdebugcb(struct aim_session_t *sess, int level, const char *format, va_list va)
726 {
727   vfprintf(stderr, format, va);
728 }
729
730 /**
731  * aim_session_init - Initializes a session structure
732  * @sess: Session to initialize
733  * @flags: Flags to use. Any of %AIM_SESS_FLAGS %OR'd together.
734  * @debuglevel: Level of debugging output (zero is least)
735  *
736  * Sets up the initial values for a session.
737  *
738  */
739 faim_export void aim_session_init(struct aim_session_t *sess, unsigned long flags, int debuglevel)
740 {
741   if (!sess)
742     return;
743
744   memset(sess, 0, sizeof(struct aim_session_t));
745   aim_connrst(sess);
746   sess->queue_outgoing = NULL;
747   sess->queue_incoming = NULL;
748   sess->pendingjoin = NULL;
749   sess->pendingjoinexchange = 0;
750   aim_initsnachash(sess);
751   sess->msgcookies = NULL;
752   sess->snac_nextid = 0x00000001;
753
754   sess->flags = 0;
755   sess->debug = 0;
756   sess->debugcb = defaultdebugcb;
757
758   sess->modlistv = NULL;
759
760   /*
761    * Default to SNAC login unless XORLOGIN is explicitly set.
762    */
763   if (!(flags & AIM_SESS_FLAGS_XORLOGIN))
764     sess->flags |= AIM_SESS_FLAGS_SNACLOGIN;
765   sess->flags |= flags;
766
767   /*
768    * This must always be set.  Default to the queue-based
769    * version for back-compatibility.  
770    */
771   aim_tx_setenqueue(sess, AIM_TX_QUEUED, NULL);
772
773
774   /*
775    * Register all the modules for this session...
776    */
777   aim__registermodule(sess, buddylist_modfirst);
778   aim__registermodule(sess, admin_modfirst);
779   aim__registermodule(sess, bos_modfirst);
780   aim__registermodule(sess, search_modfirst);
781   aim__registermodule(sess, stats_modfirst);
782   aim__registermodule(sess, auth_modfirst);
783
784   return;
785 }
786
787 /**
788  * aim_session_kill - Deallocate a session
789  * @sess: Session to kill
790  *
791  *
792  */
793 faim_export void aim_session_kill(struct aim_session_t *sess)
794 {
795
796   aim_logoff(sess);
797
798   aim__shutdownmodules(sess);
799
800   return;
801 }
802
803 /**
804  * aim_setdebuggingcb - Set the function to call when outputting debugging info
805  * @sess: Session to change
806  * @cb: Function to call
807  *
808  * The function specified is called whenever faimdprintf() is used within
809  * libfaim, and the session's debugging level is greater tha nor equal to
810  * the value faimdprintf was called with.
811  *
812  */
813 faim_export int aim_setdebuggingcb(struct aim_session_t *sess, faim_debugging_callback_t cb)
814 {
815
816   if (!sess)
817     return -1;
818
819   sess->debugcb = cb;
820
821   return 0;
822 }
823
824 /**
825  * aim_conn_isconnecting - Determine if a connection is connecting
826  * @conn: Connection to examine
827  *
828  * Returns nonzero if the connection is in the process of
829  * connecting (or if it just completed and aim_conn_completeconnect()
830  * has yet to be called on it).
831  *
832  */
833 faim_export int aim_conn_isconnecting(struct aim_conn_t *conn)
834 {
835   if (!conn)
836     return 0;
837   return (conn->status & AIM_CONN_STATUS_INPROGRESS)?1:0;
838 }
839
840 faim_export int aim_conn_completeconnect(struct aim_session_t *sess, struct aim_conn_t *conn)
841 {
842   fd_set fds, wfds;
843   struct timeval tv;
844   int res, error = ETIMEDOUT;
845   rxcallback_t userfunc;
846
847   if (!conn || (conn->fd == -1))
848     return -1;
849
850   if (!(conn->status & AIM_CONN_STATUS_INPROGRESS))
851     return -1;
852
853   FD_ZERO(&fds);
854   FD_SET(conn->fd, &fds);
855   FD_ZERO(&wfds);
856   FD_SET(conn->fd, &wfds);
857   tv.tv_sec = 0;
858   tv.tv_usec = 0;
859
860   if ((res = select(conn->fd+1, &fds, &wfds, NULL, &tv)) == -1) {
861     error = errno;
862     aim_conn_close(conn);
863     errno = error;
864     return -1;
865   } else if (res == 0) {
866     faimdprintf(sess, 0, "aim_conn_completeconnect: false alarm on %d\n", conn->fd);
867     return 0; /* hasn't really completed yet... */
868   } 
869
870   if (FD_ISSET(conn->fd, &fds) || FD_ISSET(conn->fd, &wfds)) {
871     int len = sizeof(error);
872
873     if (getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
874       error = errno;
875   }
876
877   if (error) {
878     aim_conn_close(conn);
879     errno = error;
880     return -1;
881   }
882
883   fcntl(conn->fd, F_SETFL, 0); /* XXX should restore original flags */
884
885   conn->status &= ~AIM_CONN_STATUS_INPROGRESS;
886
887   if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE)))
888     userfunc(sess, NULL, conn);
889
890   /* Flush out the queues if there was something waiting for this conn  */
891   aim_tx_flushqueue(sess);
892
893   return 0;
894 }
895
896 /*
897  * aim_logoff()
898  *
899  * Closes -ALL- open connections.
900  *
901  */
902 faim_export int aim_logoff(struct aim_session_t *sess)
903 {
904
905   aim_connrst(sess);  /* in case we want to connect again */
906
907   return 0;
908
909 }
910
This page took 0.963109 seconds and 5 git commands to generate.