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 }
|