source: protocols/oscar/txqueue.c @ 4a9c6b0

Last change on this file since 4a9c6b0 was e88fe7da, checked in by Veres Lajos <vlajos@…>, at 2015-08-07T21:53:25Z

typofix - https://github.com/vlajos/misspell_fixer

  • Property mode set to 100644
File size: 7.5 KB
RevLine 
[b7d3cc34]1/*
2 *  aim_txqueue.c
3 *
4 * Herein lies all the mangement routines for the transmit (Tx) queue.
5 *
6 */
7
8#include <aim.h>
9#include "im.h"
10
11#include <sys/socket.h>
12
13/*
14 * Allocate a new tx frame.
15 *
16 * This is more for looks than anything else.
17 *
18 * Right now, that is.  If/when we implement a pool of transmit
19 * frames, this will become the request-an-unused-frame part.
20 *
21 * framing = AIM_FRAMETYPE_OFT/FLAP
22 * chan = channel for FLAP, hdrtype for OFT
23 *
24 */
25aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, guint8 framing, guint8 chan, int datalen)
26{
27        aim_frame_t *fr;
28
29        if (!conn) {
[84b045d]30                imcb_error(sess->aux_data, "no connection specified");
[b7d3cc34]31                return NULL;
32        }
33
[5ebff60]34        if (!(fr = (aim_frame_t *) g_new0(aim_frame_t, 1))) {
[b7d3cc34]35                return NULL;
[5ebff60]36        }
[b7d3cc34]37
[5ebff60]38        fr->conn = conn;
[b7d3cc34]39
40        fr->hdrtype = framing;
41
42        if (fr->hdrtype == AIM_FRAMETYPE_FLAP) {
43
44                fr->hdr.flap.type = chan;
45
[5ebff60]46        } else {
[84b045d]47                imcb_error(sess->aux_data, "unknown framing");
[5ebff60]48        }
[b7d3cc34]49
50        if (datalen > 0) {
51                guint8 *data;
52
[5ebff60]53                if (!(data = (unsigned char *) g_malloc(datalen))) {
[b7d3cc34]54                        aim_frame_destroy(fr);
55                        return NULL;
56                }
57
58                aim_bstream_init(&fr->data, data, datalen);
59        }
60
61        return fr;
62}
63
64/*
65 * aim_tx_enqeue__queuebased()
66 *
67 * The overall purpose here is to enqueue the passed in command struct
68 * into the outgoing (tx) queue.  Basically...
[e88fe7da]69 *   1) Make a scope-irrelevant copy of the struct
[b7d3cc34]70 *   3) Mark as not-sent-yet
71 *   4) Enqueue the struct into the list
72 *   6) Return
73 *
74 * Note that this is only used when doing queue-based transmitting;
75 * that is, when sess->tx_enqueue is set to &aim_tx_enqueue__queuebased.
76 *
77 */
78static int aim_tx_enqueue__queuebased(aim_session_t *sess, aim_frame_t *fr)
79{
80
81        if (!fr->conn) {
[43462708]82                imcb_error(sess->aux_data, "Warning: enqueueing packet with no connection");
[b7d3cc34]83                fr->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS);
84        }
85
86        if (fr->hdrtype == AIM_FRAMETYPE_FLAP) {
87                /* assign seqnum -- XXX should really not assign until hardxmit */
88                fr->hdr.flap.seqnum = aim_get_next_txseqnum(fr->conn);
89        }
90
91        fr->handled = 0; /* not sent yet */
92
93        /* see overhead note in aim_rxqueue counterpart */
[5ebff60]94        if (!sess->queue_outgoing) {
[b7d3cc34]95                sess->queue_outgoing = fr;
[5ebff60]96        } else {
[b7d3cc34]97                aim_frame_t *cur;
98
[5ebff60]99                for (cur = sess->queue_outgoing; cur->next; cur = cur->next) {
[b7d3cc34]100                        ;
[5ebff60]101                }
[b7d3cc34]102                cur->next = fr;
103        }
104
105        return 0;
106}
107
108/*
109 * aim_tx_enqueue__immediate()
110 *
111 * Parallel to aim_tx_enqueue__queuebased, however, this bypasses
112 * the whole queue mess when you want immediate writes to happen.
113 *
114 * Basically the same as its __queuebased couterpart, however
115 * instead of doing a list append, it just calls aim_tx_sendframe()
[5ebff60]116 * right here.
117 *
[b7d3cc34]118 */
119static int aim_tx_enqueue__immediate(aim_session_t *sess, aim_frame_t *fr)
120{
121
122        if (!fr->conn) {
[84b045d]123                imcb_error(sess->aux_data, "packet has no connection");
[b7d3cc34]124                aim_frame_destroy(fr);
125                return 0;
126        }
127
[5ebff60]128        if (fr->hdrtype == AIM_FRAMETYPE_FLAP) {
[b7d3cc34]129                fr->hdr.flap.seqnum = aim_get_next_txseqnum(fr->conn);
[5ebff60]130        }
[b7d3cc34]131
132        fr->handled = 0; /* not sent yet */
133
134        aim_tx_sendframe(sess, fr);
135
136        aim_frame_destroy(fr);
137
138        return 0;
139}
140
141int aim_tx_setenqueue(aim_session_t *sess, int what, int (*func)(aim_session_t *, aim_frame_t *))
142{
[5ebff60]143
144        if (what == AIM_TX_QUEUED) {
[b7d3cc34]145                sess->tx_enqueue = &aim_tx_enqueue__queuebased;
[5ebff60]146        } else if (what == AIM_TX_IMMEDIATE) {
[b7d3cc34]147                sess->tx_enqueue = &aim_tx_enqueue__immediate;
[5ebff60]148        } else if (what == AIM_TX_USER) {
149                if (!func) {
[b7d3cc34]150                        return -EINVAL;
[5ebff60]151                }
[b7d3cc34]152                sess->tx_enqueue = func;
[5ebff60]153        } else {
[b7d3cc34]154                return -EINVAL; /* unknown action */
155
[5ebff60]156        }
[b7d3cc34]157        return 0;
158}
159
160int aim_tx_enqueue(aim_session_t *sess, aim_frame_t *fr)
161{
[5ebff60]162
[b7d3cc34]163        /*
164         * If we want to send a connection thats inprogress, we have to force
165         * them to use the queue based version. Otherwise, use whatever they
166         * want.
167         */
[5ebff60]168        if (fr && fr->conn &&
169            (fr->conn->status & AIM_CONN_STATUS_INPROGRESS)) {
[b7d3cc34]170                return aim_tx_enqueue__queuebased(sess, fr);
171        }
172
173        return (*sess->tx_enqueue)(sess, fr);
174}
175
[5ebff60]176/*
[b7d3cc34]177 *  aim_get_next_txseqnum()
178 *
179 *   This increments the tx command count, and returns the seqnum
180 *   that should be stamped on the next FLAP packet sent.  This is
181 *   normally called during the final step of packet preparation
182 *   before enqueuement (in aim_tx_enqueue()).
183 *
184 */
185flap_seqnum_t aim_get_next_txseqnum(aim_conn_t *conn)
186{
187        flap_seqnum_t ret;
[5ebff60]188
[b7d3cc34]189        ret = ++conn->seqnum;
190
191        return ret;
192}
193
194static int aim_send(int fd, const void *buf, size_t count)
195{
196        int left, cur;
197
198        for (cur = 0, left = count; left; ) {
199                int ret;
200
[5ebff60]201                ret = send(fd, ((unsigned char *) buf) + cur, left, 0);
202                if (ret == -1) {
[b7d3cc34]203                        return -1;
[5ebff60]204                } else if (ret == 0) {
[b7d3cc34]205                        return cur;
[5ebff60]206                }
[b7d3cc34]207
208                cur += ret;
209                left -= ret;
210        }
211
212        return cur;
213}
214
215static int aim_bstream_send(aim_bstream_t *bs, aim_conn_t *conn, size_t count)
216{
217        int wrote = 0;
[5ebff60]218
219        if (!bs || !conn || (count < 0)) {
[b7d3cc34]220                return -EINVAL;
[5ebff60]221        }
[b7d3cc34]222
[5ebff60]223        if (count > aim_bstream_empty(bs)) {
[b7d3cc34]224                count = aim_bstream_empty(bs); /* truncate to remaining space */
225
[5ebff60]226        }
[b7d3cc34]227        if (count) {
228                if (count - wrote) {
229                        wrote = wrote + aim_send(conn->fd, bs->data + bs->offset + wrote, count - wrote);
230                }
[5ebff60]231
[b7d3cc34]232        }
[5ebff60]233
[b7d3cc34]234        bs->offset += wrote;
235
[5ebff60]236        return wrote;
[b7d3cc34]237}
238
239static int sendframe_flap(aim_session_t *sess, aim_frame_t *fr)
240{
241        aim_bstream_t obs;
242        guint8 *obs_raw;
243        int payloadlen, err = 0, obslen;
244
245        payloadlen = aim_bstream_curpos(&fr->data);
246
[5ebff60]247        if (!(obs_raw = g_malloc(6 + payloadlen))) {
[b7d3cc34]248                return -ENOMEM;
[5ebff60]249        }
[b7d3cc34]250
251        aim_bstream_init(&obs, obs_raw, 6 + payloadlen);
252
253        /* FLAP header */
254        aimbs_put8(&obs, 0x2a);
255        aimbs_put8(&obs, fr->hdr.flap.type);
256        aimbs_put16(&obs, fr->hdr.flap.seqnum);
257        aimbs_put16(&obs, payloadlen);
258
259        /* payload */
260        aim_bstream_rewind(&fr->data);
261        aimbs_putbs(&obs, &fr->data, payloadlen);
262
263        obslen = aim_bstream_curpos(&obs);
264        aim_bstream_rewind(&obs);
[5ebff60]265        if (aim_bstream_send(&obs, fr->conn, obslen) != obslen) {
[b7d3cc34]266                err = -errno;
[5ebff60]267        }
268
[b7d3cc34]269        g_free(obs_raw); /* XXX aim_bstream_free */
270
271        fr->handled = 1;
272        fr->conn->lastactivity = time(NULL);
273
274        return err;
275}
276
277int aim_tx_sendframe(aim_session_t *sess, aim_frame_t *fr)
278{
[5ebff60]279        if (fr->hdrtype == AIM_FRAMETYPE_FLAP) {
[b7d3cc34]280                return sendframe_flap(sess, fr);
[5ebff60]281        }
[b7d3cc34]282        return -1;
283}
284
285int aim_tx_flushqueue(aim_session_t *sess)
286{
287        aim_frame_t *cur;
288
289        for (cur = sess->queue_outgoing; cur; cur = cur->next) {
290
[5ebff60]291                if (cur->handled) {
292                        continue; /* already been sent */
[b7d3cc34]293
[5ebff60]294                }
295                if (cur->conn && (cur->conn->status & AIM_CONN_STATUS_INPROGRESS)) {
[b7d3cc34]296                        continue;
[5ebff60]297                }
[b7d3cc34]298
299                /*
300                 * And now for the meager attempt to force transmit
301                 * latency and avoid missed messages.
302                 */
303                if ((cur->conn->lastactivity + cur->conn->forcedlatency) >= time(NULL)) {
[5ebff60]304                        /*
305                         * XXX should be a break! we dont want to block the
[b7d3cc34]306                         * upper layers
307                         *
308                         * XXX or better, just do this right.
309                         *
310                         */
311                        sleep((cur->conn->lastactivity + cur->conn->forcedlatency) - time(NULL));
312                }
313
314                /* XXX this should call the custom "queuing" function!! */
315                aim_tx_sendframe(sess, cur);
316        }
317
318        /* purge sent commands from queue */
319        aim_tx_purgequeue(sess);
320
321        return 0;
322}
323
324/*
325 *  aim_tx_purgequeue()
[5ebff60]326 *
327 *  This is responsable for removing sent commands from the transmit
[b7d3cc34]328 *  queue. This is not a required operation, but it of course helps
[5ebff60]329 *  reduce memory footprint at run time!
[b7d3cc34]330 *
331 */
332void aim_tx_purgequeue(aim_session_t *sess)
333{
334        aim_frame_t *cur, **prev;
335
336        for (prev = &sess->queue_outgoing; (cur = *prev); ) {
337
338                if (cur->handled) {
339                        *prev = cur->next;
340
341                        aim_frame_destroy(cur);
342
[5ebff60]343                } else {
[b7d3cc34]344                        prev = &cur->next;
[5ebff60]345                }
[b7d3cc34]346        }
347
348        return;
349}
350
351/**
352 * aim_tx_cleanqueue - get rid of packets waiting for tx on a dying conn
353 * @sess: session
354 * @conn: connection that's dying
355 *
356 * for now this simply marks all packets as sent and lets them
357 * disappear without warning.
358 *
359 */
360void aim_tx_cleanqueue(aim_session_t *sess, aim_conn_t *conn)
361{
362        aim_frame_t *cur;
363
364        for (cur = sess->queue_outgoing; cur; cur = cur->next) {
[5ebff60]365                if (cur->conn == conn) {
[b7d3cc34]366                        cur->handled = 1;
[5ebff60]367                }
[b7d3cc34]368        }
369
370        return;
371}
372
373
Note: See TracBrowser for help on using the repository browser.