]> andersk Git - libfaim.git/blob - aim_rxqueue.c
Fixed makefile.
[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   u_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    * Read FLAP header.  Six bytes:
28    *    
29    *   0 char  -- Always 0x2a
30    *   1 char  -- Channel ID.  Usually 2 -- 1 and 4 are used during login.
31    *   2 short -- Sequence number 
32    *   4 short -- Number of data bytes that follow.
33    */
34   faim_mutex_lock(&conn->active);
35   if (read(conn->fd, generic, 6) < 6){
36     aim_conn_close(conn);
37     faim_mutex_unlock(&conn->active);
38     return -1;
39   }
40   faim_mutex_unlock(&conn->active);
41
42   /*
43    * This shouldn't happen unless the socket breaks, the server breaks,
44    * or we break.  We must handle it just in case.
45    */
46   if (generic[0] != 0x2a) {
47     faimdprintf(1, "Bad incoming data!");
48     return -1;
49   }     
50
51   /* allocate a new struct */
52   newrx = (struct command_rx_struct *)malloc(sizeof(struct command_rx_struct));
53   if (!newrx)
54     return -1;
55   memset(newrx, 0x00, sizeof(struct command_rx_struct));
56
57   newrx->lock = 1;  /* lock the struct */
58
59   /* store channel -- byte 2 */
60   newrx->type = (char) generic[1];
61
62   /* store seqnum -- bytes 3 and 4 */
63   newrx->seqnum = aimutil_get16(generic+2);
64
65   /* store commandlen -- bytes 5 and 6 */
66   newrx->commandlen = aimutil_get16(generic+4);
67
68   newrx->nofree = 0; /* free by default */
69
70   /* malloc for data portion */
71   newrx->data = (u_char *) malloc(newrx->commandlen);
72   if (!newrx->data) {
73     free(newrx);
74     return -1;
75   }
76
77   /* read the data portion of the packet */
78   faim_mutex_lock(&conn->active);
79   if (read(conn->fd, newrx->data, newrx->commandlen) < newrx->commandlen){
80     free(newrx->data);
81     free(newrx);
82     aim_conn_close(conn);
83     faim_mutex_unlock(&conn->active);
84     return -1;
85   }
86   faim_mutex_unlock(&conn->active);
87
88   newrx->conn = conn;
89
90   newrx->next = NULL;  /* this will always be at the bottom */
91   newrx->lock = 0; /* unlock */
92
93   /* enqueue this packet */
94   if (sess->queue_incoming == NULL) {
95     sess->queue_incoming = newrx;
96   } else {
97     struct command_rx_struct *cur;
98
99     /*
100      * This append operation takes a while.  It might be faster
101      * if we maintain a pointer to the last entry in the queue
102      * and just update that.  Need to determine if the overhead
103      * to maintain that is lower than the overhead for this loop.
104      */
105     for (cur = sess->queue_incoming; cur->next; cur = cur->next)
106       ;
107     cur->next = newrx;
108   }
109   
110   newrx->conn->lastactivity = time(NULL);
111
112   return 0;  
113 }
114
115 /*
116  * Purge recieve queue of all handled commands (->handled==1).  Also
117  * allows for selective freeing using ->nofree so that the client can
118  * keep the data for various purposes.  
119  *
120  * If ->nofree is nonzero, the frame will be delinked from the global list, 
121  * but will not be free'ed.  The client _must_ keep a pointer to the
122  * data -- libfaim will not!  If the client marks ->nofree but
123  * does not keep a pointer, it's lost forever.
124  *
125  */
126 void aim_purge_rxqueue(struct aim_session_t *sess)
127 {
128   struct command_rx_struct *cur = NULL;
129   struct command_rx_struct *tmp;
130
131   if (sess->queue_incoming == NULL)
132     return;
133   
134   if (sess->queue_incoming->next == NULL) {
135     if (sess->queue_incoming->handled) {
136       tmp = sess->queue_incoming;
137       sess->queue_incoming = NULL;
138
139       if (!tmp->nofree) {
140         free(tmp->data);
141         free(tmp);
142       } else
143         tmp->next = NULL;
144     }
145     return;
146   }
147
148   for(cur = sess->queue_incoming; cur->next != NULL; ) {
149     if (cur->next->handled) {
150       tmp = cur->next;
151       cur->next = tmp->next;
152       if (!tmp->nofree) {
153         free(tmp->data);
154         free(tmp);
155       } else
156         tmp->next = NULL;
157     }   
158     cur = cur->next;
159
160     /* 
161      * Be careful here.  Because of the way we just
162      * manipulated the pointer, cur may be NULL and 
163      * the for() will segfault doing the check unless
164      * we find this case first.
165      */
166     if (cur == NULL)    
167       break;
168   }
169
170   return;
171 }
This page took 1.597135 seconds and 5 git commands to generate.