Mercurial > hg > index.fcgi > gift-gnutella > gift-gnutella-0.0.11-1pba
comparison 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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:e6ccaf892a98 |
---|---|
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 */ | |
16 | |
17 #include "gt_gnutella.h" | |
18 | |
19 #include "io/tx_stack.h" | |
20 #include "io/tx_layer.h" | |
21 #include "io/io_buf.h" | |
22 | |
23 /*****************************************************************************/ | |
24 | |
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; | |
29 | |
30 if (!(tx = NEW (struct tx_layer))) | |
31 return NULL; | |
32 | |
33 tx->ops = ops; | |
34 tx->name = name; | |
35 tx->stack = stack; | |
36 tx->partial_buf = NULL; | |
37 | |
38 if (!ops->init (tx)) | |
39 { | |
40 free (tx); | |
41 return NULL; | |
42 } | |
43 | |
44 return tx; | |
45 } | |
46 | |
47 void gt_tx_layer_free (struct tx_layer *layer) | |
48 { | |
49 if (!layer) | |
50 return; | |
51 | |
52 io_buf_free (layer->partial_buf); | |
53 | |
54 layer->ops->destroy (layer); | |
55 | |
56 FREE (layer); | |
57 } | |
58 | |
59 /*****************************************************************************/ | |
60 | |
61 static tx_status_t queue_data (struct tx_layer *tx, struct io_buf *io_buf) | |
62 { | |
63 tx_status_t ret; | |
64 | |
65 ret = tx->ops->queue (tx, io_buf); | |
66 | |
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); | |
74 | |
75 tx->partial_buf = io_buf; | |
76 return TX_OK; | |
77 } | |
78 | |
79 return ret; | |
80 } | |
81 | |
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; | |
86 | |
87 if (lower->partial_buf) | |
88 return TX_FULL; | |
89 | |
90 return queue_data (lower, io_buf); | |
91 } | |
92 | |
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; | |
98 | |
99 upper = tx->upper; | |
100 | |
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; | |
113 | |
114 tx->partial_buf = NULL; | |
115 | |
116 /* this ends up calling this layer's queue func */ | |
117 ret = queue_data (tx, io_buf); | |
118 | |
119 /* | |
120 * Can't happen because layer wouldn't have invoked us. | |
121 */ | |
122 assert (ret != TX_FULL); | |
123 assert (ret != TX_EMPTY); | |
124 | |
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 } | |
133 | |
134 ret = upper->ops->ready (upper); | |
135 assert (ret != TX_FULL); | |
136 | |
137 return ret; | |
138 } | |
139 | |
140 /*****************************************************************************/ | |
141 | |
142 void gt_tx_layer_enable (struct tx_layer *layer) | |
143 { | |
144 layer->ops->enable (layer); | |
145 } | |
146 | |
147 void gt_tx_layer_disable (struct tx_layer *layer) | |
148 { | |
149 layer->ops->disable (layer); | |
150 } |