4 * This file contains the management routines for the receive
5 * (incoming packet) queue. The actual packet handlers are in
12 * Grab a single command sequence off the socket, and enqueue
13 * it in the incoming event queue in a seperate struct.
15 int aim_get_command(struct aim_session_t *sess, struct aim_conn_t *conn)
17 unsigned char generic[6];
18 struct command_rx_struct *newrx = NULL;
23 if (conn->fd < 3) /* can happen when people abuse the interface */
27 * Rendezvous (client-client) connections do not speak
28 * FLAP, so this function will break on them.
30 if (conn->type == AIM_CONN_TYPE_RENDEZVOUS)
31 return aim_get_command_rendezvous(sess, conn);
34 * Read FLAP header. Six bytes:
36 * 0 char -- Always 0x2a
37 * 1 char -- Channel ID. Usually 2 -- 1 and 4 are used during login.
38 * 2 short -- Sequence number
39 * 4 short -- Number of data bytes that follow.
41 faim_mutex_lock(&conn->active);
42 if (read(conn->fd, generic, 6) < 6){
43 aim_conn_kill(sess, &conn);
44 faim_mutex_unlock(&conn->active);
49 * This shouldn't happen unless the socket breaks, the server breaks,
50 * or we break. We must handle it just in case.
52 if (generic[0] != 0x2a) {
53 faimdprintf(1, "Bad incoming data!");
54 faim_mutex_unlock(&conn->active);
58 /* allocate a new struct */
59 if (!(newrx = (struct command_rx_struct *)malloc(sizeof(struct command_rx_struct)))) {
60 faim_mutex_unlock(&conn->active);
63 memset(newrx, 0x00, sizeof(struct command_rx_struct));
65 newrx->lock = 1; /* lock the struct */
67 /* we're doing OSCAR if we're here */
68 newrx->hdrtype = AIM_FRAMETYPE_OSCAR;
70 /* store channel -- byte 2 */
71 newrx->hdr.oscar.type = (char) generic[1];
73 /* store seqnum -- bytes 3 and 4 */
74 newrx->hdr.oscar.seqnum = aimutil_get16(generic+2);
76 /* store commandlen -- bytes 5 and 6 */
77 newrx->commandlen = aimutil_get16(generic+4);
79 newrx->nofree = 0; /* free by default */
81 /* malloc for data portion */
82 if (!(newrx->data = (u_char *) malloc(newrx->commandlen))) {
84 faim_mutex_unlock(&conn->active);
88 /* read the data portion of the packet */
89 if (read(conn->fd, newrx->data, newrx->commandlen) < newrx->commandlen){
92 aim_conn_kill(sess, &conn);
93 faim_mutex_unlock(&conn->active);
96 faim_mutex_unlock(&conn->active);
100 newrx->next = NULL; /* this will always be at the bottom */
101 newrx->lock = 0; /* unlock */
103 /* enqueue this packet */
104 if (sess->queue_incoming == NULL) {
105 sess->queue_incoming = newrx;
107 struct command_rx_struct *cur;
110 * This append operation takes a while. It might be faster
111 * if we maintain a pointer to the last entry in the queue
112 * and just update that. Need to determine if the overhead
113 * to maintain that is lower than the overhead for this loop.
115 for (cur = sess->queue_incoming; cur->next; cur = cur->next)
120 newrx->conn->lastactivity = time(NULL);
125 int aim_get_command_rendezvous(struct aim_session_t *sess, struct aim_conn_t *conn)
127 unsigned char hdrbuf1[6];
128 unsigned char *hdr = NULL;
130 int payloadlength = 0;
134 if (read(conn->fd, hdrbuf1, 6) < 6) {
136 printf("faim: rend: read error\n");
137 aim_conn_kill(sess, &conn);
141 hdrlen = aimutil_get16(hdrbuf1+4);
144 hdr = malloc(hdrlen);
146 faim_mutex_lock(&conn->active);
147 if (read(conn->fd, hdr, hdrlen) < hdrlen) {
149 printf("faim: rend: read2 error\n");
151 faim_mutex_unlock(&conn->active);
152 aim_conn_kill(sess, &conn);
156 hdrtype = aimutil_get16(hdr);
160 payloadlength = aimutil_get32(hdr+22);
161 flags = aimutil_get16(hdr+32);
164 printf("OFT frame: %04x / %04x / %04x / %s\n", hdrtype, payloadlength, flags, snptr);
166 if (flags == 0x000e) {
167 printf("directim: %s has started typing\n", snptr);
168 } else if ((flags == 0x0000) && payloadlength) {
170 buf = malloc(payloadlength+1);
172 /* XXX theres got to be a better way */
173 faim_mutex_lock(&conn->active);
174 if (recv(conn->fd, buf, payloadlength, MSG_WAITALL) < payloadlength) {
176 printf("faim: rend: read3 error\n");
178 faim_mutex_unlock(&conn->active);
179 aim_conn_kill(sess, &conn);
182 faim_mutex_unlock(&conn->active);
183 buf[payloadlength] = '\0';
184 printf("directim: %s/%04x/%04x/%s\n", snptr, payloadlength, flags, buf);
185 aim_send_im_direct(sess, conn, buf);
191 printf("OFT frame: type %04x\n", hdrtype);
192 /* data connection may be unreliable here */
202 * Purge recieve queue of all handled commands (->handled==1). Also
203 * allows for selective freeing using ->nofree so that the client can
204 * keep the data for various purposes.
206 * If ->nofree is nonzero, the frame will be delinked from the global list,
207 * but will not be free'ed. The client _must_ keep a pointer to the
208 * data -- libfaim will not! If the client marks ->nofree but
209 * does not keep a pointer, it's lost forever.
212 void aim_purge_rxqueue(struct aim_session_t *sess)
214 struct command_rx_struct *cur = NULL;
215 struct command_rx_struct *tmp;
217 if (sess->queue_incoming == NULL)
220 if (sess->queue_incoming->next == NULL) {
221 if (sess->queue_incoming->handled) {
222 tmp = sess->queue_incoming;
223 sess->queue_incoming = NULL;
226 if (tmp->hdrtype == AIM_FRAMETYPE_OFT)
227 free(tmp->hdr.oft.hdr2);
236 for(cur = sess->queue_incoming; cur->next != NULL; ) {
237 if (cur->next->handled) {
239 cur->next = tmp->next;
241 if (tmp->hdrtype == AIM_FRAMETYPE_OFT)
242 free(tmp->hdr.oft.hdr2);
251 * Be careful here. Because of the way we just
252 * manipulated the pointer, cur may be NULL and
253 * the for() will segfault doing the check unless
254 * we find this case first.
264 * Since aim_get_command will aim_conn_kill dead connections, we need
265 * to clean up the rxqueue of unprocessed connections on that socket.
267 * XXX: this is something that was handled better in the old connection
268 * handling method, but eh.
270 void aim_rxqueue_cleanbyconn(struct aim_session_t *sess, struct aim_conn_t *conn)
272 struct command_rx_struct *currx;
274 for (currx = sess->queue_incoming; currx; currx = currx->next) {
275 if ((!currx->handled) && (currx->conn == conn))