4 * Herein lies all the mangement routines for the transmit (Tx) queue.
12 #include <sys/socket.h>
16 * Allocate a new tx frame.
18 * This is more for looks than anything else.
20 * Right now, that is. If/when we implement a pool of transmit
21 * frames, this will become the request-an-unused-frame part.
23 * framing = AIM_FRAMETYPE_OFT/FLAP
24 * chan = channel for FLAP, hdrtype for OFT
27 faim_internal aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, fu8_t framing, fu8_t chan, int datalen)
32 faimdprintf(sess, 0, "aim_tx_new: ERROR: no connection specified\n");
37 if ((conn->type == AIM_CONN_TYPE_RENDEZVOUS) ||
38 (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT)) {
39 if (framing != AIM_FRAMETYPE_OFT) {
40 faimdprintf(sess, 0, "aim_tx_new: attempted to allocate inappropriate frame type for rendezvous connection\n");
44 if (framing != AIM_FRAMETYPE_FLAP) {
45 faimdprintf(sess, 0, "aim_tx_new: attempted to allocate inappropriate frame type for FLAP connection\n");
50 if (!(fr = (aim_frame_t *)malloc(sizeof(aim_frame_t))))
52 memset(fr, 0, sizeof(aim_frame_t));
56 fr->hdrtype = framing;
58 if (fr->hdrtype == AIM_FRAMETYPE_FLAP) {
60 fr->hdr.flap.type = chan;
62 } else if (fr->hdrtype == AIM_FRAMETYPE_OFT) {
64 fr->hdr.oft.type = chan;
65 fr->hdr.oft.hdr2len = 0; /* this will get setup by caller */
68 faimdprintf(sess, 0, "tx_new: unknown framing\n");
73 if (!(data = (unsigned char *)malloc(datalen))) {
74 aim_frame_destroy(fr);
78 aim_bstream_init(&fr->data, data, datalen);
85 * aim_tx_enqeue__queuebased()
87 * The overall purpose here is to enqueue the passed in command struct
88 * into the outgoing (tx) queue. Basically...
89 * 1) Make a scope-irrelevent copy of the struct
90 * 3) Mark as not-sent-yet
91 * 4) Enqueue the struct into the list
94 * Note that this is only used when doing queue-based transmitting;
95 * that is, when sess->tx_enqueue is set to &aim_tx_enqueue__queuebased.
98 static int aim_tx_enqueue__queuebased(aim_session_t *sess, aim_frame_t *fr)
102 faimdprintf(sess, 1, "aim_tx_enqueue: WARNING: enqueueing packet with no connecetion\n");
103 fr->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS);
106 if (fr->hdrtype == AIM_FRAMETYPE_FLAP) {
107 /* assign seqnum -- XXX should really not assign until hardxmit */
108 fr->hdr.flap.seqnum = aim_get_next_txseqnum(fr->conn);
111 fr->handled = 0; /* not sent yet */
113 /* see overhead note in aim_rxqueue counterpart */
114 if (!sess->queue_outgoing)
115 sess->queue_outgoing = fr;
119 for (cur = sess->queue_outgoing; cur->next; cur = cur->next)
128 * aim_tx_enqueue__immediate()
130 * Parallel to aim_tx_enqueue__queuebased, however, this bypasses
131 * the whole queue mess when you want immediate writes to happen.
133 * Basically the same as its __queuebased couterpart, however
134 * instead of doing a list append, it just calls aim_tx_sendframe()
138 static int aim_tx_enqueue__immediate(aim_session_t *sess, aim_frame_t *fr)
142 faimdprintf(sess, 1, "aim_tx_enqueue: ERROR: packet has no connection\n");
143 aim_frame_destroy(fr);
147 if (fr->hdrtype == AIM_FRAMETYPE_FLAP)
148 fr->hdr.flap.seqnum = aim_get_next_txseqnum(fr->conn);
150 fr->handled = 0; /* not sent yet */
152 aim_tx_sendframe(sess, fr);
154 aim_frame_destroy(fr);
159 faim_export int aim_tx_setenqueue(aim_session_t *sess, int what, int (*func)(aim_session_t *, aim_frame_t *))
162 if (what == AIM_TX_QUEUED)
163 sess->tx_enqueue = &aim_tx_enqueue__queuebased;
164 else if (what == AIM_TX_IMMEDIATE)
165 sess->tx_enqueue = &aim_tx_enqueue__immediate;
166 else if (what == AIM_TX_USER) {
169 sess->tx_enqueue = func;
171 return -EINVAL; /* unknown action */
176 faim_internal int aim_tx_enqueue(aim_session_t *sess, aim_frame_t *fr)
180 * If we want to send a connection thats inprogress, we have to force
181 * them to use the queue based version. Otherwise, use whatever they
184 if (fr && fr->conn &&
185 (fr->conn->status & AIM_CONN_STATUS_INPROGRESS)) {
186 return aim_tx_enqueue__queuebased(sess, fr);
189 return (*sess->tx_enqueue)(sess, fr);
193 * aim_get_next_txseqnum()
195 * This increments the tx command count, and returns the seqnum
196 * that should be stamped on the next FLAP packet sent. This is
197 * normally called during the final step of packet preparation
198 * before enqueuement (in aim_tx_enqueue()).
201 faim_internal flap_seqnum_t aim_get_next_txseqnum(aim_conn_t *conn)
205 faim_mutex_lock(&conn->seqnum_lock);
206 ret = ++conn->seqnum;
207 faim_mutex_unlock(&conn->seqnum_lock);
212 static int aim_send(int fd, const void *buf, size_t count)
216 for (cur = 0, left = count; left; ) {
219 ret = send(fd, ((unsigned char *)buf)+cur, left, 0);
232 static int aim_bstream_send(aim_bstream_t *bs, aim_conn_t *conn, size_t count)
236 if (!bs || !conn || (count < 0))
239 if (count > aim_bstream_empty(bs))
240 count = aim_bstream_empty(bs); /* truncate to remaining space */
243 wrote = aim_send(conn->fd, bs->data + bs->offset, count);
245 if (((aim_session_t *)conn->sessv)->debug >= 2) {
247 aim_session_t *sess = (aim_session_t *)conn->sessv;
249 faimdprintf(sess, 2, "\nOutgoing data: (%d bytes)", wrote);
250 for (i = 0; i < wrote; i++) {
252 faimdprintf(sess, 2, "\n\t");
253 faimdprintf(sess, 2, "0x%02x ", *(bs->data + bs->offset + i));
255 faimdprintf(sess, 2, "\n");
264 static int sendframe_flap(aim_session_t *sess, aim_frame_t *fr)
268 int payloadlen, err = 0, obslen;
270 payloadlen = aim_bstream_curpos(&fr->data);
272 if (!(obs_raw = malloc(6 + payloadlen)))
275 aim_bstream_init(&obs, obs_raw, 6 + payloadlen);
278 aimbs_put8(&obs, 0x2a);
279 aimbs_put8(&obs, fr->hdr.flap.type);
280 aimbs_put16(&obs, fr->hdr.flap.seqnum);
281 aimbs_put16(&obs, payloadlen);
284 aim_bstream_rewind(&fr->data);
285 aimbs_putbs(&obs, &fr->data, payloadlen);
287 obslen = aim_bstream_curpos(&obs);
288 aim_bstream_rewind(&obs);
290 if (aim_bstream_send(&obs, fr->conn, obslen) != obslen)
293 free(obs_raw); /* XXX aim_bstream_free */
296 fr->conn->lastactivity = time(NULL);
301 static int sendframe_oft(aim_session_t *sess, aim_frame_t *fr)
308 hbslen = 8 + fr->hdr.oft.hdr2len;
310 if (!(hbs_raw = malloc(hbslen)))
313 aim_bstream_init(&hbs, hbs_raw, hbslen);
315 aimbs_putraw(&hbs, fr->hdr.oft.magic, 4);
316 aimbs_put16(&hbs, fr->hdr.oft.hdr2len + 8);
317 aimbs_put16(&hbs, fr->hdr.oft.type);
318 aimbs_putraw(&hbs, fr->hdr.oft.hdr2, fr->hdr.oft.hdr2len);
320 if (aim_bstream_send(&hbs, fr->conn, hbslen) != hbslen) {
324 } else if (aim_bstream_curpos(&fr->data)) {
327 len = aim_bstream_curpos(&fr->data);
328 aim_bstream_rewind(&fr->data);
330 if (aim_bstream_send(&fr->data, fr->conn, len) != len)
334 free(hbs_raw); /* XXX aim_bstream_free */
337 fr->conn->lastactivity = time(NULL);
342 faim_internal int aim_tx_sendframe(aim_session_t *sess, aim_frame_t *fr)
344 if (fr->hdrtype == AIM_FRAMETYPE_FLAP)
345 return sendframe_flap(sess, fr);
346 else if (fr->hdrtype == AIM_FRAMETYPE_OFT)
347 return sendframe_oft(sess, fr);
351 faim_export int aim_tx_flushqueue(aim_session_t *sess)
355 for (cur = sess->queue_outgoing; cur; cur = cur->next) {
358 continue; /* already been sent */
360 if (cur->conn && (cur->conn->status & AIM_CONN_STATUS_INPROGRESS))
364 * And now for the meager attempt to force transmit
365 * latency and avoid missed messages.
367 if ((cur->conn->lastactivity + cur->conn->forcedlatency) >= time(NULL)) {
369 * XXX should be a break! we dont want to block the
372 * XXX or better, just do this right.
375 sleep((cur->conn->lastactivity + cur->conn->forcedlatency) - time(NULL));
378 /* XXX this should call the custom "queuing" function!! */
379 aim_tx_sendframe(sess, cur);
382 /* purge sent commands from queue */
383 aim_tx_purgequeue(sess);
389 * aim_tx_purgequeue()
391 * This is responsable for removing sent commands from the transmit
392 * queue. This is not a required operation, but it of course helps
393 * reduce memory footprint at run time!
396 faim_export void aim_tx_purgequeue(aim_session_t *sess)
398 aim_frame_t *cur, **prev;
400 for (prev = &sess->queue_outgoing; (cur = *prev); ) {
405 aim_frame_destroy(cur);
415 * aim_tx_cleanqueue - get rid of packets waiting for tx on a dying conn
417 * @conn: connection that's dying
419 * for now this simply marks all packets as sent and lets them
420 * disappear without warning.
423 faim_export void aim_tx_cleanqueue(aim_session_t *sess, aim_conn_t *conn)
427 for (cur = sess->queue_outgoing; cur; cur = cur->next) {
428 if (cur->conn == conn)