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

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