]> andersk Git - libfaim.git/blame - aim_txqueue.c
Hopefully fix msgbot's issue.
[libfaim.git] / aim_txqueue.c
CommitLineData
9de3ca7e 1/*
24286d93 2 * aim_txqueue.c
3 *
4 * Herein lies all the mangement routines for the transmit (Tx) queue.
5 *
9de3ca7e 6 */
7
a25832e6 8#include <faim/aim.h>
9de3ca7e 9
f1a5efe0 10/*
11 * Allocate a new tx frame.
12 *
13 * This is more for looks than anything else.
5b79dc93 14 *
15 * Right now, that is. If/when we implement a pool of transmit
16 * frames, this will become the request-an-unused-frame part.
f1a5efe0 17 */
5b79dc93 18struct command_tx_struct *aim_tx_new(int chan, struct aim_conn_t *conn, int datalen)
f1a5efe0 19{
20 struct command_tx_struct *new;
21
e88ba395 22 if (!conn) {
23 printf("aim_tx_new: ERROR: no connection specified\n");
5b79dc93 24 return NULL;
e88ba395 25 }
5b79dc93 26
f1a5efe0 27 new = (struct command_tx_struct *)malloc(sizeof(struct command_tx_struct));
28 if (!new)
29 return NULL;
30 memset(new, 0, sizeof(struct command_tx_struct));
31
5b79dc93 32 new->conn = conn;
33 new->type = chan;
34
35 if(datalen) {
36 new->data = (u_char *)malloc(datalen);
37 new->commandlen = datalen;
38 }
39
f1a5efe0 40 return new;
41}
42
9de3ca7e 43/*
e88ba395 44 * aim_tx_enqeue__queuebased()
24286d93 45 *
46 * The overall purpose here is to enqueue the passed in command struct
47 * into the outgoing (tx) queue. Basically...
48 * 1) Make a scope-irrelevent copy of the struct
49 * 2) Lock the struct
50 * 3) Mark as not-sent-yet
51 * 4) Enqueue the struct into the list
52 * 5) Unlock the struct once it's linked in
53 * 6) Return
54 *
e88ba395 55 * Note that this is only used when doing queue-based transmitting;
56 * that is, when sess->tx_enqueue is set to &aim_tx_enqueue__queuebased.
57 *
9de3ca7e 58 */
e88ba395 59int aim_tx_enqueue__queuebased(struct aim_session_t *sess,
60 struct command_tx_struct *newpacket)
9de3ca7e 61{
b8d0da45 62 struct command_tx_struct *cur;
9de3ca7e 63
b8d0da45 64 if (newpacket->conn == NULL) {
5b79dc93 65 faimdprintf(1, "aim_tx_enqueue: WARNING: enqueueing packet with no connecetion\n");
a25832e6 66 newpacket->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS);
b8d0da45 67 }
9de3ca7e 68
9de3ca7e 69 /* assign seqnum */
5b79dc93 70 newpacket->seqnum = aim_get_next_txseqnum(newpacket->conn);
9de3ca7e 71 /* set some more fields */
5b79dc93 72 newpacket->lock = 1; /* lock */
73 newpacket->sent = 0; /* not sent yet */
74 newpacket->next = NULL; /* always last */
9de3ca7e 75
b8d0da45 76 /* see overhead note in aim_rxqueue counterpart */
77 if (sess->queue_outgoing == NULL) {
5b79dc93 78 sess->queue_outgoing = newpacket;
b8d0da45 79 } else {
80 for (cur = sess->queue_outgoing;
81 cur->next;
82 cur = cur->next)
83 ;
5b79dc93 84 cur->next = newpacket;
b8d0da45 85 }
9de3ca7e 86
5b79dc93 87 newpacket->lock = 0; /* unlock so it can be sent */
9de3ca7e 88
b8d0da45 89#if debug == 2
90 faimdprintf(2, "calling aim_tx_printqueue()\n");
0c20631f 91 aim_tx_printqueue(sess);
b8d0da45 92 faimdprintf(2, "back from aim_tx_printqueue()\n");
9de3ca7e 93#endif
94
95 return 0;
96}
97
e88ba395 98/*
99 * aim_tx_enqueue__immediate()
100 *
101 * Parallel to aim_tx_enqueue__queuebased, however, this bypasses
102 * the whole queue mess when you want immediate writes to happen.
103 *
104 * Basically the same as its __queuebased couterpart, however
105 * instead of doing a list append, it just calls aim_tx_sendframe()
106 * right here.
107 *
108 */
109int aim_tx_enqueue__immediate(struct aim_session_t *sess, struct command_tx_struct *newpacket)
110{
111 if (newpacket->conn == NULL) {
112 faimdprintf(1, "aim_tx_enqueue: ERROR: packet has no connection\n");
113 if (newpacket->data)
114 free(newpacket->data);
115 free(newpacket);
116 return -1;
117 }
118
119 newpacket->seqnum = aim_get_next_txseqnum(newpacket->conn);
120
121 newpacket->lock = 1; /* lock */
122 newpacket->sent = 0; /* not sent yet */
123
124 aim_tx_sendframe(newpacket);
125
126 if (newpacket->data)
127 free(newpacket->data);
128 free(newpacket);
129
130 return 0;
131}
132
9de3ca7e 133/*
a25832e6 134 * aim_get_next_txseqnum()
135 *
136 * This increments the tx command count, and returns the seqnum
137 * that should be stamped on the next FLAP packet sent. This is
138 * normally called during the final step of packet preparation
139 * before enqueuement (in aim_tx_enqueue()).
140 *
9de3ca7e 141 */
142u_int aim_get_next_txseqnum(struct aim_conn_t *conn)
143{
df5a99fb 144 u_int ret;
145
146 faim_mutex_lock(&conn->seqnum_lock);
147 ret = ++conn->seqnum;
148 faim_mutex_unlock(&conn->seqnum_lock);
149 return ret;
9de3ca7e 150}
151
152/*
a25832e6 153 * aim_tx_printqueue()
154 *
155 * This is basically for debuging purposes only. It dumps all the
156 * records in the tx queue and their current status. Very helpful
157 * if the queue isn't working quite right.
158 *
9de3ca7e 159 */
b8d0da45 160#if debug == 2
0c20631f 161int aim_tx_printqueue(struct aim_session_t *sess)
9de3ca7e 162{
b8d0da45 163 struct command_tx_struct *cur;
9de3ca7e 164
b8d0da45 165 faimdprintf(2, "\ncurrent aim_queue_outgoing...\n");
166 faimdprintf(2, "\ttype seqnum len lock sent\n");
167
168 if (sess->queue_outgoing == NULL)
169 faimdprintf(2, "aim_tx_flushqueue(): queue empty");
170 else {
171 for (cur = sess->queue_outgoing; cur; cur = cur->next) {
172 faimdprintf(2, "\t %2x %4x %4x %1d %1d\n",
173 cur->type, cur->seqnum,
174 cur->commandlen, cur->lock,
175 cur->sent);
176 }
177 }
9de3ca7e 178
b8d0da45 179 faimdprintf(2, "\n(done printing queue)\n");
9de3ca7e 180
181 return 0;
182}
183#endif
184
185/*
a25832e6 186 * aim_tx_flushqueue()
187 *
188 * This the function is responsable for putting the queued commands
189 * onto the wire. This function is critical to the operation of
190 * the queue and therefore is the most prone to brokenness. It
191 * seems to be working quite well at this point.
192 *
193 * Procedure:
194 * 1) Traverse the list, only operate on commands that are unlocked
195 * and haven't been sent yet.
196 * 2) Lock the struct
197 * 3) Allocate a temporary buffer to store the finished, fully
198 * processed packet in.
199 * 4) Build the packet from the command_tx_struct data.
200 * 5) Write the packet to the socket.
201 * 6) If success, mark the packet sent, if fail report failure, do NOT
202 * mark the packet sent (so it will not get purged and therefore
203 * be attempted again on next call).
204 * 7) Unlock the struct.
205 * 8) Free the temp buffer
206 * 9) Step to next struct in list and go back to 1.
207 *
9de3ca7e 208 */
e88ba395 209int aim_tx_sendframe(struct command_tx_struct *cur)
210{
211 u_char *curPacket;
212
213 if (!cur)
214 return -1; /* fatal */
215
216 cur->lock = 1; /* lock the struct */
217
218 /* allocate full-packet buffer */
219 curPacket = (char *) malloc(cur->commandlen + 6);
220
221 /* command byte */
222 curPacket[0] = 0x2a;
223
224 /* type/family byte */
225 curPacket[1] = cur->type;
226
227 /* bytes 3+4: word: FLAP sequence number */
228 aimutil_put16(curPacket+2, cur->seqnum);
229
230 /* bytes 5+6: word: SNAC len */
231 aimutil_put16(curPacket+4, cur->commandlen);
232
233 /* bytes 7 and on: raw: SNAC data */ /* XXX: ye gods! get rid of this! */
234 memcpy(&(curPacket[6]), cur->data, cur->commandlen);
235
236 /* full image of raw packet data now in curPacket */
237 faim_mutex_lock(&cur->conn->active);
238 if ( (u_int)write(cur->conn->fd, curPacket, (cur->commandlen + 6)) != (cur->commandlen + 6)) {
239 faim_mutex_unlock(&cur->conn->active);
240 printf("\nWARNING: Error in sending packet 0x%4x -- will try again next time\n\n", cur->seqnum);
241 cur->sent = 0; /* mark it unsent */
242 return 0; /* bail out -- continuable error */
243 } else {
244 faimdprintf(2, "\nSENT 0x%4x\n\n", cur->seqnum);
245
246 cur->sent = 1; /* mark the struct as sent */
247 cur->conn->lastactivity = time(NULL);
248 }
249 faim_mutex_unlock(&cur->conn->active);
250
251#if debug > 2
252 faimdprintf(2, "\nPacket:");
253 for (i = 0; i < (cur->commandlen + 6); i++) {
254 if ((i % 8) == 0) {
255 faimdprintf(2, "\n\t");
256 }
257 if (curPacket[i] >= ' ' && curPacket[i]<127) {
258 faimdprintf(2, "%c=%02x ", curPacket[i], curPacket[i]);
259 } else {
260 faimdprintf(2, "0x%2x ", curPacket[i]);
261 }
262 }
263 faimdprintf(2, "\n");
264#endif
265 cur->lock = 0; /* unlock the struct */
266 free(curPacket); /* free up full-packet buffer */
267
268 return 1; /* success */
269}
270
a25832e6 271int aim_tx_flushqueue(struct aim_session_t *sess)
9de3ca7e 272{
b8d0da45 273 struct command_tx_struct *cur;
e88ba395 274
9de3ca7e 275#if debug > 1
276 int i = 0;
277#endif
278
b8d0da45 279 if (sess->queue_outgoing == NULL)
280 return 0;
a25832e6 281
b8d0da45 282 faimdprintf(2, "beginning txflush...\n");
283 for (cur = sess->queue_outgoing; cur; cur = cur->next) {
284 /* only process if its unlocked and unsent */
285 if (!cur->lock && !cur->sent) {
a25832e6 286
b8d0da45 287 /*
288 * And now for the meager attempt to force transmit
289 * latency and avoid missed messages.
290 */
291 if ((cur->conn->lastactivity + cur->conn->forcedlatency) >= time(NULL)) {
292 /* FIXME FIXME -- should be a break! we dont want to block the upper layers */
293 sleep((cur->conn->lastactivity + cur->conn->forcedlatency) - time(NULL));
294 }
a25832e6 295
e88ba395 296 if (aim_tx_sendframe(cur) == -1)
297 break;
9de3ca7e 298 }
b8d0da45 299 }
9de3ca7e 300
301 /* purge sent commands from queue */
a25832e6 302 aim_tx_purgequeue(sess);
9de3ca7e 303
304 return 0;
305}
306
307/*
a25832e6 308 * aim_tx_purgequeue()
309 *
310 * This is responsable for removing sent commands from the transmit
311 * queue. This is not a required operation, but it of course helps
312 * reduce memory footprint at run time!
313 *
9de3ca7e 314 */
b8d0da45 315void aim_tx_purgequeue(struct aim_session_t *sess)
9de3ca7e 316{
b8d0da45 317 struct command_tx_struct *cur = NULL;
318 struct command_tx_struct *tmp;
319
a25832e6 320 if (sess->queue_outgoing == NULL)
b8d0da45 321 return;
322
323 if (sess->queue_outgoing->next == NULL) {
324 if (!sess->queue_outgoing->lock && sess->queue_outgoing->sent) {
325 tmp = sess->queue_outgoing;
326 sess->queue_outgoing = NULL;
327 free(tmp->data);
328 free(tmp);
9de3ca7e 329 }
b8d0da45 330 return;
331 }
332
333 for(cur = sess->queue_outgoing; cur->next != NULL; ) {
334 if (!cur->next->lock && cur->next->sent) {
335 tmp = cur->next;
336 cur->next = tmp->next;
337 free(tmp->data);
338 free(tmp);
339 }
340 cur = cur->next;
9de3ca7e 341
b8d0da45 342 /*
343 * Be careful here. Because of the way we just
344 * manipulated the pointer, cur may be NULL and
345 * the for() will segfault doing the check unless
346 * we find this case first.
347 */
348 if (cur == NULL)
349 break;
350 }
351 return;
9de3ca7e 352}
This page took 0.229114 seconds and 5 git commands to generate.