/** * Shutdown stack, disallowing further writes. */ void tx_shutdown(txdrv_t *tx) { txdrv_t *t; tx_check(tx); g_assert(tx->upper == NULL); for (t = tx; t; t = t->lower) { t->flags |= TX_DOWN; /* Signal we're going down */ /* * If we reach a stage where the service routine was enabled (the * lower driver was meant to call its upper layer service routine * when further writing was possible), disable it. That way, the * layer-specific shutdown does not have to bother with that. */ if (t->flags & TX_SERVICE) tx_srv_disable(t); TX_SHUTDOWN(t); } }
/** * Service routine for UDP message queue. */ static void mq_udp_service(void *data) { mqueue_t *q = data; int r; GList *l; unsigned dropped = 0; mq_check(q, 0); g_assert(q->count); /* Queue is serviced, we must have something */ /* * Write as much as possible. */ for (l = q->qtail; l; /* empty */) { pmsg_t *mb = l->data; int mb_size = pmsg_size(mb); struct mq_udp_info *mi = pmsg_get_metadata(mb); if (!pmsg_check(mb, q)) { dropped++; goto skip; } r = tx_sendto(q->tx_drv, mb, &mi->to); if (r < 0) /* Error, drop packet and continue */ goto skip; if (r == 0) /* No more bandwidth */ break; g_assert(r == mb_size); node_add_tx_given(q->node, r); if (q->flags & MQ_FLOWC) q->flowc_written += r; /* * The UDP layer is non-reliable so the message could be dropped * later on by lower layers. * * Therefore, message statistics will be updated by a specific * accounting callback that is known to the datagram layer, such * as node_msg_accounting(). */ skip: if (q->qlink) q->cops->qlink_remove(q, l); /* drop the message from queue, will be freed by mq_rmlink_prev() */ l = q->cops->rmlink_prev(q, l, mb_size); } mq_check(q, 0); g_assert(q->size >= 0 && q->count >= 0); if (dropped) node_add_txdrop(q->node, dropped); /* Dropped during TX */ /* * Update flow-control information. */ q->cops->update_flowc(q); /* * If queue is empty, disable servicing. */ if (q->size == 0) { g_assert(q->count == 0); tx_srv_disable(q->tx_drv); node_tx_service(q->node, FALSE); } mq_check(q, 0); }
/** * Service routine for the compressing stage. * * Called by lower layer when it is ready to process more data. */ static void deflate_service(void *data) { txdrv_t *tx = data; struct attr *attr = tx->opaque; struct buffer *b; g_assert(attr->send_idx < BUFFER_COUNT); if (tx_deflate_debugging(9)) { g_debug("TX %s: (%s) %s(buffer #%d, %zu bytes held) [%c%c]", G_STRFUNC, gnet_host_to_string(&tx->host), (tx->flags & TX_ERROR) ? "ERROR " : "", attr->send_idx, attr->send_idx >= 0 ? (attr->buf[attr->send_idx].wptr - attr->buf[attr->send_idx].rptr) : 0, (attr->flags & DF_FLOWC) ? 'C' : '-', (attr->flags & DF_FLUSH) ? 'f' : '-'); } /* * First, attempt to transmit the whole send buffer, if any pending. */ if (attr->send_idx >= 0) deflate_send(tx); /* Send buffer `send_idx' */ if (attr->send_idx >= 0) /* Could not send it entirely */ return; /* Done, servicing still enabled */ /* * NB: In the following operations, order matters. In particular, we * must disable the servicing before attempting to service the upper * layer, since the data it will send us can cause us to flow control * and re-enable the servicing. * * If the `fill' buffer is full, try to send it now. */ b = &attr->buf[attr->fill_idx]; /* Buffer we fill */ if (b->wptr >= b->end) { if (tx_deflate_debugging(9)) { g_debug("TX %s: (%s) sending fill buffer #%d, %zu bytes", G_STRFUNC, gnet_host_to_string(&tx->host), attr->fill_idx, b->wptr - b->rptr); } deflate_rotate_and_send(tx); /* Can set TX_ERROR */ if (tx->flags & TX_ERROR) return; } /* * If we were able to send the whole send buffer, disable servicing. */ if (-1 == attr->send_idx) tx_srv_disable(tx->lower); /* * If we entered flow control, we can now safely leave it, since we * have at least a free `fill' buffer. */ if (attr->flags & DF_FLOWC) deflate_set_flowc(tx, FALSE); /* Leave flow control state */ /* * If closing, we're done once we have flushed everything we could. * There's no need to even bother with the upper layer: if we're * closing, we won't accept any further data to write anyway. */ if (tx->flags & TX_CLOSING) { deflate_flush_send(tx); if (tx->flags & TX_ERROR) return; if (0 == tx_deflate_pending(tx)) { (*attr->closed)(tx, attr->closed_arg); return; } } if (tx_deflate_debugging(9)) { g_debug("TX %s: (%s) %sdone locally [%c%c]", G_STRFUNC, gnet_host_to_string(&tx->host), (tx->flags & TX_ERROR) ? "ERROR " : "", (attr->flags & DF_FLOWC) ? 'C' : '-', (attr->flags & DF_FLUSH) ? 'f' : '-'); } /* * If upper layer wants servicing, do it now. * Note that this can put us back into flow control. */ if (tx->flags & TX_SERVICE) { g_assert(tx->srv_routine); tx->srv_routine(tx->srv_arg); } }