qLibc

qio.c
Go to the documentation of this file.
1/******************************************************************************
2 * qLibc
3 *
4 * Copyright (c) 2010-2015 Seungyoung Kim.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 *****************************************************************************/
28
29/**
30 * @file qio.c I/O handling APIs.
31 */
32
33#include <stdio.h>
34#include <stdlib.h>
35#include <stdbool.h>
36#include <stdarg.h>
37#include <string.h>
38#include <unistd.h>
39#include <poll.h>
40#include <errno.h>
41#include "qinternal.h"
42#include "utilities/qio.h"
43
44#define MAX_IOSEND_SIZE (32 * 1024)
45
46/**
47 * Test & wait until the file descriptor has readable data.
48 *
49 * @param fd file descriptor
50 * @param timeoutms wait timeout milliseconds. 0 for no wait,
51 * -1 for infinite wait
52 *
53 * @return 1 if readable, 0 on timeout, -1 if an error occurred.
54 *
55 * @note
56 * The argument timeoutms can be used to set maximum wait time for a socket
57 * descriptor.
58 */
59 int qio_wait_readable(int fd, int timeoutms) {
60 struct pollfd fds[1];
61
62 fds[0].fd = fd;
63 fds[0].events = POLLIN;
64
65 int pollret = poll(fds, 1, timeoutms);
66 if (pollret == 0) {
67 errno = ETIMEDOUT;
68 return 0;
69 } else if (pollret < 0) {
70 return -1;
71 }
72
73 if (fds[0].revents & POLLIN)
74 return 1;
75 return -1;
76}
77
78/**
79 * Test & wait until the file descriptor is ready for writing.
80 *
81 * @param fd file descriptor
82 * @param timeoutms wait timeout milliseconds. 0 for no wait,
83 * -1 for infinite wait
84 *
85 * @return 1 if writable, 0 on timeout, -1 if an error occurred.
86 */
87 int qio_wait_writable(int fd, int timeoutms) {
88 struct pollfd fds[1];
89
90 fds[0].fd = fd;
91 fds[0].events = POLLOUT;
92
93 int pollret = poll(fds, 1, timeoutms);
94 if (pollret == 0) {
95 errno = ETIMEDOUT;
96 return 0;
97 } else if (pollret < 0) {
98 return -1;
99 }
100
101 if (fds[0].revents & POLLOUT)
102 return 1;
103 return -1;
104}
105
106/**
107 * Read from a file descriptor.
108 *
109 * @param fd file descriptor
110 * @param buf data buffer pointer to write to
111 * @param nbytes the number of bytes to read from file descriptor & write
112 * into buffer
113 * @param timeoutms wait timeout milliseconds. 0 for no wait, -1 for infinite
114 * wait
115 *
116 * @return the number of bytes read if successful, 0 on timeout, -1 for error.
117 */
118ssize_t qio_read(int fd, void *buf, size_t nbytes, int timeoutms) {
119 if (nbytes == 0)
120 return 0;
121
122 ssize_t total = 0;
123 while (total < nbytes) {
124 if (timeoutms >= 0 && qio_wait_readable(fd, timeoutms) <= 0)
125 break;
126
127 ssize_t rsize = read(fd, buf + total, nbytes - total);
128 if (rsize <= 0) {
129 if (errno == EAGAIN || errno == EINPROGRESS) {
130 // possible with non-block io
131 usleep(1);
132 continue;
133 }
134 break;
135 }
136 total += rsize;
137 }
138
139 if (total > 0)
140 return total;
141 else if (errno == ETIMEDOUT)
142 return 0;
143 return -1;
144}
145
146/**
147 * Write to a file descriptor.
148 *
149 * @param fd file descriptor
150 * @param buf data buffer pointer to read from
151 * @param nbytes the number of bytes to write to file descriptor & read
152 * from buffer
153 * @param timeoutms wait timeout milliseconds. 0 for no wait, -1 for infinite
154 * wait
155 *
156 * @return the number of bytes written if successful, 0 on timeout,
157 * -1 for error.
158 */
159ssize_t qio_write(int fd, const void *buf, size_t nbytes, int timeoutms) {
160 if (nbytes == 0)
161 return 0;
162
163 ssize_t total = 0;
164 while (total < nbytes) {
165 if (timeoutms >= 0 && qio_wait_writable(fd, timeoutms) <= 0)
166 break;
167 ssize_t wsize = write(fd, buf + total, nbytes - total);
168 if (wsize <= 0) {
169 if (errno == EAGAIN || errno == EINPROGRESS) {
170 // possible with non-block io
171 usleep(1);
172 continue;
173 }
174 break;
175 }
176 total += wsize;
177 }
178
179 if (total > 0)
180 return total;
181 else if (errno == ETIMEDOUT)
182 return 0;
183 return -1;
184}
185
186/**
187 * Transfer data between file descriptors
188 *
189 * @param outfd output file descriptor
190 * @param infd input file descriptor
191 * @param nbytes the number of bytes to copy between file descriptors.
192 * 0 means transfer until end of infd.
193 * @param timeoutms wait timeout milliseconds. 0 for no wait, -1 for infinite
194 * wait
195 *
196 * @return the number of bytes transferred if successful, 0 on timeout,
197 * -1 for error.
198 */
199off_t qio_send(int outfd, int infd, off_t nbytes, int timeoutms) {
200 if (nbytes == 0)
201 return 0;
202
203 unsigned char buf[MAX_IOSEND_SIZE];
204
205 off_t total = 0; // total size sent
206 while (total < nbytes) {
207 size_t chunksize; // this time sending size
208 if (nbytes - total <= sizeof(buf))
209 chunksize = nbytes - total;
210 else
211 chunksize = sizeof(buf);
212
213 // read
214 ssize_t rsize = qio_read(infd, buf, chunksize, timeoutms);
215 DEBUG("read %zd", rsize);
216 if (rsize <= 0)
217 break;
218
219 // write
220 ssize_t wsize = qio_write(outfd, buf, rsize, timeoutms);
221 DEBUG("write %zd", wsize);
222 if (wsize <= 0)
223 break;
224
225 total += wsize;
226 if (rsize != wsize) {
227 DEBUG("size mismatch. read:%zd, write:%zd", rsize, wsize);
228 break;
229 }
230 }
231
232 if (total > 0)
233 return total;
234 else if (errno == ETIMEDOUT)
235 return 0;
236 return -1;
237}
238
239/**
240 * Read a line from a file descriptor into the buffer pointed to until either a
241 * terminating newline or EOF. New-line characters(CR, LF ) will not be stored
242 * into buffer.
243 *
244 * @param fd file descriptor
245 * @param buf data buffer pointer
246 * @param bufsize buffer size
247 * @param timeoutms wait timeout milliseconds. 0 for no wait, -1 for infinite
248 * wait
249 *
250 * @return the number of bytes read if successful, 0 on timeout, -1 for error.
251 *
252 * @note
253 * Be sure the return value does not mean the length of actual stored data.
254 * It means how many bytes are readed from the file descriptor,
255 * so the new-line characters will be counted, but not be stored.
256 */
257ssize_t qio_gets(int fd, char *buf, size_t bufsize, int timeoutms) {
258 if (bufsize <= 1)
259 return -1;
260
261 ssize_t readcnt = 0;
262 char *ptr;
263 for (ptr = buf; readcnt < (bufsize - 1); ptr++) {
264 ssize_t rsize = qio_read(fd, ptr, 1, timeoutms);
265 if (rsize != 1) {
266 if (errno == EAGAIN || errno == EINPROGRESS) {
267 // possible with non-block io
268 usleep(1);
269 continue;
270 }
271 break;
272 }
273
274 readcnt++;
275 if (*ptr == '\r')
276 ptr--;
277 else if (*ptr == '\n')
278 break;
279 }
280
281 *ptr = '\0';
282
283 if (readcnt > 0)
284 return readcnt;
285 else if (errno == ETIMEDOUT)
286 return 0;
287 return -1;
288}
289
290/**
291 * Writes the string and a trailing newline to file descriptor.
292 *
293 * @param fd file descriptor
294 * @param str string pointer
295 * @param timeoutms wait timeout milliseconds. 0 for no wait, -1 for infinite
296 * wait
297 *
298 * @return the number of bytes written including trailing newline characters
299 * if successful, 0 for timeout and -1 for errors.
300 */
301ssize_t qio_puts(int fd, const char *str, int timeoutms) {
302 size_t strsize = strlen(str);
303 char *newstr = (char *) malloc(strsize + 1 + 1);
304 if (newstr == NULL)
305 return -1;
306 strncpy(newstr, str, strsize);
307 newstr[strsize] = '\n';
308 newstr[strsize + 1] = '\0';
309 ssize_t ret = qio_write(fd, newstr, strsize + 1, timeoutms);
310 free(newstr);
311 return ret;
312}
313
314/**
315 * Formatted output to a file descriptor
316 *
317 * @param fd file descriptor
318 * @param timeoutms wait timeout milliseconds. 0 for no wait, -1 for infinite
319 * wait
320 * @param format format string
321 *
322 * @return the number of bytes written including trailing newline characters
323 * if successful, 0 for timeout and -1 for errors.
324 */
325ssize_t qio_printf(int fd, int timeoutms, const char *format, ...) {
326 char *buf;
327 DYNAMIC_VSPRINTF(buf, format);
328 if (buf == NULL)
329 return -1;
330
331 ssize_t ret = qio_write(fd, buf, strlen(buf), timeoutms);
332 free(buf);
333
334 return ret;
335}
qio_write
ssize_t qio_write(int fd, const void *buf, size_t nbytes, int timeoutms)
Write to a file descriptor.
Definition qio.c:159
qio_puts
ssize_t qio_puts(int fd, const char *str, int timeoutms)
Writes the string and a trailing newline to file descriptor.
Definition qio.c:301
qio_wait_readable
int qio_wait_readable(int fd, int timeoutms)
Test & wait until the file descriptor has readable data.
Definition qio.c:59
qio_read
ssize_t qio_read(int fd, void *buf, size_t nbytes, int timeoutms)
Read from a file descriptor.
Definition qio.c:118
qio_send
off_t qio_send(int outfd, int infd, off_t nbytes, int timeoutms)
Transfer data between file descriptors.
Definition qio.c:199
qio_gets
ssize_t qio_gets(int fd, char *buf, size_t bufsize, int timeoutms)
Read a line from a file descriptor into the buffer pointed to until either a terminating newline or E...
Definition qio.c:257
qio_wait_writable
int qio_wait_writable(int fd, int timeoutms)
Test & wait until the file descriptor is ready for writing.
Definition qio.c:87
qio_printf
ssize_t qio_printf(int fd, int timeoutms, const char *format,...)
Formatted output to a file descriptor.
Definition qio.c:325