The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
base.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: 5dd95f1053bc436ea55b867bf4acf2efa5958108 $
19  * @file lib/bio/base.c
20  * @brief Binary IO abstractions.
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/null.h>
27 #include <freeradius-devel/util/syserror.h>
28 
29 #ifndef NDEBUG
30 /** Free this bio.
31  *
32  * The bio can only be freed if it is not in any chain.
33  */
35 {
38 
39  /*
40  * It's safe to free this bio.
41  */
42  return 0;
43 }
44 #endif
45 
46 /** Always returns EOF on fr_bio_read()
47  *
48  */
49 ssize_t fr_bio_eof_read(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void *buffer, UNUSED size_t size)
50 {
51  return fr_bio_error(EOF);
52 }
53 
54 /** Internal bio function which just reads from the "next" bio.
55  *
56  * It is mainly used when the current bio needs to modify the write
57  * path, but does not need to do anything on the read path.
58  */
59 ssize_t fr_bio_next_read(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
60 {
61  ssize_t rcode;
62  fr_bio_t *next;
63 
64  next = fr_bio_next(bio);
65  fr_assert(next != NULL);
66 
67  rcode = next->read(next, packet_ctx, buffer, size);
68  if (rcode >= 0) return rcode;
69 
70  if (rcode == fr_bio_error(IO_WOULD_BLOCK)) return rcode;
71 
74  return rcode;
75 }
76 
77 /** Internal bio function which just writes to the "next" bio.
78  *
79  * It is mainly used when the current bio needs to modify the read
80  * path, but does not need to do anything on the write path.
81  */
82 ssize_t fr_bio_next_write(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size)
83 {
84  ssize_t rcode;
85  fr_bio_t *next;
86 
87  next = fr_bio_next(bio);
88  fr_assert(next != NULL);
89 
90  rcode = next->write(next, packet_ctx, buffer, size);
91  if (rcode >= 0) return rcode;
92 
93  if (rcode == fr_bio_error(IO_WOULD_BLOCK)) return rcode;
94 
97  return rcode;
98 }
99 
100 /** Free this bio, and everything it calls.
101  *
102  * We unlink the bio chain, and then free it individually. If there's an error, the bio chain is relinked.
103  * That way the error can be addressed (somehow) and this function can be called again.
104  *
105  * Note that we do not support talloc_free() for the bio chain. Each individual bio has to be unlinked from
106  * the chain before the destructor will allow it to be freed. This functionality is by design.
107  *
108  * We want to have an API where bios are created "bottom up", so that it is impossible for an application to
109  * create an incorrect chain. However, creating the chain bottom up means that the lower bios not parented
110  * from the higher bios, and therefore talloc_free() won't free them. As a result, we need an explicit
111  * bio_free() function.
112  */
114 {
115  fr_bio_t *next = fr_bio_next(bio);
116 
117  /*
118  * We cannot free a bio in the middle of a chain. It has to be unlinked first.
119  */
120  if (fr_bio_prev(bio)) return -1;
121 
122  /*
123  * Unlink our bio, and recurse to free the next one. If we can't free it, re-chain it, but reset
124  * the read/write functions to do nothing.
125  */
126  if (next) {
127  next->entry.prev = NULL;
128  if (fr_bio_free(next) < 0) {
129  next->entry.prev = &bio->entry;
132  return -1;
133  }
134 
135  bio->entry.next = NULL;
136  }
137 
138  /*
139  * It's now safe to free this bio.
140  */
141  return talloc_free(bio);
142 }
143 
144 /** Shut down a set of BIOs
145  *
146  * Must be called from the top-most bio.
147  *
148  * Will shut down the bios from the bottom-up.
149  *
150  * The shutdown function MUST be callable multiple times without breaking.
151  */
153 {
154  fr_bio_t *last;
155 
157 
158  /*
159  * Find the last bio in the chain.
160  */
161  for (last = bio; fr_bio_next(last) != NULL; last = fr_bio_next(last)) {
162  /* nothing */
163  }
164 
165  /*
166  * Walk back up the chain, calling the shutdown functions.
167  */
168  do {
169  int rcode;
170  fr_bio_common_t *my = (fr_bio_common_t *) last;
171 
172  /*
173  * Call user shutdown before the bio shutdown.
174  */
175  if (my->cb.shutdown && ((rcode = my->cb.shutdown(last)) < 0)) return rcode;
176 
177  last = fr_bio_prev(last);
178  } while (last);
179 
180  return 0;
181 }
182 
183 /** Like fr_bio_shutdown(), but can be called by anyone in the chain.
184  *
185  */
187 {
188  fr_bio_common_t *prev;
189 
190  while ((prev = (fr_bio_common_t *) fr_bio_prev(bio)) != NULL) {
191  bio = (fr_bio_t *) prev;
192  }
193 
194  return fr_bio_shutdown(bio);
195 }
196 
197 char const *fr_bio_strerror(ssize_t error)
198 {
199  switch (error) {
200  case fr_bio_error(NONE):
201  return "";
202 
203  case fr_bio_error(IO_WOULD_BLOCK):
204  return "IO operation would block";
205 
206  case fr_bio_error(IO):
207  return fr_syserror(errno);
208 
209  case fr_bio_error(GENERIC):
210  return fr_strerror();
211 
212  case fr_bio_error(VERIFY):
213  return "Packet fails verification";
214 
215  case fr_bio_error(BUFFER_FULL):
216  return "Output buffer is full";
217 
218  case fr_bio_error(BUFFER_TOO_SMALL):
219  return "Output buffer is too small to cache the data";
220 
221  default:
222  return "<unknown>";
223  }
224 }
static int const char char buffer[256]
Definition: acutest.h:574
fr_bio_write_t _CONST write
write to the underlying bio
Definition: base.h:107
fr_bio_read_t _CONST read
read from the underlying bio
Definition: base.h:106
fr_dlist_t _CONST entry
in the linked list of multiple bios
Definition: base.h:109
static fr_bio_t * fr_bio_prev(fr_bio_t *bio)
Definition: base.h:112
static fr_bio_t * fr_bio_next(fr_bio_t *bio)
Definition: base.h:121
#define fr_bio_error(_x)
Definition: base.h:184
Definition: base.h:103
#define UNUSED
Definition: build.h:313
fr_dlist_t * next
Definition: dlist.h:43
fr_dlist_t * prev
Definition: dlist.h:42
int fr_bio_free(fr_bio_t *bio)
Free this bio, and everything it calls.
Definition: base.c:113
ssize_t fr_bio_eof_read(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void *buffer, UNUSED size_t size)
Always returns EOF on fr_bio_read()
Definition: base.c:49
int fr_bio_shutdown_intermediate(fr_bio_t *bio)
Like fr_bio_shutdown(), but can be called by anyone in the chain.
Definition: base.c:186
char const * fr_bio_strerror(ssize_t error)
Definition: base.c:197
int fr_bio_destructor(fr_bio_t *bio)
Free this bio.
Definition: base.c:34
ssize_t fr_bio_next_read(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
Internal bio function which just reads from the "next" bio.
Definition: base.c:59
ssize_t fr_bio_next_write(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size)
Internal bio function which just writes to the "next" bio.
Definition: base.c:82
int fr_bio_shutdown(fr_bio_t *bio)
Shut down a set of BIOs.
Definition: base.c:152
talloc_free(reap)
long int ssize_t
Definition: merged_model.c:24
ssize_t fr_bio_null_write(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void const *buffer, UNUSED size_t size)
Always return 0 on write.
Definition: null.c:39
static fr_bio_t * bio
Definition: radclient-ng.c:86
fr_assert(0)
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: syserror.c:243
#define VERIFY(_x)
Definition: trie.c:130
char const * fr_strerror(void)
Get the last library error.
Definition: strerror.c:554