Mercurial > pidgin
annotate libfaim/aim_txqueue.c @ 270:cfa39d39dec6
[gaim-migrate @ 280]
Fixed the 100% bug, but in doing so, broke permit/deny lists, so that got
commented out (yet again). Gaim/Faim is now usable.
committer: Tailor Script <tailor@pidgin.im>
| author | Eric Warmenhoven <eric@warmenhoven.org> |
|---|---|
| date | Fri, 26 May 2000 23:10:21 +0000 |
| parents | 6ced2f1c8b24 |
| 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 } |
