All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
channel.c
Go to the documentation of this file.
1 /*
2  * radmin.c RADIUS Administration tool.
3  *
4  * Version: $Id: 757ccd24897015159c05f2cfbe4cd4236e01a18e $
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2015 The FreeRADIUS server project
21  * Copyright 2015 Alan DeKok <aland@deployingradius.com>
22  */
23 
24 RCSID("$Id: 757ccd24897015159c05f2cfbe4cd4236e01a18e $")
25 
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/channel.h>
28 
29 typedef struct rchannel_t {
30  uint32_t channel;
31  uint32_t length;
32 } rchannel_t;
33 
34 
35 static ssize_t lo_read(int fd, void *inbuf, size_t buflen)
36 {
37  size_t total;
38  ssize_t r;
39  uint8_t *p = inbuf;
40 
41  for (total = 0; total < buflen; total += r) {
42  r = read(fd, p + total, buflen - total);
43 
44  if (r == 0) return 0;
45 
46  if (r < 0) {
47  if (errno == EINTR) continue;
48 
49  return -1;
50 
51  }
52  }
53 
54  return total;
55 }
56 
57 
58 /*
59  * A non-blocking copy of fr_channel_read().
60  */
61 ssize_t fr_channel_drain(int fd, fr_channel_type_t *pchannel, void *inbuf, size_t buflen, uint8_t **outbuf, size_t have_read)
62 {
63  ssize_t r;
64  size_t data_len;
65  uint8_t *buffer = inbuf;
66  rchannel_t hdr;
67 
68  /*
69  * If we can't even read a header, die.
70  */
71  if (buflen <= sizeof(hdr)) {
72  errno = EINVAL;
73  return -1;
74  }
75 
76  /*
77  * Ensure that we read the header first.
78  */
79  if (have_read < sizeof(hdr)) {
80  *pchannel = FR_CHANNEL_WANT_MORE;
81 
82  r = lo_read(fd, buffer + have_read, sizeof(hdr) - have_read);
83  if (r <= 0) return r;
84 
85  have_read += r;
86 
87  if (have_read < sizeof(hdr)) return have_read;
88  }
89 
90  /*
91  * We've read the header. Figure out how much more data
92  * we need to read.
93  */
94  memcpy(&hdr, buffer, sizeof(hdr));
95  data_len = ntohl(hdr.length);
96 
97  /*
98  * The data will overflow the buffer. Die.
99  */
100  if ((sizeof(hdr) + data_len) > buflen) {
101  errno = EINVAL;
102  return -1;
103  }
104 
105  /*
106  * This is how much we really want.
107  */
108  buflen = sizeof(hdr) + data_len;
109 
110  r = lo_read(fd, buffer + have_read, buflen - have_read);
111  if (r <= 0) return r;
112 
113  have_read += r;
114 
115  if (have_read == buflen) {
116  *pchannel = ntohl(hdr.channel);
117  *outbuf = buffer + sizeof(hdr);
118  return data_len;
119  }
120 
121  *pchannel = FR_CHANNEL_WANT_MORE;
122  return have_read;
123 }
124 
125 ssize_t fr_channel_read(int fd, fr_channel_type_t *pchannel, void *inbuf, size_t buflen)
126 {
127  ssize_t r;
128  size_t data_len;
129  uint8_t *buffer = inbuf;
130  rchannel_t hdr;
131 
132  /*
133  * Read the header
134  */
135  r = lo_read(fd, &hdr, sizeof(hdr));
136  if (r <= 0) return r;
137 
138  /*
139  * Read the data into the buffer.
140  */
141  *pchannel = ntohl(hdr.channel);
142  data_len = ntohl(hdr.length);
143 
144 #if 0
145  fprintf(stderr, "CHANNEL R %zu length %zu\n", *pchannel, data_len);
146 #endif
147 
148  /*
149  * Shrink the output buffer to the size of the data we
150  * have.
151  */
152  if (buflen > data_len) buflen = data_len;
153 
154  r = lo_read(fd, buffer, buflen);
155  if (r <= 0) return r;
156 
157  /*
158  * Read and discard any extra data sent to us. Sorry,
159  * caller, you should have used a larger buffer!
160  */
161  while (data_len > buflen) {
162  size_t discard;
163  uint8_t junk[64];
164 
165  discard = data_len - buflen;
166  if (discard > sizeof(junk)) discard = sizeof(junk);
167 
168  r = lo_read(fd, junk, discard);
169  if (r <= 0) break;
170 
171  data_len -= r;
172  }
173 
174  return buflen;
175 }
176 
177 static ssize_t lo_write(int fd, void const *inbuf, size_t buflen)
178 {
179  size_t total;
180  ssize_t r;
181  uint8_t const *buffer = inbuf;
182 
183  total = buflen;
184 
185  while (total > 0) {
186  r = write(fd, buffer, total);
187  if (r == 0) {
188  errno = EAGAIN;
189  return -1;
190  }
191 
192  if (r < 0) {
193  if (errno == EINTR) continue;
194 
195  return -1;
196  }
197 
198  buffer += r;
199  total -= r;
200  }
201 
202  return buflen;
203 }
204 
205 ssize_t fr_channel_write(int fd, fr_channel_type_t channel, void const *inbuf, size_t buflen)
206 {
207  ssize_t r;
208  rchannel_t hdr;
209  uint8_t const *buffer = inbuf;
210 
211  hdr.channel = htonl(channel);
212  hdr.length = htonl(buflen);
213 
214 #if 0
215  fprintf(stderr, "CHANNEL W %zu length %zu\n", channel, buflen);
216 #endif
217 
218  /*
219  * write the header
220  */
221  r = lo_write(fd, &hdr, sizeof(hdr));
222  if (r <= 0) return r;
223 
224  /*
225  * write the data directly from the buffer
226  */
227  r = lo_write(fd, buffer, buflen);
228  if (r <= 0) return r;
229 
230  return buflen;
231 }
ssize_t fr_channel_read(int fd, fr_channel_type_t *pchannel, void *inbuf, size_t buflen)
Definition: channel.c:125
fr_channel_type_t
Definition: channel.h:32
static ssize_t lo_read(int fd, void *inbuf, size_t buflen)
Definition: channel.c:35
static ssize_t lo_write(int fd, void const *inbuf, size_t buflen)
Definition: channel.c:177
uint32_t channel
Definition: channel.c:30
uint32_t length
Definition: channel.c:31
ssize_t fr_channel_write(int fd, fr_channel_type_t channel, void const *inbuf, size_t buflen)
Definition: channel.c:205
struct rchannel_t rchannel_t
#define RCSID(id)
Definition: build.h:135
static int r
Definition: rbmonkey.c:66
ssize_t fr_channel_drain(int fd, fr_channel_type_t *pchannel, void *inbuf, size_t buflen, uint8_t **outbuf, size_t have_read)
Definition: channel.c:61