]> andersk Git - libfaim.git/blame - src/conn.c
- Fri Mar 23 05:42:11 UTC 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 */
78b3fb13 25faim_internal void aim_connrst(struct aim_session_t *sess)
9de3ca7e 26{
b13c9e13 27 faim_mutex_init(&sess->connlistlock);
040457cc 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 }
e88ba395 37 }
040457cc 38 sess->connlist = NULL;
39 return;
9de3ca7e 40}
41
9d2a3582 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 */
49static 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
be67fdd0 68/**
69 * aim_conn_getnext - Gets a new connection structure.
70 * @sess: Session
71 *
72 * Allocate a new empty connection structure.
73 *
040457cc 74 */
78b3fb13 75faim_internal struct aim_conn_t *aim_conn_getnext(struct aim_session_t *sess)
9de3ca7e 76{
040457cc 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));
9d2a3582 83 aim_conn_init(newconn);
040457cc 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
be67fdd0 99/**
100 * aim_conn_kill - Close and free a connection.
101 * @sess: Session for the connection
102 * @deadconn: Connection to be freed
103 *
646c6b52 104 * Close, clear, and free a connection structure. Should never be
105 * called from within libfaim.
be67fdd0 106 *
107 */
78b3fb13 108faim_export void aim_conn_kill(struct aim_session_t *sess, struct aim_conn_t **deadconn)
040457cc 109{
110 struct aim_conn_t *cur;
111
112 if (!deadconn || !*deadconn)
113 return;
114
9e8c4225 115 aim_tx_cleanqueue(sess, *deadconn);
116
040457cc 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
68ac63c2 135 /* XXX: do we need this for txqueue too? */
136 aim_rxqueue_cleanbyconn(sess, *deadconn);
137
9d2a3582 138 if ((*deadconn)->fd != -1)
139 aim_conn_close(*deadconn);
f8ac5020 140 if ((*deadconn)->priv)
141 free((*deadconn)->priv);
040457cc 142 free(*deadconn);
143 deadconn = NULL;
144
145 return;
9de3ca7e 146}
147
be67fdd0 148/**
149 * aim_conn_close - Close a connection
150 * @deadconn: Connection to close
151 *
152 * Close (but not free) a connection.
153 *
9d2a3582 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 *
be67fdd0 158 */
78b3fb13 159faim_export void aim_conn_close(struct aim_conn_t *deadconn)
9de3ca7e 160{
4d7c1bfb 161
162 faim_mutex_destroy(&deadconn->active);
163 faim_mutex_destroy(&deadconn->seqnum_lock);
9de3ca7e 164 if (deadconn->fd >= 3)
165 close(deadconn->fd);
9d2a3582 166 deadconn->fd = -1;
0252e8c0 167 if (deadconn->handlerlist)
168 aim_clearhandlers(deadconn);
3369f8d4 169
4d7c1bfb 170 return;
9de3ca7e 171}
172
be67fdd0 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 */
37ee990e 183faim_export struct aim_conn_t *aim_getconn_type(struct aim_session_t *sess,
184 int type)
9de3ca7e 185{
040457cc 186 struct aim_conn_t *cur;
187
188 faim_mutex_lock(&sess->connlistlock);
189 for (cur = sess->connlist; cur; cur = cur->next) {
22517493 190 if ((cur->type == type) && !(cur->status & AIM_CONN_STATUS_INPROGRESS))
040457cc 191 break;
192 }
193 faim_mutex_unlock(&sess->connlistlock);
194 return cur;
9de3ca7e 195}
196
be67fdd0 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 *
bb0dc593 208 */
209static 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))) {
646c6b52 234 faimdprintf(sess, 0, "proxyconnect: unable to resolve proxy name\n");
bb0dc593 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) {
646c6b52 247 faimdprintf(sess, 0, "proxyconnect: unable to connect to proxy\n");
bb0dc593 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
22517493 340 memset(&sa, 0, sizeof(struct sockaddr_in));
bb0dc593 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);
22517493 346
347 if (sess->flags & AIM_SESS_FLAGS_NONBLOCKCONNECT)
348 fcntl(fd, F_SETFL, O_NONBLOCK); /* XXX save flags */
349
bb0dc593 350 if (connect(fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) {
22517493 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 }
bb0dc593 358 close(fd);
359 fd = -1;
360 }
361 }
362 return fd;
363}
364
646c6b52 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 */
37ee990e 378faim_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;
37ee990e 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
be67fdd0 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)
9de3ca7e 413 *
be67fdd0 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.
9de3ca7e 418 *
9de3ca7e 419 * FIXME: Return errors in a more sane way.
420 *
421 */
78b3fb13 422faim_export struct aim_conn_t *aim_newconn(struct aim_session_t *sess,
423 int type, char *dest)
9de3ca7e 424{
425 struct aim_conn_t *connstruct;
426 int ret;
9de3ca7e 427 u_short port = FAIM_LOGIN_PORT;
a25832e6 428 char *host = NULL;
9de3ca7e 429 int i=0;
040457cc 430
e6b05d80 431 if ((connstruct=aim_conn_getnext(sess))==NULL)
9de3ca7e 432 return NULL;
433
040457cc 434 faim_mutex_lock(&connstruct->active);
435
9de3ca7e 436 connstruct->type = type;
437
e6b05d80 438 if (!dest) { /* just allocate a struct */
439 connstruct->fd = -1;
440 connstruct->status = 0;
040457cc 441 faim_mutex_unlock(&connstruct->active);
e6b05d80 442 return connstruct;
443 }
444
9de3ca7e 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
5ac21963 454 for(i=0;i<(int)strlen(dest);i++) {
e88ba395 455 if (dest[i] == ':') {
456 port = atoi(&(dest[i+1]));
457 break;
9de3ca7e 458 }
e88ba395 459 }
a25832e6 460 host = (char *)malloc(i+1);
461 strncpy(host, dest, i);
9ba272ca 462 host[i] = '\0';
463
bb0dc593 464 if ((ret = aim_proxyconnect(sess, host, port, &connstruct->status)) < 0) {
e88ba395 465 connstruct->fd = -1;
466 connstruct->status = (errno | AIM_CONN_STATUS_CONNERR);
bb0dc593 467 free(host);
040457cc 468 faim_mutex_unlock(&connstruct->active);
e88ba395 469 return connstruct;
bb0dc593 470 } else
471 connstruct->fd = ret;
a25832e6 472
040457cc 473 faim_mutex_unlock(&connstruct->active);
474
bb0dc593 475 free(host);
476
9de3ca7e 477 return connstruct;
478}
479
be67fdd0 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 */
78b3fb13 488faim_export int aim_conngetmaxfd(struct aim_session_t *sess)
9de3ca7e 489{
040457cc 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);
e88ba395 499
9de3ca7e 500 return j;
501}
502
be67fdd0 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 */
3b101546 512faim_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
be67fdd0 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
9de3ca7e 531 *
532 * Waits for a socket with data or for timeout, whichever comes first.
646c6b52 533 * See select(2).
9de3ca7e 534 *
b8d0da45 535 * Return codes in *status:
be67fdd0 536 * -1 error in select() (%NULL returned)
537 * 0 no events pending (%NULL returned)
538 * 1 outgoing data pending (%NULL returned)
b8d0da45 539 * 2 incoming data pending (connection with pending data returned)
540 *
040457cc 541 * XXX: we could probably stand to do a little courser locking here.
542 *
9de3ca7e 543 */
78b3fb13 544faim_export struct aim_conn_t *aim_select(struct aim_session_t *sess,
9e8c4225 545 struct timeval *timeout,
546 int *status)
9de3ca7e 547{
040457cc 548 struct aim_conn_t *cur;
22517493 549 fd_set fds, wfds;
040457cc 550 int maxfd = 0;
22517493 551 int i, haveconnecting = 0;
9de3ca7e 552
040457cc 553 faim_mutex_lock(&sess->connlistlock);
554 if (sess->connlist == NULL) {
555 faim_mutex_unlock(&sess->connlistlock);
68ac63c2 556 *status = -1;
557 return NULL;
040457cc 558 }
559 faim_mutex_unlock(&sess->connlistlock);
f1a5efe0 560
9de3ca7e 561 FD_ZERO(&fds);
22517493 562 FD_ZERO(&wfds);
040457cc 563 maxfd = 0;
564
565 faim_mutex_lock(&sess->connlistlock);
566 for (cur = sess->connlist; cur; cur = cur->next) {
9d2a3582 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) {
22517493 573 FD_SET(cur->fd, &wfds);
9e8c4225 574
22517493 575 haveconnecting++;
576 }
040457cc 577 FD_SET(cur->fd, &fds);
578 if (cur->fd > maxfd)
579 maxfd = cur->fd;
580 }
581 faim_mutex_unlock(&sess->connlistlock);
582
22517493 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) {
040457cc 603 faim_mutex_lock(&sess->connlistlock);
604 for (cur = sess->connlist; cur; cur = cur->next) {
22517493 605 if ((FD_ISSET(cur->fd, &fds)) ||
606 ((cur->status & AIM_CONN_STATUS_INPROGRESS) &&
607 FD_ISSET(cur->fd, &wfds))) {
040457cc 608 *status = 2;
609 faim_mutex_unlock(&sess->connlistlock);
22517493 610 return cur; /* XXX race condition here -- shouldnt unlock connlist */
040457cc 611 }
612 }
9797852c 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 */
b8d0da45 618
040457cc 619 faim_mutex_unlock(&sess->connlistlock);
646c6b52 620
b8d0da45 621 return NULL; /* no waiting or error, return */
9de3ca7e 622}
623
be67fdd0 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 */
78b3fb13 634faim_export int aim_conn_isready(struct aim_conn_t *conn)
9de3ca7e 635{
636 if (conn)
637 return (conn->status & 0x0001);
040457cc 638 return -1;
9de3ca7e 639}
640
be67fdd0 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 *
22517493 649 * This isn't real useful.
650 *
be67fdd0 651 */
78b3fb13 652faim_export int aim_conn_setstatus(struct aim_conn_t *conn, int status)
9de3ca7e 653{
040457cc 654 int val;
655
656 if (!conn)
9de3ca7e 657 return -1;
040457cc 658
659 faim_mutex_lock(&conn->active);
660 val = conn->status ^= status;
661 faim_mutex_unlock(&conn->active);
646c6b52 662
040457cc 663 return val;
9de3ca7e 664}
665
be67fdd0 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 */
78b3fb13 680faim_export int aim_conn_setlatency(struct aim_conn_t *conn, int newval)
9de3ca7e 681{
682 if (!conn)
683 return -1;
040457cc 684
685 faim_mutex_lock(&conn->active);
9de3ca7e 686 conn->forcedlatency = newval;
687 conn->lastactivity = 0; /* reset this just to make sure */
040457cc 688 faim_mutex_unlock(&conn->active);
9de3ca7e 689
690 return 0;
691}
a25832e6 692
be67fdd0 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 *
bb0dc593 700 * Call this with your SOCKS5 proxy server parameters before
be67fdd0 701 * the first call to aim_newconn(). If called with all %NULL
bb0dc593 702 * args, it will clear out a previously set proxy.
703 *
be67fdd0 704 * Set username and password to %NULL if not applicable.
bb0dc593 705 *
706 */
707faim_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
9f1a4013 725static void defaultdebugcb(struct aim_session_t *sess, int level, const char *format, va_list va)
726{
727 vfprintf(stderr, format, va);
728}
729
be67fdd0 730/**
731 * aim_session_init - Initializes a session structure
732 * @sess: Session to initialize
22517493 733 * @flags: Flags to use. Any of %AIM_SESS_FLAGS %OR'd together.
646c6b52 734 * @debuglevel: Level of debugging output (zero is least)
be67fdd0 735 *
736 * Sets up the initial values for a session.
737 *
738 */
646c6b52 739faim_export void aim_session_init(struct aim_session_t *sess, unsigned long flags, int debuglevel)
a25832e6 740{
a25832e6 741 if (!sess)
742 return;
743
040457cc 744 memset(sess, 0, sizeof(struct aim_session_t));
e88ba395 745 aim_connrst(sess);
a25832e6 746 sess->queue_outgoing = NULL;
747 sess->queue_incoming = NULL;
0c20631f 748 sess->pendingjoin = NULL;
9f20a4e3 749 sess->pendingjoinexchange = 0;
b13c9e13 750 aim_initsnachash(sess);
9f20a4e3 751 sess->msgcookies = NULL;
a25832e6 752 sess->snac_nextid = 0x00000001;
22517493 753
754 sess->flags = 0;
646c6b52 755 sess->debug = 0;
9f1a4013 756 sess->debugcb = defaultdebugcb;
757
758 sess->modlistv = NULL;
22517493 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;
a25832e6 766
e88ba395 767 /*
768 * This must always be set. Default to the queue-based
769 * version for back-compatibility.
770 */
b8c79ca7 771 aim_tx_setenqueue(sess, AIM_TX_QUEUED, NULL);
e88ba395 772
9f1a4013 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 */
793faim_export void aim_session_kill(struct aim_session_t *sess)
794{
795
796 aim_logoff(sess);
797
798 aim__shutdownmodules(sess);
799
a25832e6 800 return;
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 */
813faim_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
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 */
833faim_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
840faim_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) {
646c6b52 866 faimdprintf(sess, 0, "aim_conn_completeconnect: false alarm on %d\n", conn->fd);
22517493 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
646c6b52 887 if ((userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE)))
22517493 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}
dd60ff8b 895
896/*
897 * aim_logoff()
898 *
899 * Closes -ALL- open connections.
900 *
901 */
902faim_export int aim_logoff(struct aim_session_t *sess)
903{
646c6b52 904
dd60ff8b 905 aim_connrst(sess); /* in case we want to connect again */
906
907 return 0;
908
909}
910
This page took 0.334066 seconds and 5 git commands to generate.