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  */
118 ssize_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  */
159 ssize_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  */
199 off_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  */
257 ssize_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  */
301 ssize_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  */
325 ssize_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 }
ssize_t qio_printf(int fd, int timeoutms, const char *format,...)
Formatted output to a file descriptor.
Definition: qio.c:325
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
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
off_t qio_send(int outfd, int infd, off_t nbytes, int timeoutms)
Transfer data between file descriptors.
Definition: qio.c:199
ssize_t qio_read(int fd, void *buf, size_t nbytes, int timeoutms)
Read from a file descriptor.
Definition: qio.c:118
int qio_wait_writable(int fd, int timeoutms)
Test & wait until the file descriptor is ready for writing.
Definition: qio.c:87
ssize_t qio_write(int fd, const void *buf, size_t nbytes, int timeoutms)
Write to a file descriptor.
Definition: qio.c:159
int qio_wait_readable(int fd, int timeoutms)
Test & wait until the file descriptor has readable data.
Definition: qio.c:59