Mercurial > pidgin.yaz
view libfaim/aim_rxqueue.c @ 761:a5e3f625389c
[gaim-migrate @ 771]
argh
committer: Tailor Script <tailor@pidgin.im>
author | Eric Warmenhoven <eric@warmenhoven.org> |
---|---|
date | Fri, 25 Aug 2000 00:51:25 +0000 |
parents | 6e318907bcce |
children | 9a123b171f46 |
line wrap: on
line source
/* * 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 <faim/aim.h> /* * 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, struct aim_conn_t *conn) { unsigned char generic[6]; struct command_rx_struct *newrx = NULL; if (!sess || !conn) return 0; if (conn->fd < 3) /* can happen when people abuse the interface */ 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; /* * 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 (read(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) { faimdprintf(1, "Bad incoming data!"); aim_conn_close(conn); faim_mutex_unlock(&conn->active); return -1; } /* allocate a new 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 */ /* we're doing OSCAR if we're here */ newrx->hdrtype = AIM_FRAMETYPE_OSCAR; /* store channel -- byte 2 */ newrx->hdr.oscar.type = (char) generic[1]; /* store seqnum -- bytes 3 and 4 */ newrx->hdr.oscar.seqnum = aimutil_get16(generic+2); /* store commandlen -- bytes 5 and 6 */ newrx->commandlen = aimutil_get16(generic+4); newrx->nofree = 0; /* free by default */ /* malloc for data portion */ 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 (read(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); newrx->conn = conn; 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 = newrx; } else { struct command_rx_struct *cur; /* * This append operation takes a while. It might be faster * if we maintain a pointer to the last entry in the queue * and just update that. Need to determine if the overhead * to maintain that is lower than the overhead for this loop. */ for (cur = sess->queue_incoming; cur->next; cur = cur->next) ; cur->next = newrx; } newrx->conn->lastactivity = time(NULL); return 0; } /* * Purge recieve queue of all handled commands (->handled==1). Also * allows for selective freeing using ->nofree so that the client can * keep the data for various purposes. * * If ->nofree is nonzero, the frame will be delinked from the global list, * but will not be free'ed. The client _must_ keep a pointer to the * data -- libfaim will not! If the client marks ->nofree but * does not keep a pointer, it's lost forever. * */ void aim_purge_rxqueue(struct aim_session_t *sess) { struct command_rx_struct *cur = NULL; struct command_rx_struct *tmp; if (sess->queue_incoming == NULL) return; if (sess->queue_incoming->next == NULL) { if (sess->queue_incoming->handled) { tmp = sess->queue_incoming; sess->queue_incoming = NULL; if (!tmp->nofree) { if (tmp->hdrtype == AIM_FRAMETYPE_OFT) free(tmp->hdr.oft.hdr2); free(tmp->data); free(tmp); } else tmp->next = NULL; } return; } for(cur = sess->queue_incoming; cur->next != NULL; ) { if (cur->next->handled) { 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 tmp->next = NULL; } cur = cur->next; /* * Be careful here. Because of the way we just * manipulated the pointer, cur may be NULL and * the for() will segfault doing the check unless * we find this case first. */ if (cur == NULL) break; } 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. */ 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; }