The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
conduit.c
Go to the documentation of this file.
1/*
2 * This program 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
5 * (at 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: c53a909e894457a53ca9bbc1d177f4e996a82d04 $
19 *
20 * @file conduit.c
21 * @brief Channels for communicating with radmin
22 *
23 * @copyright 2015 The FreeRADIUS server project
24 * @copyright 2015 Alan DeKok (aland@deployingradius.com)
25 */
26RCSID("$Id: c53a909e894457a53ca9bbc1d177f4e996a82d04 $")
27
28#include <freeradius-devel/util/strerror.h>
29#include <stdlib.h>
30#include <stdbool.h>
31#include <unistd.h>
32#include <errno.h>
33#include "conduit.h"
34
35static ssize_t lo_read(int fd, void *out, size_t outlen)
36{
37 size_t total;
38 ssize_t r;
39 uint8_t *p = out;
40
41 for (total = 0; total < outlen; ) {
42 /* coverity[overflow_sink] */
43 r = read(fd, p + total, outlen - total);
44
45 /* coverity[return_overflow] */
46 if (r == 0) return total;
47
48 if (r < 0) {
49 switch (errno) {
50 case EINTR:
51 continue;
52
53#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
54 case EWOULDBLOCK:
55#endif
56 case EAGAIN:
57 return total;
58
59 default:
60 break;
61 }
62
63 return -1;
64 }
65 total += r;
66 }
67
68 return total;
69}
70
71
72/*
73 * A non-blocking copy of fr_conduit_read().
74 */
76 void *out, size_t outlen, size_t *leftover, bool *want_more)
77{
78 ssize_t r;
79 size_t data_len;
82 size_t offset = *leftover;
83
84 /*
85 * If we can't even read a header, die.
86 */
87 if (outlen <= sizeof(hdr)) {
88 errno = EINVAL;
89 return -1;
90 }
91
92 *want_more = true;
93
94 /*
95 * Ensure that we read the header first.
96 */
97 if (offset < sizeof(hdr)) {
98 r = lo_read(fd, buffer + offset, sizeof(hdr) - offset);
99 if (r <= 0) return r;
100
101 *leftover += r;
102 offset += r;
103
104 /*
105 * We have leftover data, but no *packet* to
106 * return.
107 */
108 if (offset < sizeof(hdr)) return 0;
109 }
110
111 /*
112 * We've read the header. Figure out how much more data
113 * we need to read.
114 */
115 memcpy(&hdr, buffer, sizeof(hdr));
116 data_len = ntohl(hdr.length);
117
118 /*
119 * The data will overflow the buffer. Die.
120 */
121 if ((sizeof(hdr) + data_len) > outlen) {
122 errno = EINVAL;
123 return -1;
124 }
125
126 /*
127 * This is how much we really want.
128 */
129 outlen = sizeof(hdr) + data_len;
130
131 r = lo_read(fd, buffer + offset, outlen - offset);
132 if (r <= 0) return r;
133
134 offset += r;
135
136 if (offset == outlen) {
137 *want_more = false;
138 *pconduit = ntohs(hdr.conduit);
139 return outlen;
140 }
141
142 *leftover = offset;
143 return 0;
144}
145
146ssize_t fr_conduit_read(int fd, fr_conduit_type_t *pconduit, void *out, size_t outlen)
147{
148 ssize_t r;
149 size_t data_len;
150 uint8_t *buffer = out;
152
153 /*
154 * Read the header
155 */
156 r = lo_read(fd, &hdr, sizeof(hdr));
157 if (r <= 0) return r;
158
159 /*
160 * Read the data into the buffer.
161 */
162 *pconduit = ntohs(hdr.conduit);
163 data_len = ntohl(hdr.length);
164 if (data_len == 0) return 0;
165 if (data_len > UINT32_MAX) data_len = UINT32_MAX; /* For Coverity */
166
167#if 0
168 fprintf(stderr, "CONDUIT R %zu length %zu\n", *pconduit, data_len);
169#endif
170
171 /*
172 * Shrink the output buffer to the size of the data we
173 * have.
174 */
175 if (outlen > data_len) outlen = data_len;
176
177 r = lo_read(fd, buffer, outlen);
178 if (r <= 0) return r;
179
180 /*
181 * Read and discard any extra data sent to us. Sorry,
182 * caller, you should have used a larger buffer!
183 */
184 while (data_len > outlen) {
185 size_t discard;
186 uint8_t junk[64];
187
188 discard = data_len - outlen;
189 if (discard > sizeof(junk)) discard = sizeof(junk);
190
191 r = lo_read(fd, junk, discard);
192 if (r <= 0) break;
193
194 data_len -= r;
195 }
196
197 return outlen;
198}
199
200static ssize_t lo_write(int fd, void const *out, size_t outlen)
201{
202 size_t total;
203 ssize_t r;
204 uint8_t const *buffer = out;
205
206 total = outlen;
207
208 while (total > 0) {
209 r = write(fd, buffer, total);
210 if (r == 0) {
211 errno = EAGAIN;
212 return -1;
213 }
214
215 if (r < 0) {
216 if (errno == EINTR) continue;
217
218 return -1;
219 }
220
221 buffer += r;
222 total -= r;
223 }
224
225 return outlen;
226}
227
228ssize_t fr_conduit_write(int fd, fr_conduit_type_t conduit, void const *out, size_t outlen)
229{
230 ssize_t r;
232 uint8_t const *buffer = out;
233
234 if (outlen > UINT32_MAX) {
235 fr_strerror_printf("Data to write to conduit (%zu bytes) exceeds maximum length", outlen);
236 return -1;
237 }
238
239 /*
240 * Asked to write nothing, suppress it.
241 */
242 if (!outlen) return 0;
243
244 hdr = (fr_conduit_hdr_t) {
245 .conduit = htons(conduit),
246 .length = htonl(outlen),
247 };
248
249#if 0
250 fprintf(stderr, "CONDUIT W %zu length %zu\n", conduit, outlen);
251#endif
252
253 /*
254 * write the header
255 */
256 r = lo_write(fd, &hdr, sizeof(hdr));
257 if (r <= 0) return r;
258
259 /*
260 * write the data directly from the buffer
261 */
262 r = lo_write(fd, buffer, outlen);
263 if (r <= 0) return r;
264
265 return outlen;
266}
static int const char char buffer[256]
Definition acutest.h:576
#define RCSID(id)
Definition build.h:483
static ssize_t lo_write(int fd, void const *out, size_t outlen)
Definition conduit.c:200
ssize_t fr_conduit_write(int fd, fr_conduit_type_t conduit, void const *out, size_t outlen)
Definition conduit.c:228
static ssize_t lo_read(int fd, void *out, size_t outlen)
Definition conduit.c:35
ssize_t fr_conduit_read_async(int fd, fr_conduit_type_t *pconduit, void *out, size_t outlen, size_t *leftover, bool *want_more)
Definition conduit.c:75
ssize_t fr_conduit_read(int fd, fr_conduit_type_t *pconduit, void *out, size_t outlen)
Definition conduit.c:146
API to provide distinct communication conduits for the radmin protocol.
uint16_t conduit
Definition conduit.h:77
uint32_t length
Definition conduit.h:78
fr_conduit_type_t
Definition conduit.h:34
long int ssize_t
unsigned char uint8_t
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
static size_t char ** out
Definition value.h:997