X-Git-Url: http://andersk.mit.edu/gitweb/libfaim.git/blobdiff_plain/f1a5efe0f353b6c28d4d962b3416329024771cef..f0a7908e6ac789e81e591519d5554ea84ba8feb9:/aim_conn.c diff --git a/aim_conn.c b/aim_conn.c index 5cb4a79..061409f 100644 --- a/aim_conn.c +++ b/aim_conn.c @@ -8,30 +8,83 @@ #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, NULL); + 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_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); + + aim_conn_close(*deadconn); + free(*deadconn); + deadconn = NULL; + + return; } void aim_conn_close(struct aim_conn_t *deadconn) @@ -43,21 +96,28 @@ void aim_conn_close(struct aim_conn_t *deadconn) deadconn->seqnum = 0; deadconn->lastactivity = 0; deadconn->forcedlatency = 0; - aim_clearhandlers(deadconn); + if (deadconn->handlerlist) + aim_clearhandlers(deadconn); deadconn->handlerlist = NULL; if (deadconn->priv) free(deadconn->priv); deadconn->priv = NULL; + faim_mutex_init(&deadconn->active, NULL); + faim_mutex_init(&deadconn->seqnum_lock, NULL); } 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,15 +139,18 @@ struct aim_conn_t *aim_newconn(struct aim_session_t *sess, u_short port = FAIM_LOGIN_PORT; char *host = NULL; int i=0; - + 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; } @@ -100,25 +163,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); @@ -127,33 +189,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; } @@ -169,15 +241,23 @@ int aim_countconn(struct aim_session_t *sess) * 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, int *status) { + struct aim_conn_t *cur; fd_set fds; + int maxfd = 0; int i; - if (aim_countconn(sess) <= 0) + faim_mutex_lock(&sess->connlistlock); + if (sess->connlist == NULL) { + faim_mutex_unlock(&sess->connlistlock); return 0; + } + faim_mutex_unlock(&sess->connlistlock); /* * If we have data waiting to be sent, return immediatly @@ -188,24 +268,28 @@ struct aim_conn_t *aim_select(struct aim_session_t *sess, } FD_ZERO(&fds); - - for(i=0;iconns[i].fd>-1) - FD_SET(sess->conns[i].fd, &fds); - - if ((i = select(aim_conngetmaxfd(sess)+1, &fds, NULL, NULL, timeout))>=1) { - int j; - for (j=0;jconns[j].fd > -1) { - if ((FD_ISSET(sess->conns[j].fd, &fds))) { - *status = 2; - return &(sess->conns[j]); /* return the first waiting struct */ - } - } - } - /* should never get here */ + 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; + } + } } + faim_mutex_unlock(&sess->connlistlock); *status = i; /* may be 0 or -1 */ return NULL; /* no waiting or error, return */ } @@ -214,59 +298,53 @@ 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; 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; }