4 * This file contains the management routines for the receive
5 * (incoming packet) queue. The actual packet handlers are in
12 * Since not all implementations support MSG_WAITALL, define
13 * an alternate guarenteed read function...
15 static int aim_recv(int fd, void *buf, size_t count)
17 #ifdef FAIM_HAS_MSG_WAITALL
18 return recv(fd, buf, count, MSG_WAITALL);
20 int left, ret, cur = 0;
25 ret = read(fd, buf+cur, left);
40 * Grab a single command sequence off the socket, and enqueue
41 * it in the incoming event queue in a seperate struct.
43 int aim_get_command(struct aim_session_t *sess, struct aim_conn_t *conn)
45 unsigned char generic[6];
46 struct command_rx_struct *newrx = NULL;
51 if (conn->fd < 3) /* can happen when people abuse the interface */
55 * Rendezvous (client-client) connections do not speak
56 * FLAP, so this function will break on them.
58 if (conn->type == AIM_CONN_TYPE_RENDEZVOUS)
59 return aim_get_command_rendezvous(sess, conn);
60 if (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT)
64 * Read FLAP header. Six bytes:
66 * 0 char -- Always 0x2a
67 * 1 char -- Channel ID. Usually 2 -- 1 and 4 are used during login.
68 * 2 short -- Sequence number
69 * 4 short -- Number of data bytes that follow.
71 faim_mutex_lock(&conn->active);
72 if (aim_recv(conn->fd, generic, 6) < 6){
74 faim_mutex_unlock(&conn->active);
79 * This shouldn't happen unless the socket breaks, the server breaks,
80 * or we break. We must handle it just in case.
82 if (generic[0] != 0x2a) {
83 faimdprintf(1, "Bad incoming data!");
85 faim_mutex_unlock(&conn->active);
89 /* allocate a new struct */
90 if (!(newrx = (struct command_rx_struct *)malloc(sizeof(struct command_rx_struct)))) {
91 faim_mutex_unlock(&conn->active);
94 memset(newrx, 0x00, sizeof(struct command_rx_struct));
96 newrx->lock = 1; /* lock the struct */
98 /* we're doing OSCAR if we're here */
99 newrx->hdrtype = AIM_FRAMETYPE_OSCAR;
101 /* store channel -- byte 2 */
102 newrx->hdr.oscar.type = (char) generic[1];
104 /* store seqnum -- bytes 3 and 4 */
105 newrx->hdr.oscar.seqnum = aimutil_get16(generic+2);
107 /* store commandlen -- bytes 5 and 6 */
108 newrx->commandlen = aimutil_get16(generic+4);
110 newrx->nofree = 0; /* free by default */
112 /* malloc for data portion */
113 if (!(newrx->data = (u_char *) malloc(newrx->commandlen))) {
115 faim_mutex_unlock(&conn->active);
119 /* read the data portion of the packet */
120 if (aim_recv(conn->fd, newrx->data, newrx->commandlen) < newrx->commandlen){
123 aim_conn_close(conn);
124 faim_mutex_unlock(&conn->active);
127 faim_mutex_unlock(&conn->active);
131 newrx->next = NULL; /* this will always be at the bottom */
132 newrx->lock = 0; /* unlock */
134 /* enqueue this packet */
135 if (sess->queue_incoming == NULL) {
136 sess->queue_incoming = newrx;
138 struct command_rx_struct *cur;
141 * This append operation takes a while. It might be faster
142 * if we maintain a pointer to the last entry in the queue
143 * and just update that. Need to determine if the overhead
144 * to maintain that is lower than the overhead for this loop.
146 for (cur = sess->queue_incoming; cur->next; cur = cur->next)
151 newrx->conn->lastactivity = time(NULL);
157 * Purge recieve queue of all handled commands (->handled==1). Also
158 * allows for selective freeing using ->nofree so that the client can
159 * keep the data for various purposes.
161 * If ->nofree is nonzero, the frame will be delinked from the global list,
162 * but will not be free'ed. The client _must_ keep a pointer to the
163 * data -- libfaim will not! If the client marks ->nofree but
164 * does not keep a pointer, it's lost forever.
167 void aim_purge_rxqueue(struct aim_session_t *sess)
169 struct command_rx_struct *cur = NULL;
170 struct command_rx_struct *tmp;
172 if (sess->queue_incoming == NULL)
175 if (sess->queue_incoming->next == NULL) {
176 if (sess->queue_incoming->handled) {
177 tmp = sess->queue_incoming;
178 sess->queue_incoming = NULL;
181 if (tmp->hdrtype == AIM_FRAMETYPE_OFT)
182 free(tmp->hdr.oft.hdr2);
191 for(cur = sess->queue_incoming; cur->next != NULL; ) {
192 if (cur->next->handled) {
194 cur->next = tmp->next;
196 if (tmp->hdrtype == AIM_FRAMETYPE_OFT)
197 free(tmp->hdr.oft.hdr2);
206 * Be careful here. Because of the way we just
207 * manipulated the pointer, cur may be NULL and
208 * the for() will segfault doing the check unless
209 * we find this case first.
219 * Since aim_get_command will aim_conn_kill dead connections, we need
220 * to clean up the rxqueue of unprocessed connections on that socket.
222 * XXX: this is something that was handled better in the old connection
223 * handling method, but eh.
225 void aim_rxqueue_cleanbyconn(struct aim_session_t *sess, struct aim_conn_t *conn)
227 struct command_rx_struct *currx;
229 for (currx = sess->queue_incoming; currx; currx = currx->next) {
230 if ((!currx->handled) && (currx->conn == conn))