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