Mercurial > pidgin
comparison libfaim/aim_rxqueue.c @ 237:6ced2f1c8b24
[gaim-migrate @ 247]
How cool is this, libfaim is making a comeback. I completely redid everything,
as was necessary because of the updates to libfaim since gaim 0.9.7. You can
sign on and send/recv IMs, but there's a bad lag between display updates that
I haven't figured out how to fix yet.
committer: Tailor Script <tailor@pidgin.im>
author | Eric Warmenhoven <eric@warmenhoven.org> |
---|---|
date | Sat, 20 May 2000 00:30:53 +0000 |
parents | 68b230f8da5f |
children | 501e09c51cbc |
comparison
equal
deleted
inserted
replaced
236:62d470738cc7 | 237:6ced2f1c8b24 |
---|---|
1 /* | 1 /* |
2 aim_rxqueue.c | 2 * aim_rxqueue.c |
3 | 3 * |
4 This file contains the management routines for the receive | 4 * This file contains the management routines for the receive |
5 (incoming packet) queue. The actual packet handlers are in | 5 * (incoming packet) queue. The actual packet handlers are in |
6 aim_rxhandlers.c. | 6 * aim_rxhandlers.c. |
7 | |
8 */ | 7 */ |
9 | 8 |
10 #include "aim.h" | 9 #include <aim.h> |
11 | 10 |
12 /* | 11 /* |
13 This is a modified read() to make SURE we get the number | 12 * Grab a single command sequence off the socket, and enqueue |
14 of bytes we are told to, otherwise block. | 13 * it in the incoming event queue in a seperate struct. |
15 */ | 14 */ |
16 int Read(int fd, u_char *buf, int len) | 15 int aim_get_command(struct aim_session_t *sess, struct aim_conn_t *conn) |
17 { | 16 { |
18 int i = 0; | 17 u_char generic[6]; |
19 int j = 0; | 18 struct command_rx_struct *newrx = NULL; |
20 | 19 |
21 while ((i < len) && (!(i < 0))) | 20 if (!sess || !conn) |
22 { | 21 return 0; |
23 j = read(fd, &(buf[i]), len-i); | |
24 if ( (j < 0) && (errno != EAGAIN)) | |
25 return -errno; /* fail */ | |
26 else | |
27 i += j; /* success, continue */ | |
28 } | |
29 #if 0 | |
30 printf("\nRead Block: (%d/%04x)\n", len, len); | |
31 printf("\t"); | |
32 for (j = 0; j < len; j++) | |
33 { | |
34 if (j % 8 == 0) | |
35 printf("\n\t"); | |
36 if (buf[j] >= ' ' && buf[j] < 127) | |
37 printf("%c=%02x ",buf[j], buf[j]); | |
38 else | |
39 printf("0x%02x ", buf[j]); | |
40 } | |
41 printf("\n\n"); | |
42 #endif | |
43 return i; | |
44 } | |
45 | 22 |
46 /* | 23 if (conn->fd < 3) /* can happen when people abuse the interface */ |
47 struct command_struct * | 24 return 0; |
48 get_generic( | |
49 struct connection_info struct *, | |
50 struct command_struct * | |
51 ) | |
52 | |
53 Grab as many command sequences as we can off the socket, and enqueue | |
54 each command in the incoming event queue in a seperate struct. | |
55 | 25 |
56 */ | 26 /* |
57 int aim_get_command(void) | 27 * Read FLAP header. Six bytes: |
58 { | 28 * |
59 int i, readgood, j, isav, err; | 29 * 0 char -- Always 0x2a |
60 int s; | 30 * 1 char -- Channel ID. Usually 2 -- 1 and 4 are used during login. |
61 fd_set fds; | 31 * 2 short -- Sequence number |
62 struct timeval tv; | 32 * 4 short -- Number of data bytes that follow. |
63 char generic[6]; | 33 */ |
64 struct command_rx_struct *workingStruct = NULL; | 34 if (read(conn->fd, generic, 6) < 6){ |
65 struct command_rx_struct *workingPtr = NULL; | 35 aim_conn_close(conn); |
66 struct aim_conn_t *conn = NULL; | 36 return -1; |
67 #if debug > 0 | 37 } |
68 printf("Reading generic/unknown response..."); | |
69 #endif | |
70 | |
71 | |
72 /* dont wait at all (ie, never call this unless something is there) */ | |
73 tv.tv_sec = 0; | |
74 tv.tv_usec = 0; | |
75 conn = aim_select(&tv); | |
76 | 38 |
77 if (conn==NULL) | 39 /* |
78 return 0; /* nothing waiting */ | 40 * This shouldn't happen unless the socket breaks, the server breaks, |
79 | 41 * or we break. We must handle it just in case. |
80 s = conn->fd; | 42 */ |
81 | 43 if (generic[0] != 0x2a) { |
82 FD_ZERO(&fds); | 44 faimdprintf(1, "Bad incoming data!"); |
83 FD_SET(s, &fds); | 45 return -1; |
84 tv.tv_sec = 0; /* wait, but only for 10us */ | 46 } |
85 tv.tv_usec = 10; | |
86 | |
87 generic[0] = 0x00; | |
88 | |
89 readgood = 0; | |
90 i = 0; | |
91 j = 0; | |
92 /* read first 6 bytes (the FLAP header only) off the socket */ | |
93 while ( (select(s+1, &fds, NULL, NULL, &tv) == 1) && (i < 6)) | |
94 { | |
95 if ((err = Read(s, &(generic[i]), 1)) < 0) | |
96 { | |
97 /* error is probably not recoverable...(must be a pessimistic day) */ | |
98 aim_conn_close(conn); | |
99 return err; | |
100 } | |
101 | |
102 if (readgood == 0) | |
103 { | |
104 if (generic[i] == 0x2a) | |
105 { | |
106 readgood = 1; | |
107 #if debug > 1 | |
108 printf("%x ", generic[i]); | |
109 fflush(stdout); | |
110 #endif | |
111 i++; | |
112 } | |
113 else | |
114 { | |
115 #if debug > 1 | |
116 printf("skipping 0x%d ", generic[i]); | |
117 fflush(stdout); | |
118 #endif | |
119 j++; | |
120 } | |
121 } | |
122 else | |
123 { | |
124 #if debug > 1 | |
125 printf("%x ", generic[i]); | |
126 #endif | |
127 i++; | |
128 } | |
129 FD_ZERO(&fds); | |
130 FD_SET(s, &fds); | |
131 tv.tv_sec= 2; | |
132 tv.tv_usec= 2; | |
133 } | |
134 | |
135 if (generic[0] != 0x2a) | |
136 { | |
137 /* this really shouldn't happen, since the main loop | |
138 select() should protect us from entering this function | |
139 without data waiting */ | |
140 printf("Bad incoming data!"); | |
141 return -1; | |
142 } | |
143 | |
144 isav = i; | |
145 | 47 |
146 /* allocate a new struct */ | 48 /* allocate a new struct */ |
147 workingStruct = (struct command_rx_struct *) malloc(sizeof(struct command_rx_struct)); | 49 newrx = (struct command_rx_struct *)malloc(sizeof(struct command_rx_struct)); |
148 workingStruct->lock = 1; /* lock the struct */ | 50 if (!newrx) |
51 return -1; | |
52 memset(newrx, 0x00, sizeof(struct command_rx_struct)); | |
149 | 53 |
150 /* store type -- byte 2 */ | 54 newrx->lock = 1; /* lock the struct */ |
151 workingStruct->type = (char) generic[1]; | 55 |
56 /* store channel -- byte 2 */ | |
57 newrx->type = (char) generic[1]; | |
152 | 58 |
153 /* store seqnum -- bytes 3 and 4 */ | 59 /* store seqnum -- bytes 3 and 4 */ |
154 workingStruct->seqnum = ( (( (unsigned int) generic[2]) & 0xFF) << 8); | 60 newrx->seqnum = aimutil_get16(generic+2); |
155 workingStruct->seqnum += ( (unsigned int) generic[3]) & 0xFF; | |
156 | 61 |
157 /* store commandlen -- bytes 5 and 6 */ | 62 /* store commandlen -- bytes 5 and 6 */ |
158 workingStruct->commandlen = ( (( (unsigned int) generic[4]) & 0xFF ) << 8); | 63 newrx->commandlen = aimutil_get16(generic+4); |
159 workingStruct->commandlen += ( (unsigned int) generic[5]) & 0xFF; | 64 |
160 | 65 newrx->nofree = 0; /* free by default */ |
161 printf("%d\n", workingStruct->commandlen); | |
162 | 66 |
163 /* malloc for data portion */ | 67 /* malloc for data portion */ |
164 workingStruct->data = (char *) malloc(workingStruct->commandlen); | 68 newrx->data = (u_char *) malloc(newrx->commandlen); |
69 if (!newrx->data) { | |
70 free(newrx); | |
71 return -1; | |
72 } | |
165 | 73 |
166 /* read the data portion of the packet */ | 74 /* read the data portion of the packet */ |
167 i = Read(s, workingStruct->data, workingStruct->commandlen); | 75 if (read(conn->fd, newrx->data, newrx->commandlen) < newrx->commandlen){ |
168 if (i < 0) | 76 free(newrx->data); |
169 { | 77 free(newrx); |
170 aim_conn_close(conn); | 78 aim_conn_close(conn); |
171 return i; | 79 return -1; |
172 } | 80 } |
173 | 81 |
174 #if debug > 0 | 82 newrx->conn = conn; |
175 printf(" done. (%db+%db read, %db skipped)\n", isav, i, j); | |
176 #endif | |
177 | 83 |
178 workingStruct->conn = conn; | 84 newrx->next = NULL; /* this will always be at the bottom */ |
179 | 85 newrx->lock = 0; /* unlock */ |
180 workingStruct->next = NULL; /* this will always be at the bottom */ | |
181 workingStruct->lock = 0; /* unlock */ | |
182 | 86 |
183 /* enqueue this packet */ | 87 /* enqueue this packet */ |
184 if (aim_queue_incoming == NULL) | 88 if (sess->queue_incoming == NULL) { |
185 aim_queue_incoming = workingStruct; | 89 sess->queue_incoming = newrx; |
186 else | 90 } else { |
187 { | 91 struct command_rx_struct *cur; |
188 workingPtr = aim_queue_incoming; | 92 |
189 while (workingPtr->next != NULL) | 93 /* |
190 workingPtr = workingPtr->next; | 94 * This append operation takes a while. It might be faster |
191 workingPtr->next = workingStruct; | 95 * if we maintain a pointer to the last entry in the queue |
192 } | 96 * and just update that. Need to determine if the overhead |
97 * to maintain that is lower than the overhead for this loop. | |
98 */ | |
99 for (cur = sess->queue_incoming; cur->next; cur = cur->next) | |
100 ; | |
101 cur->next = newrx; | |
102 } | |
103 | |
104 newrx->conn->lastactivity = time(NULL); | |
193 | 105 |
194 return 0; | 106 return 0; |
195 } | 107 } |
196 | 108 |
197 /* | 109 /* |
198 purge_rxqueue() | 110 * Purge recieve queue of all handled commands (->handled==1). Also |
111 * allows for selective freeing using ->nofree so that the client can | |
112 * keep the data for various purposes. | |
113 * | |
114 * If ->nofree is nonzero, the frame will be delinked from the global list, | |
115 * but will not be free'ed. The client _must_ keep a pointer to the | |
116 * data -- libfaim will not! If the client marks ->nofree but | |
117 * does not keep a pointer, it's lost forever. | |
118 * | |
119 */ | |
120 void aim_purge_rxqueue(struct aim_session_t *sess) | |
121 { | |
122 struct command_rx_struct *cur = NULL; | |
123 struct command_rx_struct *tmp; | |
199 | 124 |
200 This is just what it sounds. It purges the receive (rx) queue of | 125 if (sess->queue_incoming == NULL) |
201 all handled commands. This is normally called from inside | 126 return; |
202 aim_rxdispatch() after it's processed all the commands in the queue. | |
203 | 127 |
204 */ | 128 if (sess->queue_incoming->next == NULL) { |
205 struct command_rx_struct *aim_purge_rxqueue(struct command_rx_struct *queue) | 129 if (sess->queue_incoming->handled) { |
206 { | 130 tmp = sess->queue_incoming; |
207 int i = 0; | 131 sess->queue_incoming = NULL; |
208 struct command_rx_struct *workingPtr = NULL; | |
209 struct command_rx_struct *workingPtr2 = NULL; | |
210 | 132 |
211 workingPtr = queue; | 133 if (!tmp->nofree) { |
212 if (queue == NULL) | 134 free(tmp->data); |
213 { | 135 free(tmp); |
214 return queue; | 136 } else |
137 tmp->next = NULL; | |
215 } | 138 } |
216 else if (queue->next == NULL) | 139 return; |
217 { | 140 } |
218 if (queue->handled == 1) | |
219 { | |
220 workingPtr2 = queue; | |
221 queue = NULL; | |
222 free(workingPtr2->data); | |
223 free(workingPtr2); | |
224 } | |
225 return queue; | |
226 } | |
227 else | |
228 { | |
229 for (i = 0; workingPtr != NULL; i++) | |
230 { | |
231 if (workingPtr->next->handled == 1) | |
232 { | |
233 /* save struct */ | |
234 workingPtr2 = workingPtr->next; | |
235 /* dequeue */ | |
236 workingPtr->next = workingPtr2->next; | |
237 /* free */ | |
238 free(workingPtr2->data); | |
239 free(workingPtr2); | |
240 } | |
241 | 141 |
242 workingPtr = workingPtr->next; | 142 for(cur = sess->queue_incoming; cur->next != NULL; ) { |
243 } | 143 if (cur->next->handled) { |
244 } | 144 tmp = cur->next; |
145 cur->next = tmp->next; | |
146 if (!tmp->nofree) { | |
147 free(tmp->data); | |
148 free(tmp); | |
149 } else | |
150 tmp->next = NULL; | |
151 } | |
152 cur = cur->next; | |
245 | 153 |
246 return queue; | 154 /* |
155 * Be careful here. Because of the way we just | |
156 * manipulated the pointer, cur may be NULL and | |
157 * the for() will segfault doing the check unless | |
158 * we find this case first. | |
159 */ | |
160 if (cur == NULL) | |
161 break; | |
162 } | |
163 | |
164 return; | |
247 } | 165 } |