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