]> andersk Git - libfaim.git/blob - aim_rxqueue.c
- Sun Mar 19 06:07:52 UTC 2000
[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
10 #include <faim/aim.h> 
11
12
13 /*
14  * This is a modified read() to make SURE we get the number
15  * of bytes we are told to, otherwise block.
16  *
17  * Modified to count errno (Sébastien Carpe <scarpe@atos-group.com>)
18  * 
19 */
20 int aim_failsaferead(int fd, u_char *buf, int len)
21 {
22   int i = 0;
23   int j = 0;
24   int err_count=0;
25   
26   while ((i < len) && (!(i < 0)))
27     {
28       j = read(fd, &(buf[i]), len-i);
29       if ( (j < 0) && (errno != EAGAIN))
30         return -errno; /* fail */
31       else if (j==0) 
32         {
33           err_count++;
34           if (err_count> MAX_READ_ERROR)  {
35             /*
36              * Reached maximum number of allowed read errors.
37              *
38              * Lets suppose the connection is lost and errno didn't
39              * know it.
40              *
41              */
42           return (-1); 
43         }
44       } 
45       else
46         i += j; /* success, continue */
47     }
48   return i;
49 }
50
51 /*  
52  * Grab as many command sequences as we can off the socket, and enqueue
53  * each command in the incoming event queue in a seperate struct.
54  */
55 int aim_get_command(struct aim_session_t *sess)
56 {
57   int i, readgood, j, isav, err;
58   int s;
59   fd_set fds;
60   struct timeval tv;
61   char generic[6]; 
62   struct command_rx_struct *workingStruct = NULL;
63   struct aim_conn_t *conn = NULL;
64   int selstat = 0;
65
66   faimdprintf(1, "Reading generic/unknown response...");
67
68   /* dont wait at all (ie, never call this unless something is there) */
69   tv.tv_sec = 0; 
70   tv.tv_usec = 0;
71   conn = aim_select(sess, &tv, &selstat);
72
73   if (conn==NULL) 
74     return 0;  /* nothing waiting */
75
76   s = conn->fd;
77
78   if (s < 3) 
79     return 0;
80
81   FD_ZERO(&fds);
82   FD_SET(s, &fds);
83   tv.tv_sec = 0;  /* wait, but only for 10us */
84   tv.tv_usec = 10;
85   
86   generic[0] = 0x00;  
87
88   readgood = 0;
89   i = 0;
90   j = 0;
91   /* read first 6 bytes (the FLAP header only) off the socket */
92   while ( (select(s+1, &fds, NULL, NULL, &tv) == 1) && (i < 6))
93     {
94       if ((err = aim_failsaferead(s, &(generic[i]), 1)) < 0)
95         {
96           /* error is probably not recoverable...(must be a pessimistic day) */
97           aim_conn_close(conn);
98           return err;
99         }
100
101       if (readgood == 0)
102         {
103           if (generic[i] == 0x2a)
104           {
105             readgood = 1;
106             faimdprintf(1, "%x ", generic[i]);
107             i++;
108           }
109           else
110             {
111               faimdprintf(1, "skipping 0x%d ", generic[i]);
112               j++;
113             }
114         }
115       else
116         {
117           faimdprintf(1, "%x ", generic[i]);
118           i++;
119         }
120       FD_ZERO(&fds);
121       FD_SET(s, &fds);
122       tv.tv_sec= 2;
123       tv.tv_usec= 2;
124     }
125
126   /*
127    * This shouldn't happen unless the socket breaks, the server breaks,
128    * or we break.  We must handle it just in case.
129    */
130   if (generic[0] != 0x2a) {
131     printf("Bad incoming data!");
132     return -1;
133   }     
134
135   isav = i;
136
137   /* allocate a new struct */
138   workingStruct = (struct command_rx_struct *) malloc(sizeof(struct command_rx_struct));
139   memset(workingStruct, 0x00, sizeof(struct command_rx_struct));
140
141   workingStruct->lock = 1;  /* lock the struct */
142
143   /* store channel -- byte 2 */
144   workingStruct->type = (char) generic[1];
145
146   /* store seqnum -- bytes 3 and 4 */
147   workingStruct->seqnum = aimutil_get16(generic+2);
148
149   /* store commandlen -- bytes 5 and 6 */
150   workingStruct->commandlen = aimutil_get16(generic+4);
151
152   workingStruct->nofree = 0; /* free by default */
153
154   /* malloc for data portion */
155   workingStruct->data = (u_char *) malloc(workingStruct->commandlen);
156
157   /* read the data portion of the packet */
158   if (aim_failsaferead(s, workingStruct->data, workingStruct->commandlen) < 0){
159     aim_conn_close(conn);
160     return -1;
161   }
162
163   faimdprintf(1, " done. (%db+%db read, %db skipped)\n", isav, i, j);
164
165   workingStruct->conn = conn;
166
167   workingStruct->next = NULL;  /* this will always be at the bottom */
168   workingStruct->lock = 0; /* unlock */
169
170   /* enqueue this packet */
171   if (sess->queue_incoming == NULL) {
172     sess->queue_incoming = workingStruct;
173   } else {
174     struct command_rx_struct *cur;
175
176     /*
177      * This append operation takes a while.  It might be faster
178      * if we maintain a pointer to the last entry in the queue
179      * and just update that.  Need to determine if the overhead
180      * to maintain that is lower than the overhead for this loop.
181      */
182     for (cur = sess->queue_incoming; cur->next; cur = cur->next)
183       ;
184     cur->next = workingStruct;
185   }
186   
187   workingStruct->conn->lastactivity = time(NULL);
188
189   return 0;  
190 }
191
192 /*
193  * Purge recieve queue of all handled commands (->handled==1).  Also
194  * allows for selective freeing using ->nofree so that the client can
195  * keep the data for various purposes.  
196  *
197  * If ->nofree is nonzero, the frame will be delinked from the global list, 
198  * but will not be free'ed.  The client _must_ keep a pointer to the
199  * data -- libfaim will not!  If the client marks ->nofree but
200  * does not keep a pointer, it's lost forever.
201  *
202  */
203 void aim_purge_rxqueue(struct aim_session_t *sess)
204 {
205   struct command_rx_struct *cur = NULL;
206   struct command_rx_struct *tmp;
207
208   if (sess->queue_incoming == NULL)
209     return;
210   
211   if (sess->queue_incoming->next == NULL) {
212     if (sess->queue_incoming->handled) {
213       tmp = sess->queue_incoming;
214       sess->queue_incoming = NULL;
215
216       if (!tmp->nofree) {
217         free(tmp->data);
218         free(tmp);
219       } else
220         tmp->next = NULL;
221     }
222     return;
223   }
224
225   for(cur = sess->queue_incoming; cur->next != NULL; ) {
226     if (cur->next->handled) {
227       tmp = cur->next;
228       cur->next = tmp->next;
229       if (!tmp->nofree) {
230         free(tmp->data);
231         free(tmp);
232       } else
233         tmp->next = NULL;
234     }   
235     cur = cur->next;
236
237     /* 
238      * Be careful here.  Because of the way we just
239      * manipulated the pointer, cur may be NULL and 
240      * the for() will segfault doing the check unless
241      * we find this case first.
242      */
243     if (cur == NULL)    
244       break;
245   }
246
247   return;
248 }
This page took 0.585616 seconds and 5 git commands to generate.