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 5.9KB

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