net_io.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. /** @file net.c
  2. * @brief Network related functions.
  3. */
  4. // For ppol()
  5. #define _GNU_SOURCE
  6. #include <stdlib.h>
  7. #include <unistd.h>
  8. #include <assert.h>
  9. #include <errno.h>
  10. #include <stdio.h>
  11. #include <sys/types.h>
  12. #include <sys/socket.h>
  13. #include <sys/uio.h>
  14. #include <signal.h>
  15. #include <poll.h>
  16. #include "faux/faux.h"
  17. #include "faux/time.h"
  18. #include "faux/net.h"
  19. #ifdef HAVE_PTHREAD
  20. #define setsigmask pthread_sigmask
  21. #else
  22. #define setsigmask sigprocmask
  23. #endif
  24. /** @brief Sends data to socket. Uses timeout and signal mask.
  25. *
  26. * The function acts like a pselect(). It gets timeout interval to interrupt
  27. * too long sending. It gets signal mask to atomically set it while blocking
  28. * within select()-like function. But it doesn't blocks signals before it.
  29. * User code must do it. The function can be interrupted by unblocked signal or
  30. * by timeout. Else it will send() all data given. Function can return sent
  31. * size less than required by user. It can happen due to errors.
  32. *
  33. * @param [in] fd Socket.
  34. * @param [in] buf Buffer to write.
  35. * @param [in] n Number of bytes to write.
  36. * @param [in] timeout Send timeout.
  37. * @param [in] sigmask Signal mask to set while pselect() call.
  38. * @return Number of bytes written or < 0 on error.
  39. */
  40. ssize_t faux_send(int fd, const void *buf, size_t n,
  41. const struct timespec *timeout, const sigset_t *sigmask)
  42. {
  43. size_t total_written = 0;
  44. size_t left = n;
  45. const void *data = buf;
  46. struct timespec now = {};
  47. struct timespec deadline = {};
  48. assert(fd != -1);
  49. assert(buf);
  50. if ((-1 == fd) || !buf)
  51. return -1;
  52. if (0 == n)
  53. return 0;
  54. // Calculate deadline - the time when timeout must occur.
  55. if (timeout) {
  56. faux_timespec_now(&now);
  57. faux_timespec_sum(&deadline, &now, timeout);
  58. }
  59. do {
  60. ssize_t bytes_written = 0;
  61. struct pollfd fds = {};
  62. struct timespec *poll_timeout = NULL;
  63. struct timespec to = {};
  64. int sn = 0;
  65. if (timeout) {
  66. if (faux_timespec_before_now(&deadline))
  67. break; // Timeout already occured
  68. faux_timespec_now(&now);
  69. faux_timespec_diff(&to, &deadline, &now);
  70. poll_timeout = &to;
  71. }
  72. // Handlers for poll()
  73. faux_bzero(&fds, sizeof(fds));
  74. fds.fd = fd;
  75. fds.events = POLLOUT;
  76. sn = ppoll(&fds, 1, poll_timeout, sigmask);
  77. // When kernel can't allocate some internal structures it can
  78. // return EAGAIN so retry.
  79. if ((sn < 0) && (EAGAIN == errno))
  80. continue;
  81. // All unneded signals are masked so don't process EINTR
  82. // in special way. Just break the loop
  83. if (sn < 0)
  84. break;
  85. // Timeout: break the loop. User don't want to wait any more
  86. if (0 == sn)
  87. break;
  88. // Some unknown event (not POLLOUT). So retry polling
  89. if (!(fds.revents & POLLOUT))
  90. continue;
  91. // The send() call is non-blocking but it's not obvious that
  92. // it can't return EINTR. Probably it can. Due to the fact the
  93. // call is non-blocking re-send() on any signal i.e. any EINTR.
  94. do {
  95. bytes_written = send(fd, data, left, MSG_DONTWAIT | MSG_NOSIGNAL);
  96. } while ((bytes_written < 0) && (EINTR == errno));
  97. if (bytes_written < 0)
  98. break;
  99. // Insufficient space
  100. if (0 == bytes_written)
  101. break;
  102. data += bytes_written;
  103. left = left - bytes_written;
  104. total_written += bytes_written;
  105. } while (left > 0);
  106. return total_written;
  107. }
  108. /** @brief Sends data to socket. It blocks signals and removes races.
  109. *
  110. * The function is like a faux_send() but it blocks all the signals and then
  111. * checks for "isbreak_func()" function to interrupt function call in a case
  112. * when isbreak_func() returns not-null value. See pselect() manpage for race
  113. * conditions explanation. It's needed for consistent signal handling.
  114. *
  115. * Usually signal hanler sets global volatile var to inform main programm about
  116. * event. For example it can be SIGINT to stop the programm. Programm analyzes
  117. * this var and can exit. Library function knows nothing about global vars or
  118. * signal handlers so user can create special function that returns 0 if nothing
  119. * is happened and !=0 if system call (or function in our case) must be
  120. * interrupted. So isbreak_func() is a such function. Library function will call
  121. * it to determine if it must to be interrupted due to signal. Additionally
  122. * sigmask allows only interested signals while data sending.
  123. *
  124. * @sa faux_send()
  125. * @sa pselect()
  126. * @param [in] fd Socket.
  127. * @param [in] buf Buffer to write.
  128. * @param [in] n Number of bytes to write.
  129. * @param [in] timeout Send timeout.
  130. * @param [in] sigmask Signal mask to set while pselect() call.
  131. * @param [in] isbreak_func Function returns !=0 if call must be interrupted.
  132. * @return Number of bytes written or < 0 on error.
  133. */
  134. ssize_t faux_send_block(int fd, const void *buf, size_t n,
  135. const struct timespec *timeout, const sigset_t *sigmask,
  136. int (*isbreak_func)(void))
  137. {
  138. sigset_t all_sigmask = {}; // All signals mask
  139. sigset_t orig_sigmask = {}; // Saved signal mask
  140. ssize_t bytes_num = 0;
  141. assert(fd != -1);
  142. assert(buf);
  143. if ((-1 == fd) || !buf)
  144. return -1;
  145. if (0 == n)
  146. return 0;
  147. // Block signals to prevent race conditions right before pselect()
  148. // Catch signals while pselect() only
  149. // Now blocks all signals
  150. sigfillset(&all_sigmask);
  151. setsigmask(SIG_SETMASK, &all_sigmask, &orig_sigmask);
  152. // Signal handler can set var to interrupt exchange.
  153. // Get value of this var by special callback function.
  154. if (isbreak_func && isbreak_func())
  155. return -1;
  156. bytes_num = faux_send(fd, buf, n, timeout, sigmask);
  157. setsigmask(SIG_SETMASK, &orig_sigmask, NULL);
  158. return bytes_num;
  159. }
  160. /** @brief Sends "struct iovec" data blocks to socket.
  161. *
  162. * This function is like a faux_send() function but uses scatter/gather.
  163. *
  164. * @see faux_send().
  165. * @param [in] fd Socket.
  166. * @param [in] iov Array of "struct iovec" structures.
  167. * @param [in] iovcnt Number of iov array members.
  168. * @param [in] timeout Send timeout.
  169. * @param [in] sigmask Signal mask to set while pselect() call.
  170. * @return Number of bytes written.
  171. * < total_length then insufficient space, timeout or
  172. * error (but some data were already sent).
  173. * < 0 - error.
  174. */
  175. ssize_t faux_sendv(int fd, const struct iovec *iov, int iovcnt,
  176. const struct timespec *timeout, const sigset_t *sigmask)
  177. {
  178. size_t total_written = 0;
  179. int i = 0;
  180. struct timespec now = {};
  181. struct timespec deadline = {};
  182. assert(fd != -1);
  183. if (fd == -1)
  184. return -1;
  185. if (!iov)
  186. return -1;
  187. if (iovcnt == 0)
  188. return 0;
  189. // Calculate deadline - the time when timeout must occur.
  190. if (timeout) {
  191. faux_timespec_now(&now);
  192. faux_timespec_sum(&deadline, &now, timeout);
  193. }
  194. for (i = 0; i < iovcnt; i++) {
  195. ssize_t bytes_written = 0;
  196. struct timespec *send_timeout = NULL;
  197. struct timespec to = {};
  198. if (timeout) {
  199. if (faux_timespec_before_now(&deadline))
  200. break; // Timeout already occured
  201. faux_timespec_now(&now);
  202. faux_timespec_diff(&to, &deadline, &now);
  203. send_timeout = &to;
  204. }
  205. if (iov[i].iov_len == 0)
  206. continue;
  207. bytes_written = faux_send(fd, iov[i].iov_base, iov[i].iov_len,
  208. send_timeout, sigmask);
  209. if (bytes_written < 0) { // Error
  210. if (total_written != 0)
  211. break;
  212. return -1;
  213. }
  214. if (0 == bytes_written) // Insufficient space or timeout
  215. break;
  216. total_written += bytes_written;
  217. }
  218. return total_written;
  219. }
  220. /** @brief Sends "struct iovec" data blocks to socket. It removes signal races.
  221. *
  222. * This function is like a faux_send_block() function but uses scatter/gather.
  223. *
  224. * @see faux_send_block().
  225. * @param [in] fd Socket.
  226. * @param [in] iov Array of "struct iovec" structures.
  227. * @param [in] iovcnt Number of iov array members.
  228. * @param [in] timeout Send timeout.
  229. * @param [in] sigmask Signal mask to set while pselect() call.
  230. * @param [in] isbreak_func Function returns !=0 if call must be interrupted.
  231. * @return Number of bytes written.
  232. * < total_length then insufficient space, timeout or
  233. * error (but some data were already sent).
  234. * < 0 - error.
  235. */
  236. ssize_t faux_sendv_block(int fd, const struct iovec *iov, int iovcnt,
  237. const struct timespec *timeout, const sigset_t *sigmask,
  238. int (*isbreak_func)(void))
  239. {
  240. sigset_t all_sigmask = {}; // All signals mask
  241. sigset_t orig_sigmask = {}; // Saved signal mask
  242. ssize_t bytes_num = 0;
  243. assert(fd != -1);
  244. if ((-1 == fd))
  245. return -1;
  246. if (!iov)
  247. return -1;
  248. if (iovcnt == 0)
  249. return 0;
  250. // Block signals to prevent race conditions right before pselect()
  251. // Catch signals while pselect() only
  252. // Now blocks all signals
  253. sigfillset(&all_sigmask);
  254. setsigmask(SIG_SETMASK, &all_sigmask, &orig_sigmask);
  255. // Signal handler can set var to interrupt exchange.
  256. // Get value of this var by special callback function.
  257. if (isbreak_func && isbreak_func())
  258. return -1;
  259. bytes_num = faux_sendv(fd, iov, iovcnt, timeout, sigmask);
  260. setsigmask(SIG_SETMASK, &orig_sigmask, NULL);
  261. return bytes_num;
  262. }
  263. /** @brief Receives data from the socket.
  264. *
  265. * Function has the same parameters and features like faux_send() function
  266. * but it receives data.
  267. *
  268. * @sa faux_send()
  269. */
  270. ssize_t faux_recv(int fd, void *buf, size_t n,
  271. const struct timespec *timeout, const sigset_t *sigmask)
  272. {
  273. size_t total_readed = 0;
  274. size_t left = n;
  275. void *data = buf;
  276. struct timespec now = {};
  277. struct timespec deadline = {};
  278. assert(fd != -1);
  279. assert(buf);
  280. if ((-1 == fd) || !buf)
  281. return -1;
  282. if (0 == n)
  283. return 0;
  284. // Calculate deadline - the time when timeout must occur.
  285. if (timeout) {
  286. faux_timespec_now(&now);
  287. faux_timespec_sum(&deadline, &now, timeout);
  288. }
  289. do {
  290. ssize_t bytes_readed = 0;
  291. struct pollfd fds = {};
  292. struct timespec *poll_timeout = NULL;
  293. struct timespec to = {};
  294. int sn = 0;
  295. if (timeout) {
  296. if (faux_timespec_before_now(&deadline))
  297. break; // Timeout already occured
  298. faux_timespec_now(&now);
  299. faux_timespec_diff(&to, &deadline, &now);
  300. poll_timeout = &to;
  301. }
  302. // Handlers for poll()
  303. faux_bzero(&fds, sizeof(fds));
  304. fds.fd = fd;
  305. fds.events = POLLIN;
  306. sn = ppoll(&fds, 1, poll_timeout, sigmask);
  307. // When kernel can't allocate some internal structures it can
  308. // return EAGAIN so retry.
  309. if ((sn < 0) && (EAGAIN == errno))
  310. continue;
  311. // All unneded signals are masked so don't process EINTR
  312. // in special way. Just break the loop
  313. if (sn < 0)
  314. break;
  315. // Timeout: break the loop. User don't want to wait any more
  316. if (0 == sn)
  317. break;
  318. // Some unknown event (not POLLIN). So retry polling
  319. if (!(fds.revents & POLLIN))
  320. continue;
  321. // The send() call is non-blocking but it's not obvious that
  322. // it can't return EINTR. Probably it can. Due to the fact the
  323. // call is non-blocking re-send() on any signal i.e. any EINTR.
  324. do {
  325. bytes_readed = recv(fd, data, left, MSG_DONTWAIT | MSG_NOSIGNAL);
  326. } while ((bytes_readed < 0) && (EINTR == errno));
  327. if (bytes_readed < 0)
  328. break;
  329. // EOF
  330. if (0 == bytes_readed)
  331. break;
  332. data += bytes_readed;
  333. left = left - bytes_readed;
  334. total_readed += bytes_readed;
  335. } while (left > 0);
  336. return total_readed;
  337. }
  338. /** @brief Receives data from the socket. It removes signal races.
  339. *
  340. * Function has the same parameters and features like faux_send_block() function
  341. * but it receives data.
  342. *
  343. * @sa faux_send_block()
  344. */
  345. ssize_t faux_recv_block(int fd, void *buf, size_t n,
  346. const struct timespec *timeout, const sigset_t *sigmask,
  347. int (*isbreak_func)(void))
  348. {
  349. sigset_t all_sigmask = {}; // All signals mask
  350. sigset_t orig_sigmask = {}; // Saved signal mask
  351. ssize_t bytes_num = 0;
  352. assert(fd != -1);
  353. assert(buf);
  354. if ((-1 == fd) || !buf)
  355. return -1;
  356. if (0 == n)
  357. return 0;
  358. // Block signals to prevent race conditions right before pselect()
  359. // Catch signals while pselect() only
  360. // Now blocks all signals
  361. sigfillset(&all_sigmask);
  362. setsigmask(SIG_SETMASK, &all_sigmask, &orig_sigmask);
  363. // Signal handler can set var to interrupt exchange.
  364. // Get value of this var by special callback function.
  365. if (isbreak_func && isbreak_func())
  366. return -1;
  367. bytes_num = faux_recv(fd, buf, n, timeout, sigmask);
  368. setsigmask(SIG_SETMASK, &orig_sigmask, NULL);
  369. return bytes_num;
  370. }
  371. /** @brief Receives data from the socket. Uses scatter/gather.
  372. *
  373. * Function has the same parameters and features like faux_sendv() function
  374. * but it receives data.
  375. *
  376. * @sa faux_sendv()
  377. */
  378. ssize_t faux_recvv(int fd, struct iovec *iov, int iovcnt,
  379. const struct timespec *timeout, const sigset_t *sigmask)
  380. {
  381. size_t total_readed = 0;
  382. int i = 0;
  383. struct timespec now = {};
  384. struct timespec deadline = {};
  385. assert(fd != -1);
  386. if (fd == -1)
  387. return -1;
  388. if (!iov)
  389. return -1;
  390. if (iovcnt == 0)
  391. return 0;
  392. // Calculate deadline - the time when timeout must occur.
  393. if (timeout) {
  394. faux_timespec_now(&now);
  395. faux_timespec_sum(&deadline, &now, timeout);
  396. }
  397. for (i = 0; i < iovcnt; i++) {
  398. ssize_t bytes_readed = 0;
  399. struct timespec *recv_timeout = NULL;
  400. struct timespec to = {};
  401. if (timeout) {
  402. if (faux_timespec_before_now(&deadline))
  403. break; // Timeout already occured
  404. faux_timespec_now(&now);
  405. faux_timespec_diff(&to, &deadline, &now);
  406. recv_timeout = &to;
  407. }
  408. if (iov[i].iov_len == 0)
  409. continue;
  410. bytes_readed = faux_recv(fd, iov[i].iov_base, iov[i].iov_len,
  411. recv_timeout, sigmask);
  412. if (bytes_readed < 0) { // Error
  413. if (total_readed != 0)
  414. break;
  415. return -1;
  416. }
  417. if (0 == bytes_readed) // EOF or timeout
  418. break;
  419. total_readed += bytes_readed;
  420. }
  421. return total_readed;
  422. }
  423. /** @brief Receives data from the socket. Uses sactter/gather, removes races.
  424. *
  425. * Function has the same parameters and features like faux_sendv_block()
  426. * function but it receives data.
  427. *
  428. * @sa faux_sendv_block()
  429. */
  430. ssize_t faux_recvv_block(int fd, struct iovec *iov, int iovcnt,
  431. const struct timespec *timeout, const sigset_t *sigmask,
  432. int (*isbreak_func)(void))
  433. {
  434. sigset_t all_sigmask = {}; // All signals mask
  435. sigset_t orig_sigmask = {}; // Saved signal mask
  436. ssize_t bytes_num = 0;
  437. assert(fd != -1);
  438. if ((-1 == fd))
  439. return -1;
  440. if (!iov)
  441. return -1;
  442. if (iovcnt == 0)
  443. return 0;
  444. // Block signals to prevent race conditions right before pselect()
  445. // Catch signals while pselect() only
  446. // Now blocks all signals
  447. sigfillset(&all_sigmask);
  448. setsigmask(SIG_SETMASK, &all_sigmask, &orig_sigmask);
  449. // Signal handler can set var to interrupt exchange.
  450. // Get value of this var by special callback function.
  451. if (isbreak_func && isbreak_func())
  452. return -1;
  453. bytes_num = faux_recvv(fd, iov, iovcnt, timeout, sigmask);
  454. setsigmask(SIG_SETMASK, &orig_sigmask, NULL);
  455. return bytes_num;
  456. }