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