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.0KB

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