]> andersk Git - libfaim.git/blob - aim_rxqueue.c
003c1a20fc8413f81c588636c367c6f3897dd801
[libfaim.git] / aim_rxqueue.c
1 /*
2  *  aim_rxqueue.c
3  *
4  * This file contains the management routines for the receive
5  * (incoming packet) queue.  The actual packet handlers are in
6  * aim_rxhandlers.c.
7  */
8
9 #include <faim/aim.h> 
10
11 /*
12  * Grab a single command sequence off the socket, and enqueue
13  * it in the incoming event queue in a seperate struct.
14  */
15 int aim_get_command(struct aim_session_t *sess, struct aim_conn_t *conn)
16 {
17   unsigned char generic[6]; 
18   struct command_rx_struct *newrx = NULL;
19
20   if (!sess || !conn)
21     return 0;
22
23   if (conn->fd < 3)  /* can happen when people abuse the interface */
24     return 0;
25
26   /*
27    * Rendezvous (client-client) connections do not speak
28    * FLAP, so this function will break on them.
29    */
30   if (conn->type == AIM_CONN_TYPE_RENDEZVOUS) 
31     return aim_get_command_rendezvous(sess, conn);
32
33   /*
34    * Read FLAP header.  Six bytes:
35    *    
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.
40    */
41   faim_mutex_lock(&conn->active);
42   if (read(conn->fd, generic, 6) < 6){
43     aim_conn_close(conn);
44     faim_mutex_unlock(&conn->active);
45     return -1;
46   }
47
48   /*
49    * This shouldn't happen unless the socket breaks, the server breaks,
50    * or we break.  We must handle it just in case.
51    */
52   if (generic[0] != 0x2a) {
53     faimdprintf(1, "Bad incoming data!");
54     faim_mutex_unlock(&conn->active);
55     return -1;
56   }     
57
58   /* allocate a new struct */
59   if (!(newrx = (struct command_rx_struct *)malloc(sizeof(struct command_rx_struct)))) {
60     faim_mutex_unlock(&conn->active);
61     return -1;
62   }
63   memset(newrx, 0x00, sizeof(struct command_rx_struct));
64
65   newrx->lock = 1;  /* lock the struct */
66
67   /* we're doing OSCAR if we're here */
68   newrx->hdrtype = AIM_FRAMETYPE_OSCAR;
69
70   /* store channel -- byte 2 */
71   newrx->hdr.oscar.type = (char) generic[1];
72
73   /* store seqnum -- bytes 3 and 4 */
74   newrx->hdr.oscar.seqnum = aimutil_get16(generic+2);
75
76   /* store commandlen -- bytes 5 and 6 */
77   newrx->commandlen = aimutil_get16(generic+4);
78
79   newrx->nofree = 0; /* free by default */
80
81   /* malloc for data portion */
82   if (!(newrx->data = (u_char *) malloc(newrx->commandlen))) {
83     free(newrx);
84     faim_mutex_unlock(&conn->active);
85     return -1;
86   }
87
88   /* read the data portion of the packet */
89   if (read(conn->fd, newrx->data, newrx->commandlen) < newrx->commandlen){
90     free(newrx->data);
91     free(newrx);
92     aim_conn_close(conn);
93     faim_mutex_unlock(&conn->active);
94     return -1;
95   }
96   faim_mutex_unlock(&conn->active);
97
98   newrx->conn = conn;
99
100   newrx->next = NULL;  /* this will always be at the bottom */
101   newrx->lock = 0; /* unlock */
102
103   /* enqueue this packet */
104   if (sess->queue_incoming == NULL) {
105     sess->queue_incoming = newrx;
106   } else {
107     struct command_rx_struct *cur;
108
109     /*
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.
114      */
115     for (cur = sess->queue_incoming; cur->next; cur = cur->next)
116       ;
117     cur->next = newrx;
118   }
119   
120   newrx->conn->lastactivity = time(NULL);
121
122   return 0;  
123 }
124
125 int aim_get_command_rendezvous(struct aim_session_t *sess, struct aim_conn_t *conn)
126 {
127   unsigned char hdrbuf1[6];
128   unsigned char *hdr = NULL;
129   int hdrlen, hdrtype;
130   int payloadlength = 0;
131   int flags = 0;
132   char *snptr = NULL;
133
134   if (read(conn->fd, hdrbuf1, 6) < 6) {
135     perror("read");
136     printf("faim: rend: read error\n");
137     aim_conn_kill(sess, &conn);
138     return -1;
139   }
140
141   hdrlen = aimutil_get16(hdrbuf1+4);
142
143   hdrlen -= 6;
144   hdr = malloc(hdrlen);
145
146   faim_mutex_lock(&conn->active);
147   if (read(conn->fd, hdr, hdrlen) < hdrlen) {
148     perror("read");
149     printf("faim: rend: read2 error\n");
150     free(hdr);
151     faim_mutex_unlock(&conn->active);
152     aim_conn_kill(sess, &conn);
153     return -1;
154   }
155   
156   hdrtype = aimutil_get16(hdr);  
157
158   switch (hdrtype) {
159   case 0x0001: {
160     payloadlength = aimutil_get32(hdr+22);
161     flags = aimutil_get16(hdr+32);
162     snptr = hdr+38;
163
164     printf("OFT frame: %04x / %04x / %04x / %s\n", hdrtype, payloadlength, flags, snptr);
165
166     if (flags == 0x000e) {
167       printf("directim: %s has started typing\n", snptr);
168     } else if ((flags == 0x0000) && payloadlength) {
169       unsigned char *buf;
170       buf = malloc(payloadlength+1);
171
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) {
175         perror("read");
176         printf("faim: rend: read3 error\n");
177         free(buf);
178         faim_mutex_unlock(&conn->active);
179         aim_conn_kill(sess, &conn);
180         return -1;
181       }
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);
186       free(buf);
187     }
188     break;
189   }
190   default:
191     printf("OFT frame: type %04x\n", hdrtype);  
192     /* data connection may be unreliable here */
193     break;
194   } /* switch */
195
196   free(hdr);
197   
198   return 0;
199 }
200
201 /*
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.  
205  *
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.
210  *
211  */
212 void aim_purge_rxqueue(struct aim_session_t *sess)
213 {
214   struct command_rx_struct *cur = NULL;
215   struct command_rx_struct *tmp;
216
217   if (sess->queue_incoming == NULL)
218     return;
219   
220   if (sess->queue_incoming->next == NULL) {
221     if (sess->queue_incoming->handled) {
222       tmp = sess->queue_incoming;
223       sess->queue_incoming = NULL;
224
225       if (!tmp->nofree) {
226         if (tmp->hdrtype == AIM_FRAMETYPE_OFT)
227           free(tmp->hdr.oft.hdr2);
228         free(tmp->data);
229         free(tmp);
230       } else
231         tmp->next = NULL;
232     }
233     return;
234   }
235
236   for(cur = sess->queue_incoming; cur->next != NULL; ) {
237     if (cur->next->handled) {
238       tmp = cur->next;
239       cur->next = tmp->next;
240       if (!tmp->nofree) {
241         if (tmp->hdrtype == AIM_FRAMETYPE_OFT)
242           free(tmp->hdr.oft.hdr2);
243         free(tmp->data);
244         free(tmp);
245       } else
246         tmp->next = NULL;
247     }   
248     cur = cur->next;
249
250     /* 
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.
255      */
256     if (cur == NULL)    
257       break;
258   }
259
260   return;
261 }
This page took 0.055782 seconds and 3 git commands to generate.