The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
pipe.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: f8df91302ef3a8f0f6abb039a8da544e3b46e3b7 $
19 * @file lib/bio/pipe.c
20 * @brief BIO abstractions for in-memory pipes
21 *
22 * @copyright 2024 Network RADIUS SAS (legal@networkradius.com)
23 */
24#include <freeradius-devel/bio/bio_priv.h>
25#include <freeradius-devel/bio/null.h>
26#include <freeradius-devel/bio/mem.h>
27
28#include <freeradius-devel/bio/pipe.h>
29
30#include <pthread.h>
31
32/** The pipe bio
33 *
34 */
35typedef struct {
37
39
40 bool eof; //!< are we at EOF?
41
42 fr_bio_pipe_cb_funcs_t signal; //!< inform us that the pipe is readable
43
46
47
49{
51
52 pthread_mutex_destroy(&my->mutex);
53
54 return 0;
55}
56
57/** Read from the pipe.
58 *
59 * Once EOF is set, any pending data is read, and then EOF is returned.
60 */
61static ssize_t fr_bio_pipe_read(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
62{
63 ssize_t rcode;
64 fr_bio_pipe_t *my = talloc_get_type_abort(bio, fr_bio_pipe_t);
65
66 fr_assert(my->next != NULL);
67
68 pthread_mutex_lock(&my->mutex);
69 rcode = my->next->read(my->next, packet_ctx, buffer, size);
70 if ((rcode == 0) && my->eof) {
71 pthread_mutex_unlock(&my->mutex);
72
73 /*
74 * Don't call our EOF function. But do tell the other BIOs that we're at EOF.
75 */
76 my->priv_cb.eof = NULL;
77 fr_bio_eof(bio);
78 return 0;
79
80 } else if (rcode > 0) {
81 /*
82 * There is room to write more data.
83 *
84 * @todo - only signal when we transition from BLOCKED to unblocked.
85 */
86 my->signal.writeable(&my->bio);
87 }
88 pthread_mutex_unlock(&my->mutex);
89
90 return rcode;
91}
92
93
94/** Write to the pipe.
95 *
96 * Once EOF is set, no further writes are possible.
97 */
98static ssize_t fr_bio_pipe_write(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size)
99{
100 ssize_t rcode;
101 fr_bio_pipe_t *my = talloc_get_type_abort(bio, fr_bio_pipe_t);
102
103 fr_assert(my->next != NULL);
104
105 pthread_mutex_lock(&my->mutex);
106 if (!my->eof) {
107 rcode = my->next->write(my->next, packet_ctx, buffer, size);
108
109 /*
110 * There is more data to read.
111 *
112 * @todo - only signal when we transition from no data to data.
113 */
114 if (rcode > 0) {
115 my->signal.readable(&my->bio);
116 }
117
118 } else {
119 rcode = 0;
120 }
121 pthread_mutex_unlock(&my->mutex);
122
123 return rcode;
124}
125
126/** Shutdown callback.
127 *
128 */
130{
131 int rcode;
132 fr_bio_pipe_t *my = talloc_get_type_abort(bio, fr_bio_pipe_t);
133
134 fr_assert(my->next != NULL);
135
136 pthread_mutex_lock(&my->mutex);
137 rcode = fr_bio_shutdown(my->next);
138 pthread_mutex_unlock(&my->mutex);
139
140 return rcode;
141}
142
143/** Set EOF.
144 *
145 * Either side can set EOF, in which case pending reads are still processed. Writes return EOF immediately.
146 * Readers return pending data, and then EOF.
147 */
148static int fr_bio_pipe_eof(fr_bio_t *bio)
149{
150 fr_bio_pipe_t *my = talloc_get_type_abort(bio, fr_bio_pipe_t);
151
152 pthread_mutex_lock(&my->mutex);
153 my->eof = true;
154 pthread_mutex_unlock(&my->mutex);
155
156 /*
157 * We don't know if the other end is at EOF, we have to do a read. So we tell fr_bio_eof() to
158 * stop processing.
159 */
160 return 0;
161}
162
163/** Allocate a thread-safe pipe which can be used for both reads and writes.
164 *
165 * Due to talloc issues with multiple threads, if the caller wants a bi-directional pipe, this function will
166 * need to be called twice. That way a free in each context won't result in a race condition on two mutex
167 * locks.
168 *
169 * For now, iqt's too difficult to emulate the pipe[2] behavior, where two identical "connected" things are
170 * returned, and either can be used for reading or for writing.
171 *
172 * i.e. a pipe is really a mutex-protected memory buffer. One side should call write (and never read). The
173 * other side should call read (and never write).
174 *
175 * The pipe should be freed only after both ends have set EOF.
176 */
177fr_bio_t *fr_bio_pipe_alloc(TALLOC_CTX *ctx, fr_bio_pipe_cb_funcs_t *cb, size_t buffer_size)
178{
180
181 if (!cb->readable || !cb->writeable) return NULL;
182
183 if (buffer_size < 1024) buffer_size = 1024;
184 if (buffer_size > (1 << 20)) buffer_size = (1 << 20);
185
186 my = talloc_zero(ctx, fr_bio_pipe_t);
187 if (!my) return NULL;
188
189 my->next = fr_bio_mem_sink_alloc(my, buffer_size);
190 if (!my->next) {
192 return NULL;
193 }
194
195 my->signal = *cb;
196
197 pthread_mutex_init(&my->mutex, NULL);
198
199 my->bio.read = fr_bio_pipe_read;
200 my->bio.write = fr_bio_pipe_write;
201 my->cb.shutdown = fr_bio_pipe_shutdown;
202 my->priv_cb.eof = fr_bio_pipe_eof;
203
204 talloc_set_destructor(my, fr_bio_pipe_destructor);
205 return (fr_bio_t *) my;
206}
static int const char char buffer[256]
Definition acutest.h:576
#define FR_BIO_DESTRUCTOR_COMMON
Define a common destructor pattern.
Definition bio_priv.h:64
void fr_bio_shutdown & my
Definition fd_errno.h:70
void fr_bio_eof(fr_bio_t *bio)
Internal BIO function to run EOF callbacks.
Definition base.c:212
int fr_bio_shutdown(fr_bio_t *bio)
Shut down a set of BIOs.
Definition base.c:98
fr_bio_t * fr_bio_mem_sink_alloc(TALLOC_CTX *ctx, size_t read_size)
Allocate a memory buffer which sinks data from a bio system into the callers application.
Definition mem.c:865
talloc_free(reap)
long int ssize_t
static int fr_bio_pipe_eof(fr_bio_t *bio)
Set EOF.
Definition pipe.c:148
static ssize_t fr_bio_pipe_read(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
Read from the pipe.
Definition pipe.c:61
fr_bio_t * fr_bio_pipe_alloc(TALLOC_CTX *ctx, fr_bio_pipe_cb_funcs_t *cb, size_t buffer_size)
Allocate a thread-safe pipe which can be used for both reads and writes.
Definition pipe.c:177
bool eof
are we at EOF?
Definition pipe.c:40
static int fr_bio_pipe_shutdown(fr_bio_t *bio)
Shutdown callback.
Definition pipe.c:129
fr_bio_pipe_cb_funcs_t signal
inform us that the pipe is readable
Definition pipe.c:42
pthread_mutex_t mutex
Definition pipe.c:44
static ssize_t fr_bio_pipe_write(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size)
Write to the pipe.
Definition pipe.c:98
fr_bio_t * next
Definition pipe.c:38
static int fr_bio_pipe_destructor(fr_bio_pipe_t *my)
Definition pipe.c:48
The pipe bio.
Definition pipe.c:35
fr_bio_callback_t writeable
Definition pipe.h:29
fr_bio_callback_t readable
Definition pipe.h:28
#define fr_assert(_expr)
Definition rad_assert.h:38