annotate src/io/tx_layer.c @ 0:d39e1d0d75b6

initial add
author paulo@hit-nxdomain.opendns.com
date Sat, 20 Feb 2010 21:18:28 -0800
parents
children
rev   line source
paulo@0 1 /*
paulo@0 2 * $Id: tx_layer.c,v 1.7 2004/03/24 06:37:30 hipnod Exp $
paulo@0 3 *
paulo@0 4 * Copyright (C) 2003 giFT project (gift.sourceforge.net)
paulo@0 5 *
paulo@0 6 * This program is free software; you can redistribute it and/or modify it
paulo@0 7 * under the terms of the GNU General Public License as published by the
paulo@0 8 * Free Software Foundation; either version 2, or (at your option) any
paulo@0 9 * later version.
paulo@0 10 *
paulo@0 11 * This program is distributed in the hope that it will be useful, but
paulo@0 12 * WITHOUT ANY WARRANTY; without even the implied warranty of
paulo@0 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
paulo@0 14 * General Public License for more details.
paulo@0 15 */
paulo@0 16
paulo@0 17 #include "gt_gnutella.h"
paulo@0 18
paulo@0 19 #include "io/tx_stack.h"
paulo@0 20 #include "io/tx_layer.h"
paulo@0 21 #include "io/io_buf.h"
paulo@0 22
paulo@0 23 /*****************************************************************************/
paulo@0 24
paulo@0 25 struct tx_layer *gt_tx_layer_new (GtTxStack *stack, const char *name,
paulo@0 26 struct tx_layer_ops *ops)
paulo@0 27 {
paulo@0 28 struct tx_layer *tx;
paulo@0 29
paulo@0 30 if (!(tx = NEW (struct tx_layer)))
paulo@0 31 return NULL;
paulo@0 32
paulo@0 33 tx->ops = ops;
paulo@0 34 tx->name = name;
paulo@0 35 tx->stack = stack;
paulo@0 36 tx->partial_buf = NULL;
paulo@0 37
paulo@0 38 if (!ops->init (tx))
paulo@0 39 {
paulo@0 40 free (tx);
paulo@0 41 return NULL;
paulo@0 42 }
paulo@0 43
paulo@0 44 return tx;
paulo@0 45 }
paulo@0 46
paulo@0 47 void gt_tx_layer_free (struct tx_layer *layer)
paulo@0 48 {
paulo@0 49 if (!layer)
paulo@0 50 return;
paulo@0 51
paulo@0 52 io_buf_free (layer->partial_buf);
paulo@0 53
paulo@0 54 layer->ops->destroy (layer);
paulo@0 55
paulo@0 56 FREE (layer);
paulo@0 57 }
paulo@0 58
paulo@0 59 /*****************************************************************************/
paulo@0 60
paulo@0 61 static tx_status_t queue_data (struct tx_layer *tx, struct io_buf *io_buf)
paulo@0 62 {
paulo@0 63 tx_status_t ret;
paulo@0 64
paulo@0 65 ret = tx->ops->queue (tx, io_buf);
paulo@0 66
paulo@0 67 /*
paulo@0 68 * If the message didn't get completely written, buffer the partial
paulo@0 69 * message buffer until it's finished.
paulo@0 70 */
paulo@0 71 if (ret == TX_PARTIAL)
paulo@0 72 {
paulo@0 73 assert (io_buf_read_avail (io_buf) > 0);
paulo@0 74
paulo@0 75 tx->partial_buf = io_buf;
paulo@0 76 return TX_OK;
paulo@0 77 }
paulo@0 78
paulo@0 79 return ret;
paulo@0 80 }
paulo@0 81
paulo@0 82 /* send a message to the layer underneath this one */
paulo@0 83 tx_status_t gt_tx_layer_queue (struct tx_layer *tx, struct io_buf *io_buf)
paulo@0 84 {
paulo@0 85 struct tx_layer *lower = tx->lower;
paulo@0 86
paulo@0 87 if (lower->partial_buf)
paulo@0 88 return TX_FULL;
paulo@0 89
paulo@0 90 return queue_data (lower, io_buf);
paulo@0 91 }
paulo@0 92
paulo@0 93 /* let upper layer know we're writable and get data from it */
paulo@0 94 tx_status_t gt_tx_layer_ready (struct tx_layer *tx)
paulo@0 95 {
paulo@0 96 struct tx_layer *upper;
paulo@0 97 tx_status_t ret;
paulo@0 98
paulo@0 99 upper = tx->upper;
paulo@0 100
paulo@0 101 /*
paulo@0 102 * If there is a partially written buffer on the layer, try to finish it
paulo@0 103 * off before asking for more data by pretending the upper layer tried to
paulo@0 104 * write it.
paulo@0 105 *
paulo@0 106 * Doing this avoids a special case in each layer where a partial buffer
paulo@0 107 * is kept set aside and checked before calling gt_tx_layer_ready(), leading
paulo@0 108 * to less code.
paulo@0 109 */
paulo@0 110 if (tx->partial_buf)
paulo@0 111 {
paulo@0 112 struct io_buf *io_buf = tx->partial_buf;
paulo@0 113
paulo@0 114 tx->partial_buf = NULL;
paulo@0 115
paulo@0 116 /* this ends up calling this layer's queue func */
paulo@0 117 ret = queue_data (tx, io_buf);
paulo@0 118
paulo@0 119 /*
paulo@0 120 * Can't happen because layer wouldn't have invoked us.
paulo@0 121 */
paulo@0 122 assert (ret != TX_FULL);
paulo@0 123 assert (ret != TX_EMPTY);
paulo@0 124
paulo@0 125 /*
paulo@0 126 * Upper layer can't be safely invoked again, even if the partial
paulo@0 127 * buffer was completed, because we don't know if the lower layer has
paulo@0 128 * any more room. So, the lower layer must reinvoke tx_layer_ready()
paulo@0 129 * to write more data.
paulo@0 130 */
paulo@0 131 return ret;
paulo@0 132 }
paulo@0 133
paulo@0 134 ret = upper->ops->ready (upper);
paulo@0 135 assert (ret != TX_FULL);
paulo@0 136
paulo@0 137 return ret;
paulo@0 138 }
paulo@0 139
paulo@0 140 /*****************************************************************************/
paulo@0 141
paulo@0 142 void gt_tx_layer_enable (struct tx_layer *layer)
paulo@0 143 {
paulo@0 144 layer->ops->enable (layer);
paulo@0 145 }
paulo@0 146
paulo@0 147 void gt_tx_layer_disable (struct tx_layer *layer)
paulo@0 148 {
paulo@0 149 layer->ops->disable (layer);
paulo@0 150 }