X-Git-Url: http://andersk.mit.edu/gitweb/libfaim.git/blobdiff_plain/b8d0da450de7ce933bd9cf9622baa650e469693d..313a06b7b4be217e90a17413862dc04552f693c3:/aim_rxqueue.c diff --git a/aim_rxqueue.c b/aim_rxqueue.c index 88721c4..a26648a 100644 --- a/aim_rxqueue.c +++ b/aim_rxqueue.c @@ -1,175 +1,151 @@ /* - aim_rxqueue.c - - This file contains the management routines for the receive - (incoming packet) queue. The actual packet handlers are in - aim_rxhandlers.c. - + * aim_rxqueue.c + * + * This file contains the management routines for the receive + * (incoming packet) queue. The actual packet handlers are in + * aim_rxhandlers.c. */ #include +#ifndef _WIN32 +#include +#endif /* - * This is a modified read() to make SURE we get the number - * of bytes we are told to, otherwise block. + * Since not all implementations support MSG_WAITALL, define + * an alternate guarenteed read function... * - * Modified to count errno (Sébastien Carpe ) - * -*/ -int aim_failsaferead(int fd, u_char *buf, int len) + * We keep recv() for systems that can do it because it means + * a single system call for the entire packet, where read may + * take more for a badly fragmented packet. + * + */ +faim_internal int aim_recv(int fd, void *buf, size_t count) { - int i = 0; - int j = 0; - int err_count=0; - - while ((i < len) && (!(i < 0))) - { - j = read(fd, &(buf[i]), len-i); - if ( (j < 0) && (errno != EAGAIN)) - return -errno; /* fail */ - else if (j==0) - { - err_count++; - if (err_count> MAX_READ_ERROR) { - /* - * Reached maximum number of allowed read errors. - * - * Lets suppose the connection is lost and errno didn't - * know it. - * - */ - return (-1); - } - } - else - i += j; /* success, continue */ - } - return i; +#ifdef MSG_WAITALL + return recv(fd, buf, count, MSG_WAITALL); +#else + int left, ret, cur = 0; + + left = count; + + while (left) { + ret = recv(fd, ((unsigned char *)buf)+cur, left, 0); + if (ret == -1) + return -1; + if (ret == 0) + return cur; + + cur += ret; + left -= ret; + } + + return cur; +#endif } -/* - * Grab as many command sequences as we can off the socket, and enqueue - * each command in the incoming event queue in a seperate struct. +/* + * Grab a single command sequence off the socket, and enqueue + * it in the incoming event queue in a seperate struct. */ -int aim_get_command(struct aim_session_t *sess) +faim_export int aim_get_command(struct aim_session_t *sess, struct aim_conn_t *conn) { - int i, readgood, j, isav, err; - int s; - fd_set fds; - struct timeval tv; - char generic[6]; - struct command_rx_struct *workingStruct = NULL; - struct aim_conn_t *conn = NULL; - int selstat = 0; + unsigned char generic[6]; + struct command_rx_struct *newrx = NULL; - faimdprintf(1, "Reading generic/unknown response..."); - - /* dont wait at all (ie, never call this unless something is there) */ - tv.tv_sec = 0; - tv.tv_usec = 0; - conn = aim_select(sess, &tv, &selstat); + if (!sess || !conn) + return 0; - if (conn==NULL) - return 0; /* nothing waiting */ + if (conn->fd < 3) /* can happen when people abuse the interface */ + return 0; - s = conn->fd; + if (conn->status & AIM_CONN_STATUS_INPROGRESS) + return aim_conn_completeconnect(sess, conn); - if (s < 3) - return 0; + /* + * Rendezvous (client-client) connections do not speak + * FLAP, so this function will break on them. + */ + if (conn->type == AIM_CONN_TYPE_RENDEZVOUS) + return aim_get_command_rendezvous(sess, conn); + if (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) + return 0; - FD_ZERO(&fds); - FD_SET(s, &fds); - tv.tv_sec = 0; /* wait, but only for 10us */ - tv.tv_usec = 10; - - generic[0] = 0x00; - - readgood = 0; - i = 0; - j = 0; - /* read first 6 bytes (the FLAP header only) off the socket */ - while ( (select(s+1, &fds, NULL, NULL, &tv) == 1) && (i < 6)) - { - if ((err = aim_failsaferead(s, &(generic[i]), 1)) < 0) - { - /* error is probably not recoverable...(must be a pessimistic day) */ - aim_conn_close(conn); - return err; - } - - if (readgood == 0) - { - if (generic[i] == 0x2a) - { - readgood = 1; - faimdprintf(1, "%x ", generic[i]); - i++; - } - else - { - faimdprintf(1, "skipping 0x%d ", generic[i]); - j++; - } - } - else - { - faimdprintf(1, "%x ", generic[i]); - i++; - } - FD_ZERO(&fds); - FD_SET(s, &fds); - tv.tv_sec= 2; - tv.tv_usec= 2; - } + /* + * Read FLAP header. Six bytes: + * + * 0 char -- Always 0x2a + * 1 char -- Channel ID. Usually 2 -- 1 and 4 are used during login. + * 2 short -- Sequence number + * 4 short -- Number of data bytes that follow. + */ + faim_mutex_lock(&conn->active); + if (aim_recv(conn->fd, generic, 6) < 6){ + aim_conn_close(conn); + faim_mutex_unlock(&conn->active); + return -1; + } /* * This shouldn't happen unless the socket breaks, the server breaks, * or we break. We must handle it just in case. */ if (generic[0] != 0x2a) { - printf("Bad incoming data!"); + faimdprintf(1, "Bad incoming data!"); + aim_conn_close(conn); + faim_mutex_unlock(&conn->active); return -1; } - isav = i; - /* allocate a new struct */ - workingStruct = (struct command_rx_struct *) malloc(sizeof(struct command_rx_struct)); - memset(workingStruct, 0x00, sizeof(struct command_rx_struct)); + if (!(newrx = (struct command_rx_struct *)malloc(sizeof(struct command_rx_struct)))) { + faim_mutex_unlock(&conn->active); + return -1; + } + memset(newrx, 0x00, sizeof(struct command_rx_struct)); + + newrx->lock = 1; /* lock the struct */ - workingStruct->lock = 1; /* lock the struct */ + /* we're doing OSCAR if we're here */ + newrx->hdrtype = AIM_FRAMETYPE_OSCAR; /* store channel -- byte 2 */ - workingStruct->type = (char) generic[1]; + newrx->hdr.oscar.type = (char) generic[1]; /* store seqnum -- bytes 3 and 4 */ - workingStruct->seqnum = aimutil_get16(generic+2); + newrx->hdr.oscar.seqnum = aimutil_get16(generic+2); /* store commandlen -- bytes 5 and 6 */ - workingStruct->commandlen = aimutil_get16(generic+4); + newrx->commandlen = aimutil_get16(generic+4); - workingStruct->nofree = 0; /* free by default */ + newrx->nofree = 0; /* free by default */ /* malloc for data portion */ - workingStruct->data = (u_char *) malloc(workingStruct->commandlen); + if (!(newrx->data = (u_char *) malloc(newrx->commandlen))) { + free(newrx); + faim_mutex_unlock(&conn->active); + return -1; + } /* read the data portion of the packet */ - if (aim_failsaferead(s, workingStruct->data, workingStruct->commandlen) < 0){ + if (aim_recv(conn->fd, newrx->data, newrx->commandlen) < newrx->commandlen){ + free(newrx->data); + free(newrx); aim_conn_close(conn); + faim_mutex_unlock(&conn->active); return -1; } + faim_mutex_unlock(&conn->active); - faimdprintf(1, " done. (%db+%db read, %db skipped)\n", isav, i, j); + newrx->conn = conn; - workingStruct->conn = conn; - - workingStruct->next = NULL; /* this will always be at the bottom */ - workingStruct->lock = 0; /* unlock */ + newrx->next = NULL; /* this will always be at the bottom */ + newrx->lock = 0; /* unlock */ /* enqueue this packet */ if (sess->queue_incoming == NULL) { - sess->queue_incoming = workingStruct; + sess->queue_incoming = newrx; } else { struct command_rx_struct *cur; @@ -181,10 +157,10 @@ int aim_get_command(struct aim_session_t *sess) */ for (cur = sess->queue_incoming; cur->next; cur = cur->next) ; - cur->next = workingStruct; + cur->next = newrx; } - workingStruct->conn->lastactivity = time(NULL); + newrx->conn->lastactivity = time(NULL); return 0; } @@ -200,7 +176,7 @@ int aim_get_command(struct aim_session_t *sess) * does not keep a pointer, it's lost forever. * */ -void aim_purge_rxqueue(struct aim_session_t *sess) +faim_export void aim_purge_rxqueue(struct aim_session_t *sess) { struct command_rx_struct *cur = NULL; struct command_rx_struct *tmp; @@ -214,6 +190,8 @@ void aim_purge_rxqueue(struct aim_session_t *sess) sess->queue_incoming = NULL; if (!tmp->nofree) { + if (tmp->hdrtype == AIM_FRAMETYPE_OFT) + free(tmp->hdr.oft.hdr2); free(tmp->data); free(tmp); } else @@ -227,6 +205,8 @@ void aim_purge_rxqueue(struct aim_session_t *sess) tmp = cur->next; cur->next = tmp->next; if (!tmp->nofree) { + if (tmp->hdrtype == AIM_FRAMETYPE_OFT) + free(tmp->hdr.oft.hdr2); free(tmp->data); free(tmp); } else @@ -246,3 +226,21 @@ void aim_purge_rxqueue(struct aim_session_t *sess) return; } + +/* + * Since aim_get_command will aim_conn_kill dead connections, we need + * to clean up the rxqueue of unprocessed connections on that socket. + * + * XXX: this is something that was handled better in the old connection + * handling method, but eh. + */ +faim_internal void aim_rxqueue_cleanbyconn(struct aim_session_t *sess, struct aim_conn_t *conn) +{ + struct command_rx_struct *currx; + + for (currx = sess->queue_incoming; currx; currx = currx->next) { + if ((!currx->handled) && (currx->conn == conn)) + currx->handled = 1; + } + return; +}