The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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  */
26 RCSID("$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 
35 static 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;
80  uint8_t *buffer = out;
81  fr_conduit_hdr_t hdr;
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 
146 ssize_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;
151  fr_conduit_hdr_t hdr;
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 
200 static 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 
228 ssize_t fr_conduit_write(int fd, fr_conduit_type_t conduit, void const *out, size_t outlen)
229 {
230  ssize_t r;
231  fr_conduit_hdr_t hdr;
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:574
#define RCSID(id)
Definition: build.h:481
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
Definition: merged_model.c:24
unsigned char uint8_t
Definition: merged_model.c:30
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
static size_t char ** out
Definition: value.h:997