Mercurial > pidgin
annotate libfaim/aim_txqueue.c @ 271:f7706908f8ae
[gaim-migrate @ 281]
There aren't panel support problems any more because the 100% bug got fixed.
committer: Tailor Script <tailor@pidgin.im>
author | Eric Warmenhoven <eric@warmenhoven.org> |
---|---|
date | Fri, 26 May 2000 23:17:19 +0000 |
parents | cfa39d39dec6 |
children | 501e09c51cbc |
rev | line source |
---|---|
2 | 1 /* |
237 | 2 * aim_txqueue.c |
3 * | |
4 * Herein lies all the mangement routines for the transmit (Tx) queue. | |
5 * | |
270
cfa39d39dec6
[gaim-migrate @ 280]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
237
diff
changeset
|
6 * Changes by EWarmenhoven Fri May 26 22:52:46 UTC 2000: |
cfa39d39dec6
[gaim-migrate @ 280]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
237
diff
changeset
|
7 * - added aim_tx_flushqueue() to the end of aim_tx_enqueue() so that I don't |
cfa39d39dec6
[gaim-migrate @ 280]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
237
diff
changeset
|
8 * have to worry about it any more. mid tells me that doing so will solve the |
cfa39d39dec6
[gaim-migrate @ 280]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
237
diff
changeset
|
9 * 100% bug. Thanks mid! |
cfa39d39dec6
[gaim-migrate @ 280]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
237
diff
changeset
|
10 * |
2 | 11 */ |
12 | |
237 | 13 #include <aim.h> |
14 | |
15 /* | |
16 * Allocate a new tx frame. | |
17 * | |
18 * This is more for looks than anything else. | |
19 * | |
20 * Right now, that is. If/when we implement a pool of transmit | |
21 * frames, this will become the request-an-unused-frame part. | |
22 */ | |
23 struct command_tx_struct *aim_tx_new(int chan, struct aim_conn_t *conn, int datalen) | |
2 | 24 { |
237 | 25 struct command_tx_struct *new; |
2 | 26 |
237 | 27 if (!conn) |
28 return NULL; | |
29 | |
30 new = (struct command_tx_struct *)malloc(sizeof(struct command_tx_struct)); | |
31 if (!new) | |
32 return NULL; | |
33 memset(new, 0, sizeof(struct command_tx_struct)); | |
2 | 34 |
237 | 35 new->conn = conn; |
36 new->type = chan; | |
37 | |
38 if(datalen) { | |
39 new->data = (u_char *)malloc(datalen); | |
40 new->commandlen = datalen; | |
41 } | |
42 | |
43 return new; | |
44 } | |
2 | 45 |
237 | 46 /* |
47 * aim_tx_enqeue() | |
48 * | |
49 * The overall purpose here is to enqueue the passed in command struct | |
50 * into the outgoing (tx) queue. Basically... | |
51 * 1) Make a scope-irrelevent copy of the struct | |
52 * 2) Lock the struct | |
53 * 3) Mark as not-sent-yet | |
54 * 4) Enqueue the struct into the list | |
55 * 5) Unlock the struct once it's linked in | |
56 * 6) Return | |
57 * | |
58 */ | |
59 int aim_tx_enqueue(struct aim_session_t *sess, | |
60 struct command_tx_struct *newpacket) | |
61 { | |
62 struct command_tx_struct *cur; | |
2 | 63 |
237 | 64 if (newpacket->conn == NULL) { |
65 faimdprintf(1, "aim_tx_enqueue: WARNING: enqueueing packet with no connecetion\n"); | |
66 newpacket->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS); | |
67 } | |
68 | |
69 /* assign seqnum */ | |
70 newpacket->seqnum = aim_get_next_txseqnum(newpacket->conn); | |
71 /* set some more fields */ | |
72 newpacket->lock = 1; /* lock */ | |
73 newpacket->sent = 0; /* not sent yet */ | |
74 newpacket->next = NULL; /* always last */ | |
2 | 75 |
237 | 76 /* see overhead note in aim_rxqueue counterpart */ |
77 if (sess->queue_outgoing == NULL) { | |
78 sess->queue_outgoing = newpacket; | |
79 } else { | |
80 for (cur = sess->queue_outgoing; | |
81 cur->next; | |
82 cur = cur->next) | |
83 ; | |
84 cur->next = newpacket; | |
85 } | |
86 | |
87 newpacket->lock = 0; /* unlock so it can be sent */ | |
88 | |
89 #if debug == 2 | |
90 faimdprintf(2, "calling aim_tx_printqueue()\n"); | |
91 aim_tx_printqueue(sess); | |
92 faimdprintf(2, "back from aim_tx_printqueue()\n"); | |
2 | 93 #endif |
94 | |
270
cfa39d39dec6
[gaim-migrate @ 280]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
237
diff
changeset
|
95 /* mid tells me this should solve a lot of my problems */ |
cfa39d39dec6
[gaim-migrate @ 280]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
237
diff
changeset
|
96 aim_tx_flushqueue(sess); |
cfa39d39dec6
[gaim-migrate @ 280]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
237
diff
changeset
|
97 |
2 | 98 return 0; |
99 } | |
100 | |
101 /* | |
237 | 102 * aim_get_next_txseqnum() |
103 * | |
104 * This increments the tx command count, and returns the seqnum | |
105 * that should be stamped on the next FLAP packet sent. This is | |
106 * normally called during the final step of packet preparation | |
107 * before enqueuement (in aim_tx_enqueue()). | |
108 * | |
2 | 109 */ |
237 | 110 u_int aim_get_next_txseqnum(struct aim_conn_t *conn) |
2 | 111 { |
112 return ( ++conn->seqnum ); | |
113 } | |
114 | |
115 /* | |
237 | 116 * aim_tx_printqueue() |
117 * | |
118 * This is basically for debuging purposes only. It dumps all the | |
119 * records in the tx queue and their current status. Very helpful | |
120 * if the queue isn't working quite right. | |
121 * | |
2 | 122 */ |
237 | 123 #if debug == 2 |
124 int aim_tx_printqueue(struct aim_session_t *sess) | |
2 | 125 { |
237 | 126 struct command_tx_struct *cur; |
2 | 127 |
237 | 128 faimdprintf(2, "\ncurrent aim_queue_outgoing...\n"); |
129 faimdprintf(2, "\ttype seqnum len lock sent\n"); | |
2 | 130 |
237 | 131 if (sess->queue_outgoing == NULL) |
132 faimdprintf(2, "aim_tx_flushqueue(): queue empty"); | |
133 else { | |
134 for (cur = sess->queue_outgoing; cur; cur = cur->next) { | |
135 faimdprintf(2, "\t %2x %4x %4x %1d %1d\n", | |
136 cur->type, cur->seqnum, | |
137 cur->commandlen, cur->lock, | |
138 cur->sent); | |
139 } | |
140 } | |
141 | |
142 faimdprintf(2, "\n(done printing queue)\n"); | |
2 | 143 |
144 return 0; | |
145 } | |
146 #endif | |
147 | |
148 /* | |
237 | 149 * aim_tx_flushqueue() |
150 * | |
151 * This the function is responsable for putting the queued commands | |
152 * onto the wire. This function is critical to the operation of | |
153 * the queue and therefore is the most prone to brokenness. It | |
154 * seems to be working quite well at this point. | |
155 * | |
156 * Procedure: | |
157 * 1) Traverse the list, only operate on commands that are unlocked | |
158 * and haven't been sent yet. | |
159 * 2) Lock the struct | |
160 * 3) Allocate a temporary buffer to store the finished, fully | |
161 * processed packet in. | |
162 * 4) Build the packet from the command_tx_struct data. | |
163 * 5) Write the packet to the socket. | |
164 * 6) If success, mark the packet sent, if fail report failure, do NOT | |
165 * mark the packet sent (so it will not get purged and therefore | |
166 * be attempted again on next call). | |
167 * 7) Unlock the struct. | |
168 * 8) Free the temp buffer | |
169 * 9) Step to next struct in list and go back to 1. | |
170 * | |
2 | 171 */ |
237 | 172 int aim_tx_flushqueue(struct aim_session_t *sess) |
2 | 173 { |
237 | 174 struct command_tx_struct *cur; |
175 u_char *curPacket = NULL; | |
2 | 176 #if debug > 1 |
177 int i = 0; | |
178 #endif | |
179 | |
237 | 180 if (sess->queue_outgoing == NULL) |
181 return 0; | |
182 | |
183 faimdprintf(2, "beginning txflush...\n"); | |
184 for (cur = sess->queue_outgoing; cur; cur = cur->next) { | |
185 /* only process if its unlocked and unsent */ | |
186 if (!cur->lock && !cur->sent) { | |
187 | |
188 /* | |
189 * And now for the meager attempt to force transmit | |
190 * latency and avoid missed messages. | |
191 */ | |
192 if ((cur->conn->lastactivity + cur->conn->forcedlatency) >= time(NULL)) { | |
193 /* FIXME FIXME -- should be a break! we dont want to block the upper layers */ | |
194 sleep((cur->conn->lastactivity + cur->conn->forcedlatency) - time(NULL)); | |
195 } | |
196 | |
197 cur->lock = 1; /* lock the struct */ | |
198 | |
199 /* allocate full-packet buffer */ | |
200 curPacket = (char *) malloc(cur->commandlen + 6); | |
201 | |
202 /* command byte */ | |
203 curPacket[0] = 0x2a; | |
204 | |
205 /* type/family byte */ | |
206 curPacket[1] = cur->type; | |
207 | |
208 /* bytes 3+4: word: FLAP sequence number */ | |
209 aimutil_put16(curPacket+2, cur->seqnum); | |
2 | 210 |
237 | 211 /* bytes 5+6: word: SNAC len */ |
212 aimutil_put16(curPacket+4, cur->commandlen); | |
213 | |
214 /* bytes 7 and on: raw: SNAC data */ | |
215 memcpy(&(curPacket[6]), cur->data, cur->commandlen); | |
216 | |
217 /* full image of raw packet data now in curPacket */ | |
218 if ( (u_int)write(cur->conn->fd, curPacket, (cur->commandlen + 6)) != (cur->commandlen + 6)) { | |
219 printf("\nWARNING: Error in sending packet 0x%4x -- will try again next time\n\n", cur->seqnum); | |
220 cur->sent = 0; /* mark it unsent */ | |
221 continue; /* bail out */ | |
222 } else { | |
223 faimdprintf(2, "\nSENT 0x%4x\n\n", cur->seqnum); | |
224 | |
225 cur->sent = 1; /* mark the struct as sent */ | |
226 cur->conn->lastactivity = time(NULL); | |
227 } | |
2 | 228 #if debug > 2 |
237 | 229 faimdprintf(2, "\nPacket:"); |
230 for (i = 0; i < (cur->commandlen + 6); i++) { | |
231 if ((i % 8) == 0) { | |
232 faimdprintf(2, "\n\t"); | |
233 } | |
234 if (curPacket[i] >= ' ' && curPacket[i]<127) { | |
235 faimdprintf(2, "%c=%02x ", curPacket[i], curPacket[i]); | |
236 } else { | |
237 faimdprintf(2, "0x%2x ", curPacket[i]); | |
238 } | |
239 } | |
240 faimdprintf(2, "\n"); | |
2 | 241 #endif |
237 | 242 cur->lock = 0; /* unlock the struct */ |
243 free(curPacket); /* free up full-packet buffer */ | |
2 | 244 } |
237 | 245 } |
2 | 246 |
247 /* purge sent commands from queue */ | |
237 | 248 aim_tx_purgequeue(sess); |
2 | 249 |
250 return 0; | |
251 } | |
252 | |
253 /* | |
237 | 254 * aim_tx_purgequeue() |
255 * | |
256 * This is responsable for removing sent commands from the transmit | |
257 * queue. This is not a required operation, but it of course helps | |
258 * reduce memory footprint at run time! | |
259 * | |
2 | 260 */ |
237 | 261 void aim_tx_purgequeue(struct aim_session_t *sess) |
2 | 262 { |
237 | 263 struct command_tx_struct *cur = NULL; |
264 struct command_tx_struct *tmp; | |
265 | |
266 if (sess->queue_outgoing == NULL) | |
267 return; | |
268 | |
269 if (sess->queue_outgoing->next == NULL) { | |
270 if (!sess->queue_outgoing->lock && sess->queue_outgoing->sent) { | |
271 tmp = sess->queue_outgoing; | |
272 sess->queue_outgoing = NULL; | |
273 free(tmp->data); | |
274 free(tmp); | |
2 | 275 } |
237 | 276 return; |
277 } | |
278 | |
279 for(cur = sess->queue_outgoing; cur->next != NULL; ) { | |
280 if (!cur->next->lock && cur->next->sent) { | |
281 tmp = cur->next; | |
282 cur->next = tmp->next; | |
283 free(tmp->data); | |
284 free(tmp); | |
285 } | |
286 cur = cur->next; | |
2 | 287 |
237 | 288 /* |
289 * Be careful here. Because of the way we just | |
290 * manipulated the pointer, cur may be NULL and | |
291 * the for() will segfault doing the check unless | |
292 * we find this case first. | |
293 */ | |
294 if (cur == NULL) | |
295 break; | |
296 } | |
297 return; | |
2 | 298 } |