libfuncs is collection of code (list, queue, circular buffer, io, logging, etc.). https://georgi.unixsol.org/programs/libfuncs/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

io.c 6.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /*
  2. * UX IO functions
  3. * Copyright (C) 2006-2009 Unix Solutions Ltd.
  4. *
  5. * Released under MIT license.
  6. * See LICENSE-MIT.txt for license terms.
  7. */
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <stdarg.h>
  11. #include <stdbool.h>
  12. #include <unistd.h>
  13. #include <string.h>
  14. #include <netdb.h>
  15. #include <arpa/inet.h>
  16. #include <netinet/in.h>
  17. #include <netinet/tcp.h>
  18. #include <sys/utsname.h>
  19. #include <sys/socket.h>
  20. #include <sys/time.h>
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <poll.h>
  24. #include <fcntl.h>
  25. #include <errno.h>
  26. #include <time.h>
  27. #include "libfuncs.h"
  28. #include "log.h"
  29. static int io_report_errors = 1;
  30. void set_log_io_errors(int report_io_errors) {
  31. io_report_errors = report_io_errors;
  32. }
  33. char * chomp(char *x) {
  34. int i=strlen(x)-1;
  35. while ((i>=0)&&((x[i]=='\n')||(x[i]=='\r')||(x[i]==' ')||(x[i]=='\t'))){
  36. x[i--]=0;
  37. }
  38. return x;
  39. }
  40. ssize_t safe_read(int fd, void *buf, size_t len) {
  41. ssize_t readen;
  42. do {
  43. readen = read(fd, buf, len);
  44. if ((readen < 0) && (errno == EAGAIN || errno == EINTR))
  45. continue;
  46. return readen;
  47. } while (1);
  48. }
  49. ssize_t safe_write(int fd, const void *buf, size_t len) {
  50. ssize_t written;
  51. do {
  52. written = write(fd, buf, len);
  53. if ((written < 0) && (errno == EAGAIN || errno == EINTR))
  54. continue;
  55. return written;
  56. } while (1);
  57. }
  58. void shutdown_fd(int *in_fd) {
  59. if (*in_fd > -1) {
  60. shutdown(*in_fd, SHUT_RDWR);
  61. close(*in_fd);
  62. *in_fd = -1;
  63. }
  64. }
  65. ssize_t fdgetline(int fd, char *buf, size_t buf_size) {
  66. size_t i=0;
  67. int intrs = 0;
  68. int num_timeouts = 0;
  69. struct pollfd fdset[1];
  70. fdset[0].fd = fd;
  71. fdset[0].events = POLLIN;
  72. if (buf_size <= 0 || fd == -1)
  73. return 0;
  74. while (1) {
  75. int fdready = poll(fdset, 1, FDGETLINE_TIMEOUT);
  76. if (fdready == -1) {
  77. if (errno == EINTR) {
  78. if (++intrs < FDGETLINE_RETRIES)
  79. continue;
  80. else
  81. return i;
  82. }
  83. if (num_timeouts++ <= FDGETLINE_RETRIES) {
  84. continue;
  85. } else {
  86. if (io_report_errors)
  87. log_perror("fdgetline() timeout", errno);
  88. }
  89. }
  90. if (fdready == 0 || fdready == -1) { /* Timeout || error */
  91. if (num_timeouts++ <= FDGETLINE_RETRIES)
  92. continue;
  93. return 0;
  94. }
  95. if (safe_read(fd,buf+i,1)!=1) /* Try to read 1 char */
  96. break;
  97. i++;
  98. if (buf[i-1]=='\n')
  99. break;
  100. if (i==buf_size) /* End of buffer reached, get out a here */
  101. return 0;
  102. }
  103. buf[i]='\0';
  104. return i;
  105. }
  106. ssize_t fdread_ex(int fd, char *buf, size_t buf_size, int timeout, int retries, int waitfull) {
  107. ssize_t rbytes = 0;
  108. int intrs = 0;
  109. int num_timeouts = 0;
  110. struct pollfd fdset[1];
  111. fdset[0].fd = fd;
  112. fdset[0].events = POLLIN;
  113. if (buf_size <= 0 || fd == -1)
  114. return 0;
  115. while (1) {
  116. int fdready = poll(fdset, 1, timeout);
  117. if (fdready == -1 || fdready == 0) { /* Timeout || error */
  118. if (errno == EINTR) {
  119. if (++intrs < retries)
  120. continue;
  121. else
  122. return rbytes;
  123. }
  124. if (num_timeouts++ <= retries) {
  125. continue;
  126. } else {
  127. if (timeout && io_report_errors) {
  128. log_perror("fdread() timeout", errno);
  129. }
  130. return rbytes > 0 ? rbytes : -1;
  131. }
  132. }
  133. ssize_t j = safe_read(fd, buf + rbytes, buf_size - rbytes);
  134. if (j < 0) // Error reading
  135. return j;
  136. if (j == 0) { // No data, retry?
  137. if (num_timeouts++ > retries) {
  138. return rbytes;
  139. }
  140. continue;
  141. }
  142. rbytes += j;
  143. if (!waitfull)
  144. return rbytes;
  145. if (rbytes == (ssize_t)buf_size)
  146. return rbytes;
  147. }
  148. return 0;
  149. }
  150. ssize_t fdread(int fd, char *buf, size_t buf_size) {
  151. return fdread_ex(fd, buf, buf_size, FDREAD_TIMEOUT, FDREAD_RETRIES, 1);
  152. }
  153. ssize_t fdread_nowaitfull(int fd, char *buf, size_t buf_size) {
  154. return fdread_ex(fd, buf, buf_size, FDREAD_TIMEOUT, FDREAD_RETRIES, 0);
  155. }
  156. ssize_t fdwrite(int fd, char *buf, size_t buf_size) {
  157. ssize_t wbytes=0;
  158. int intrs = 0;
  159. int num_timeouts = 0;
  160. struct pollfd fdset[1];
  161. fdset[0].fd = fd;
  162. fdset[0].events = POLLOUT | POLLERR | POLLHUP | POLLNVAL | POLLRDHUP;
  163. if (buf_size <= 0 || fd == -1)
  164. return 0;
  165. while (1) {
  166. int fdready = poll(fdset, 1, FDWRITE_TIMEOUT);
  167. if (fdready == -1 || fdready == 0) { /* Timeout || error */
  168. if (errno == EINTR) {
  169. if (++intrs < FDWRITE_RETRIES)
  170. continue;
  171. else
  172. return wbytes;
  173. }
  174. if (num_timeouts++ <= FDWRITE_RETRIES) {
  175. continue;
  176. } else {
  177. if (io_report_errors)
  178. log_perror("fdwrite() timeout", errno);
  179. return wbytes > 0 ? wbytes : -1;
  180. }
  181. }
  182. if (fdready < 1 || (fdready == 1 && fdset[0].revents != POLLOUT)) /* Timeout || error */
  183. return -1;
  184. ssize_t j = safe_write(fd, buf+wbytes, buf_size-wbytes);
  185. if (j < 0) // Error writing
  186. return j;
  187. if (j == 0) { // No data, retry?
  188. if (num_timeouts++ > FDREAD_RETRIES) {
  189. return wbytes;
  190. }
  191. continue;
  192. }
  193. wbytes += j;
  194. if (wbytes == (ssize_t)buf_size)
  195. return wbytes;
  196. }
  197. return 0;
  198. }
  199. int fdputs(int fd, char *msg) {
  200. return fdwrite(fd, msg, strlen(msg));
  201. }
  202. int fdputsf(int fd, char *fmt, ...) {
  203. char msg[2048];
  204. va_list args;
  205. va_start(args, fmt);
  206. vsnprintf(msg, sizeof(msg)-1, fmt, args);
  207. va_end(args);
  208. return fdwrite(fd, msg, strlen(msg));
  209. }
  210. void set_sock_nonblock(int sockfd) {
  211. int arg = fcntl(sockfd, F_GETFL, NULL);
  212. arg |= O_NONBLOCK;
  213. fcntl(sockfd, F_SETFL, arg);
  214. }
  215. void set_sock_block(int sockfd) {
  216. int arg = fcntl(sockfd, F_GETFL, NULL);
  217. arg &= (~O_NONBLOCK);
  218. fcntl(sockfd, F_SETFL, arg);
  219. }
  220. int do_connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen, int timeout) {
  221. set_sock_nonblock(sockfd);
  222. // Trying to connect with timeout
  223. int result = connect(sockfd, serv_addr, addrlen);
  224. if (result < 0) { // Not connected
  225. if (errno != EINPROGRESS) { // Not in progress
  226. return -1;
  227. } else { // Wait a timeout ms for socket to become ready to write into
  228. struct pollfd fdset[1];
  229. fdset[0].fd = sockfd;
  230. fdset[0].events = POLLOUT | POLLERR | POLLHUP | POLLNVAL | POLLRDHUP;
  231. do {
  232. int fdready = poll(fdset, 1, timeout);
  233. if (fdready == -1 && errno == EINTR)
  234. continue;
  235. if (fdready < 1 || (fdready == 1 && fdset[0].revents != POLLOUT)) { // Timeout || error
  236. // Get socket error
  237. unsigned int err_val=0, sz = sizeof(int);
  238. getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)(&err_val), &sz);
  239. errno = err_val;
  240. if (!errno) // It can't be success, so simulate timeout
  241. errno = ENETDOWN;
  242. return -1;
  243. }
  244. break;
  245. } while (1);
  246. }
  247. }
  248. set_sock_block(sockfd);
  249. return 0;
  250. }