The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: bdf72473a940e88b13b624668bd3e0cb605e88a4 $
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  rcode = my->cb.write_resume(my);
87  if (rcode < 0) return rcode;
88 
89  my->write_blocked = (rcode == 0);
90 
91  return rcode;
92 }
93 
95 {
96  fr_bio_packet_t *my = bio->uctx;
97 
98  my->read_blocked = true;
99 
100  return my->cb.read_blocked(my);
101 }
102 
104 {
105  fr_bio_packet_t *my = bio->uctx;
106 
107  my->read_blocked = false;
108 
109  return my->cb.read_resume(my);
110 }
111 
112 /** Called when a particular BIO is connected.
113  *
114  * We see if we can connect the previous BIOs.
115  */
117 {
118  fr_bio_packet_t *my = bio->uctx;
119 
120  fr_assert(!my->connected);
121 
122  /*
123  * Run the internal connected callback for previous BIOs. If one returns "not connected", then
124  * the packet BIO as a whole is not connected.
125  */
126  while ((bio = fr_bio_prev(bio)) != NULL) {
127  if (!((fr_bio_common_t *) bio)->priv_cb.connected) continue;
128 
129  /*
130  * Tell this BIO that everything it needs has been connected.
131  */
132  if (((fr_bio_common_t *) bio)->priv_cb.connected(bio) == 0) return;
133  }
134 
135  /*
136  * The top-level BIO is connected. This means that the entire chain is now connected, and is
137  * usable by the application.
138  */
139  my->connected = true;
140 
141  /*
142  * Stop any connection timeout.
143  */
144  if (my->ev) talloc_const_free(&my->ev);
145 
146  /*
147  * Tell the application that the packet BIO is now usable.
148  */
149  my->cb.connected(my);
150 }
151 
153 {
154  fr_bio_packet_t *my = bio->uctx;
155 
156  if (my->cb.shutdown) my->cb.shutdown(my);
157  my->cb.shutdown = NULL;
158 }
159 
160 static void fr_bio_packet_eof(fr_bio_t *bio)
161 {
162  fr_bio_packet_t *my = bio->uctx;
163 
164  if (my->cb.eof) my->cb.eof(my);
165  my->cb.eof = NULL;
166 }
167 
169 {
170  fr_bio_packet_t *my = bio->uctx;
171 
172  if (my->cb.failed) my->cb.failed(my);
173  my->cb.failed = NULL;
174 }
175 
176 
178 {
179  fr_bio_t *bio = my->bio;
180 
181  fr_bio_cb_funcs_t bio_cb = {
183  .shutdown = fr_bio_packet_shutdown,
184  .eof = fr_bio_packet_eof,
185  .failed = fr_bio_packet_failed,
186 
187  .write_blocked = fr_bio_packet_write_blocked,
188  .write_resume = fr_bio_packet_write_resume,
189  .read_blocked = fr_bio_packet_read_blocked,
190  .read_resume = fr_bio_packet_read_resume,
191  };
192 
193  /*
194  * Every participating BIO has us set as the bio->uctx, and we handle all BIO callbacks.
195  *
196  * The application sets its own pointer my->uctx and sets itself via our callbacks.
197  */
198  while (bio) {
199  bio->uctx = my;
200 
201  fr_bio_cb_set(bio, &bio_cb);
202  bio = fr_bio_next(bio);
203  }
204 }
fr_bio_callback_t connected
called when the BIO is ready to be used
Definition: base.h:88
static fr_bio_t * fr_bio_prev(fr_bio_t *bio)
Definition: base.h:121
static fr_bio_t * fr_bio_next(fr_bio_t *bio)
Definition: base.h:130
void * uctx
user ctx, caller can manually set it.
Definition: base.h:113
Definition: base.h:112
next
Definition: dcursor.h:178
fr_bio_shutdown & my
Definition: fd_errno.h:59
void fr_bio_cb_set(fr_bio_t *bio, fr_bio_cb_funcs_t const *cb)
Definition: base.c:225
void fr_bio_packet_init(fr_bio_packet_t *my)
Definition: packet.c:177
void fr_bio_packet_connected(fr_bio_t *bio)
Called when a particular BIO is connected.
Definition: packet.c:116
static void fr_bio_packet_failed(fr_bio_t *bio)
Definition: packet.c:168
static void fr_bio_packet_shutdown(fr_bio_t *bio)
Definition: packet.c:152
static void fr_bio_packet_eof(fr_bio_t *bio)
Definition: packet.c:160
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:103
static int fr_bio_packet_read_blocked(fr_bio_t *bio)
Definition: packet.c:94
static int fr_bio_packet_write_resume(fr_bio_t *bio)
Definition: packet.c:55
fr_assert(0)
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition: talloc.h:224