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