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