X-Git-Url: http://andersk.mit.edu/gitweb/libfaim.git/blobdiff_plain/7bed16929b8f47e2b957a019c1a7d9f83629f4c7..17d80b55c244944a8c0d2c93e5d483b871eacbf0:/aim_conn.c diff --git a/aim_conn.c b/aim_conn.c index b47b42b..7caef93 100644 --- a/aim_conn.c +++ b/aim_conn.c @@ -8,56 +8,151 @@ #include +/* + * Clears out connection list, killing remaining connections. + */ void aim_connrst(struct aim_session_t *sess) { - int i; - for (i = 0; i < AIM_CONN_MAX; i++) - { - sess->conns[i].fd = -1; - sess->conns[i].type = -1; - sess->conns[i].status = 0; - sess->conns[i].seqnum = 0; - sess->conns[i].lastactivity = 0; - sess->conns[i].forcedlatency = 0; - aim_clearhandlers(&(sess->conns[i])); - sess->conns[i].handlerlist = NULL; - } + faim_mutex_init(&sess->connlistlock); + if (sess->connlist) { + struct aim_conn_t *cur = sess->connlist, *tmp; + while(cur) { + tmp = cur->next; + aim_conn_close(cur); + free(cur); + cur = tmp; + } + } + sess->connlist = NULL; + return; } +/* + * Gets a new connection structure. + */ struct aim_conn_t *aim_conn_getnext(struct aim_session_t *sess) { - int i; - for (i=0;iconns[i].fd == -1) - return &(sess->conns[i]); - return NULL; + struct aim_conn_t *newconn, *cur; + + if (!(newconn = malloc(sizeof(struct aim_conn_t)))) + return NULL; + + memset(newconn, 0, sizeof(struct aim_conn_t)); + aim_conn_close(newconn); + newconn->next = NULL; + + faim_mutex_lock(&sess->connlistlock); + if (sess->connlist == NULL) + sess->connlist = newconn; + else { + for (cur = sess->connlist; cur->next; cur = cur->next) + ; + cur->next = newconn; + } + faim_mutex_unlock(&sess->connlistlock); + + return newconn; } -void aim_conn_close(struct aim_conn_t *deadconn) +static void aim_conn_init(struct aim_conn_t *deadconn) { - if (deadconn->fd >= 3) - close(deadconn->fd); + if (!deadconn) + return; + deadconn->fd = -1; + deadconn->subtype = -1; deadconn->type = -1; deadconn->seqnum = 0; deadconn->lastactivity = 0; deadconn->forcedlatency = 0; - aim_clearhandlers(deadconn); deadconn->handlerlist = NULL; - if (deadconn->priv) - free(deadconn->priv); deadconn->priv = NULL; + faim_mutex_init(&deadconn->active); + faim_mutex_init(&deadconn->seqnum_lock); + + return; +} + +void aim_conn_kill(struct aim_session_t *sess, struct aim_conn_t **deadconn) +{ + struct aim_conn_t *cur; + + if (!deadconn || !*deadconn) + return; + + faim_mutex_lock(&sess->connlistlock); + if (sess->connlist == NULL) + ; + else if (sess->connlist->next == NULL) { + if (sess->connlist == *deadconn) + sess->connlist = NULL; + } else { + cur = sess->connlist; + while (cur->next) { + if (cur->next == *deadconn) { + cur->next = cur->next->next; + break; + } + cur = cur->next; + } + } + faim_mutex_unlock(&sess->connlistlock); + + /* XXX: do we need this for txqueue too? */ + aim_rxqueue_cleanbyconn(sess, *deadconn); + + aim_conn_close(*deadconn); + if ((*deadconn)->priv) + free((*deadconn)->priv); + free(*deadconn); + deadconn = NULL; + + return; +} + +void aim_conn_close(struct aim_conn_t *deadconn) +{ + int typesav = -1, subtypesav = -1; + void *privsav = NULL; + + faim_mutex_destroy(&deadconn->active); + faim_mutex_destroy(&deadconn->seqnum_lock); + if (deadconn->fd >= 3) + close(deadconn->fd); + if (deadconn->handlerlist) + aim_clearhandlers(deadconn); + + typesav = deadconn->type; + subtypesav = deadconn->subtype; + + if (deadconn->priv && (deadconn->type != AIM_CONN_TYPE_RENDEZVOUS)) { + free(deadconn->priv); + deadconn->priv = NULL; + } + privsav = deadconn->priv; + + aim_conn_init(deadconn); + + deadconn->type = typesav; + deadconn->subtype = subtypesav; + deadconn->priv = privsav; + + return; } struct aim_conn_t *aim_getconn_type(struct aim_session_t *sess, int type) { - int i; - for (i=0; iconns[i].type == type) - return &(sess->conns[i]); - return NULL; + struct aim_conn_t *cur; + + faim_mutex_lock(&sess->connlistlock); + for (cur = sess->connlist; cur; cur = cur->next) { + if (cur->type == type) + break; + } + faim_mutex_unlock(&sess->connlistlock); + return cur; } /* @@ -79,12 +174,21 @@ struct aim_conn_t *aim_newconn(struct aim_session_t *sess, u_short port = FAIM_LOGIN_PORT; char *host = NULL; int i=0; - - if (!dest || ((connstruct=aim_conn_getnext(sess))==NULL)) + + if ((connstruct=aim_conn_getnext(sess))==NULL) return NULL; + faim_mutex_lock(&connstruct->active); + connstruct->type = type; + if (!dest) { /* just allocate a struct */ + connstruct->fd = -1; + connstruct->status = 0; + faim_mutex_unlock(&connstruct->active); + return connstruct; + } + /* * As of 23 Jul 1999, AOL now sends the port number, preceded by a * colon, in the BOS redirect. This fatally breaks all previous @@ -94,25 +198,24 @@ struct aim_conn_t *aim_newconn(struct aim_session_t *sess, * */ - for(i=0;istatus = (h_errno | AIM_CONN_STATUS_RESOLVERR); - return connstruct; - } + if (hp == NULL) { + connstruct->status = (h_errno | AIM_CONN_STATUS_RESOLVERR); + faim_mutex_unlock(&connstruct->active); + return connstruct; + } memset(&sa.sin_zero, 0, 8); sa.sin_port = htons(port); @@ -121,33 +224,43 @@ struct aim_conn_t *aim_newconn(struct aim_session_t *sess, connstruct->fd = socket(hp->h_addrtype, SOCK_STREAM, 0); ret = connect(connstruct->fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)); - if( ret < 0) - { - connstruct->fd = -1; - connstruct->status = (errno | AIM_CONN_STATUS_CONNERR); - return connstruct; - } + if(ret < 0) { + connstruct->fd = -1; + connstruct->status = (errno | AIM_CONN_STATUS_CONNERR); + faim_mutex_unlock(&connstruct->active); + return connstruct; + } + faim_mutex_unlock(&connstruct->active); + return connstruct; } int aim_conngetmaxfd(struct aim_session_t *sess) { - int i,j; - j=0; - for (i=0;iconns[i].fd > j) - j = sess->conns[i].fd; + int j = 0; + struct aim_conn_t *cur; + + faim_mutex_lock(&sess->connlistlock); + for (cur = sess->connlist; cur; cur = cur->next) { + if (cur->fd > j) + j = cur->fd; + } + faim_mutex_unlock(&sess->connlistlock); + return j; } int aim_countconn(struct aim_session_t *sess) { - int i,cnt; - cnt = 0; - for (i=0;iconns[i].fd > -1) - cnt++; + int cnt = 0; + struct aim_conn_t *cur; + + faim_mutex_lock(&sess->connlistlock); + for (cur = sess->connlist; cur; cur = cur->next) + cnt++; + faim_mutex_unlock(&sess->connlistlock); + return cnt; } @@ -157,115 +270,117 @@ int aim_countconn(struct aim_session_t *sess) * Waits for a socket with data or for timeout, whichever comes first. * See select(2). * + * Return codes in *status: + * -1 error in select() (NULL returned) + * 0 no events pending (NULL returned) + * 1 outgoing data pending (NULL returned) + * 2 incoming data pending (connection with pending data returned) + * + * XXX: we could probably stand to do a little courser locking here. + * */ struct aim_conn_t *aim_select(struct aim_session_t *sess, - struct timeval *timeout) + struct timeval *timeout, int *status) { + struct aim_conn_t *cur; fd_set fds; - fd_set errfds; + int maxfd = 0; int i; - if (aim_countconn(sess) <= 0) - return 0; + faim_mutex_lock(&sess->connlistlock); + if (sess->connlist == NULL) { + faim_mutex_unlock(&sess->connlistlock); + *status = -1; + return NULL; + } + faim_mutex_unlock(&sess->connlistlock); /* * If we have data waiting to be sent, return immediatly */ - if (sess->queue_outgoing) - return (struct aim_conn_t *)1; + if (sess->queue_outgoing != NULL) { + *status = 1; + return NULL; + } FD_ZERO(&fds); - FD_ZERO(&errfds); - - for(i=0;iconns[i].fd>-1) - { - FD_SET(sess->conns[i].fd, &fds); - FD_SET(sess->conns[i].fd, &errfds); + maxfd = 0; + + faim_mutex_lock(&sess->connlistlock); + for (cur = sess->connlist; cur; cur = cur->next) { + FD_SET(cur->fd, &fds); + if (cur->fd > maxfd) + maxfd = cur->fd; + } + faim_mutex_unlock(&sess->connlistlock); + + if ((i = select(maxfd+1, &fds, NULL, NULL, timeout))>=1) { + faim_mutex_lock(&sess->connlistlock); + for (cur = sess->connlist; cur; cur = cur->next) { + if (FD_ISSET(cur->fd, &fds)) { + *status = 2; + faim_mutex_unlock(&sess->connlistlock); + return cur; } - - i = select(aim_conngetmaxfd(sess)+1, &fds, NULL, &errfds, timeout); - if (i>=1) - { - int j; - for (j=0;jconns[j].fd > -1) - { - if ((FD_ISSET(sess->conns[j].fd, &errfds))) - { - /* got an exception; close whats left of it up */ - aim_conn_close(&(sess->conns[j])); - return (struct aim_conn_t *)-1; - } - else if ((FD_ISSET(sess->conns[j].fd, &fds))) - return &(sess->conns[j]); /* return the first waiting struct */ - } - } - /* should never get here */ } - else - return (struct aim_conn_t *)i; /* no waiting or error, return -- FIXME: return type funnies */ - return NULL; /* NO REACH */ + } + + faim_mutex_unlock(&sess->connlistlock); + *status = i; /* may be 0 or -1 */ + return NULL; /* no waiting or error, return */ } int aim_conn_isready(struct aim_conn_t *conn) { if (conn) return (conn->status & 0x0001); - else - return -1; + return -1; } int aim_conn_setstatus(struct aim_conn_t *conn, int status) { - if (conn) - return (conn->status ^= status); - else + int val; + + if (!conn) return -1; + + faim_mutex_lock(&conn->active); + val = conn->status ^= status; + faim_mutex_unlock(&conn->active); + return val; } int aim_conn_setlatency(struct aim_conn_t *conn, int newval) { if (!conn) return -1; - + + faim_mutex_lock(&conn->active); conn->forcedlatency = newval; conn->lastactivity = 0; /* reset this just to make sure */ + faim_mutex_unlock(&conn->active); return 0; } void aim_session_init(struct aim_session_t *sess) { - int i; - if (!sess) return; - memset(sess->logininfo.screen_name, 0x00, MAXSNLEN); - sess->logininfo.BOSIP = NULL; - memset(sess->logininfo.cookie, 0x00, AIM_COOKIELEN); - sess->logininfo.email = NULL; - sess->logininfo.regstatus = 0x00; - - for (i = 0; i < AIM_CONN_MAX; i++) - { - sess->conns[i].fd = -1; - sess->conns[i].type = -1; - sess->conns[i].status = 0; - sess->conns[i].seqnum = 0; - sess->conns[i].lastactivity = 0; - sess->conns[i].forcedlatency = 0; - sess->conns[i].handlerlist = NULL; - sess->conns[i].priv = NULL; - } - + memset(sess, 0, sizeof(struct aim_session_t)); + aim_connrst(sess); sess->queue_outgoing = NULL; sess->queue_incoming = NULL; sess->pendingjoin = NULL; - sess->outstanding_snacs = NULL; + aim_initsnachash(sess); sess->snac_nextid = 0x00000001; + /* + * This must always be set. Default to the queue-based + * version for back-compatibility. + */ + sess->tx_enqueue = &aim_tx_enqueue__queuebased; + return; }