The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
packet.c
Go to the documentation of this file.
1/*
2 * This program is is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or (at
5 * your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: 172455e51bc04cef9c5240784d98cc0174d91736 $
19 * @file lib/bio/packet.c
20 * @brief BIO PACKET handlers
21 *
22 * @copyright 2024 Network RADIUS SAS (legal@networkradius.com)
23 */
24
25#include <freeradius-devel/bio/bio_priv.h>
26#include <freeradius-devel/bio/packet.h>
27
28/** Inform all of the BIOs that the write is blocked.
29 *
30 * This function should be set as the BIO layer "write_blocked" callback for all BIOs created as part
31 * of a #fr_bio_packet_t. The application should also set bio->uctx=bio_packet for all BIOs.
32 */
34{
35 fr_bio_packet_t *my = bio->uctx;
36
37 /*
38 * This function must be callable multiple times, as different portions of the BIOs can block at
39 * different times.
40 */
41 if (my->write_blocked) return 1;
42 my->write_blocked = true;
43
44 /*
45 * The application doesn't want to know that it's blocked, so we just return.
46 */
47 if (!my->cb.write_blocked) return 1;
48
49 /*
50 * Tell the application that IO is blocked.
51 */
52 return my->cb.write_blocked(my);
53}
54
56{
57 fr_bio_packet_t *my = bio->uctx;
58 fr_bio_t *next;
59 int rcode;
60
61 if (!my->write_blocked) return 1;
62 my->write_blocked = false;
63
64 /*
65 * Inform each underlying BIO that it can be resumed. Note that we might be called from a
66 * lower-layer BIO, so we have to start from the top of the chain.
67 *
68 * Note that if the callback returns 0, saying "I couldn't resume", then the BIO is still marked
69 * as blocked.
70 */
71 for (next = my->bio;
72 next != NULL;
73 next = fr_bio_next(next)) {
74
75 if (!((fr_bio_common_t *) next)->priv_cb.write_resume) continue;
76
77 rcode = ((fr_bio_common_t *) next)->priv_cb.write_resume(next);
78 if (rcode < 0) return rcode;
79
80 if (rcode == 0) {
81 my->write_blocked = true;
82 return 0;
83 }
84 }
85
86 if (!my->cb.write_resume) return 0;
87
88 rcode = my->cb.write_resume(my);
89 if (rcode < 0) return rcode;
90 my->write_blocked = (rcode == 0);
91
92 return rcode;
93}
94
96{
97 fr_bio_packet_t *my = bio->uctx;
98
99 my->read_blocked = true;
100
101 if (!my->cb.read_blocked) return 0;
102
103 return my->cb.read_blocked(my);
104}
105
107{
108 fr_bio_packet_t *my = bio->uctx;
109
110 my->read_blocked = false;
111
112 if (!my->cb.read_resume) return 0;
113
114 return my->cb.read_resume(my);
115}
116
117/** Called when a particular BIO is connected.
118 *
119 * We see if we can connect the previous BIOs.
120 */
122{
123 fr_bio_packet_t *my = bio->uctx;
124
125 fr_assert(!my->connected);
126
127 /*
128 * Run the internal connected callback for previous BIOs. If one returns "not connected", then
129 * the packet BIO as a whole is not connected.
130 */
131 while ((bio = fr_bio_prev(bio)) != NULL) {
132 if (!((fr_bio_common_t *) bio)->priv_cb.connected) continue;
133
134 /*
135 * Tell this BIO that everything it needs has been connected.
136 */
137 if (((fr_bio_common_t *) bio)->priv_cb.connected(bio) == 0) return;
138 }
139
140 /*
141 * The top-level BIO is connected. This means that the entire chain is now connected, and is
142 * usable by the application.
143 */
144 my->connected = true;
145
146 /*
147 * Stop any connection timeout.
148 */
149 FR_TIMER_DELETE(&my->ev);
150
151 if (!my->cb.connected) return;
152
153 /*
154 * Tell the application that the packet BIO is now usable.
155 */
156 my->cb.connected(my);
157}
158
160{
161 int rcode;
162 fr_bio_packet_t *my = bio->uctx;
163
164 rcode = fr_bio_shutdown(bio);
165 if (rcode < 0) return rcode;
166
167 if (!my->cb.shutdown) return 0;
168
169 return my->cb.shutdown(my);
170}
171
173{
174 fr_bio_packet_t *my = bio->uctx;
175
176 if (my->cb.eof) my->cb.eof(my);
177 my->cb.eof = NULL;
178}
179
181{
182 fr_bio_packet_t *my = bio->uctx;
183
184 if (my->cb.failed) my->cb.failed(my);
185 my->cb.failed = NULL;
186}
187
188
190{
191 fr_bio_t *bio = my->bio;
192
193 fr_bio_cb_funcs_t bio_cb = {
195 .shutdown = fr_bio_packet_shutdown,
196 .eof = fr_bio_packet_eof,
197 .failed = fr_bio_packet_failed,
198
199 .write_blocked = fr_bio_packet_write_blocked,
200 .write_resume = fr_bio_packet_write_resume,
201 .read_blocked = fr_bio_packet_read_blocked,
202 .read_resume = fr_bio_packet_read_resume,
203 };
204
205 /*
206 * Every participating BIO has us set as the bio->uctx, and we handle all BIO callbacks.
207 *
208 * The application sets its own pointer my->uctx and sets itself via our callbacks.
209 */
210 while (bio) {
211 bio->uctx = my;
212
213 fr_bio_cb_set(bio, &bio_cb);
214 bio = fr_bio_next(bio);
215 }
216}
static fr_bio_t * fr_bio_prev(fr_bio_t *bio)
Definition base.h:122
static fr_bio_t * fr_bio_next(fr_bio_t *bio)
Definition base.h:131
fr_bio_callback_t connected
called when the BIO is ready to be used
Definition base.h:89
void * uctx
user ctx, caller can manually set it.
Definition base.h:114
void fr_bio_shutdown & my
Definition fd_errno.h:70
void fr_bio_cb_set(fr_bio_t *bio, fr_bio_cb_funcs_t const *cb)
Definition base.c:193
int fr_bio_shutdown(fr_bio_t *bio)
Shut down a set of BIOs.
Definition base.c:98
void fr_bio_packet_init(fr_bio_packet_t *my)
Definition packet.c:189
void fr_bio_packet_connected(fr_bio_t *bio)
Called when a particular BIO is connected.
Definition packet.c:121
static void fr_bio_packet_failed(fr_bio_t *bio)
Definition packet.c:180
static void fr_bio_packet_eof(fr_bio_t *bio)
Definition packet.c:172
static int fr_bio_packet_write_blocked(fr_bio_t *bio)
Inform all of the BIOs that the write is blocked.
Definition packet.c:33
static int fr_bio_packet_read_resume(fr_bio_t *bio)
Definition packet.c:106
static int fr_bio_packet_read_blocked(fr_bio_t *bio)
Definition packet.c:95
static int fr_bio_packet_shutdown(fr_bio_t *bio)
Definition packet.c:159
static int fr_bio_packet_write_resume(fr_bio_t *bio)
Definition packet.c:55
#define fr_assert(_expr)
Definition rad_assert.h:38
#define FR_TIMER_DELETE(_ev_p)
Definition timer.h:103