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