Lely core libraries  2.2.5
fd.c
Go to the documentation of this file.
1 
22 #include "fd.h"
23 
24 #if _POSIX_C_SOURCE >= 200112L
25 
26 #include <assert.h>
27 #include <errno.h>
28 
29 #include <fcntl.h>
30 #include <poll.h>
31 
32 int
34 {
35  int arg = fcntl(fd, F_GETFD);
36  if (arg == -1)
37  return -1;
38  if (!(arg & FD_CLOEXEC) && fcntl(fd, F_SETFD, arg | FD_CLOEXEC) == -1)
39  return -1;
40  return 0;
41 }
42 
43 int
45 {
46  int arg = fcntl(fd, F_GETFL);
47  if (arg == -1)
48  return -1;
49  if (!(arg & O_NONBLOCK) && fcntl(fd, F_SETFL, arg | O_NONBLOCK) == -1)
50  return -1;
51  return 0;
52 }
53 
54 int
55 io_fd_wait(int fd, int *events, int timeout)
56 {
57  assert(events);
58 
59  int result;
60  struct pollfd fds[1] = { { .fd = fd, .events = *events } };
61  do
62  result = poll(fds, 1, timeout);
63  // clang-format off
64  while (result == -1 && ((timeout < 0 && errno == EINTR)
65  || errno == EAGAIN));
66  // clang-format on
67  *events = 0;
68  if (result == -1)
69  return -1;
70  if (!result && timeout >= 0) {
71  errno = EAGAIN;
72  return -1;
73  }
74  assert(result == 1);
75  *events = fds[0].revents;
76  return 0;
77 }
78 
79 ssize_t
80 io_fd_recvmsg(int fd, struct msghdr *msg, int flags, int timeout)
81 {
82 #ifdef MSG_DONTWAIT
83  if (timeout >= 0)
84  flags |= MSG_DONTWAIT;
85 #endif
86 
87  ssize_t result = 0;
88  int errsv = errno;
89  for (;;) {
90  errno = errsv;
91  // Try to receive a message.
92  result = recvmsg(fd, msg, flags);
93  if (result >= 0)
94  break;
95  if (errno == EINTR)
96  continue;
97  if (!timeout || (errno != EAGAIN && errno != EWOULDBLOCK))
98  return -1;
99  // Wait for a message to arrive.
100  // clang-format off
101  int events = (flags & MSG_OOB)
102  ? (POLLRDBAND | POLLPRI) : POLLRDNORM;
103  // clang-format on
104  if (io_fd_wait(fd, &events, timeout) == -1)
105  return -1;
106  // Since the timeout is relative, we can only use a positive
107  // value once.
108  if (timeout > 0)
109  timeout = 0;
110  }
111 
112  return result;
113 }
114 
115 ssize_t
116 io_fd_sendmsg(int fd, const struct msghdr *msg, int flags, int timeout)
117 {
118  flags |= MSG_NOSIGNAL;
119 #ifdef MSG_DONTWAIT
120  if (timeout >= 0)
121  flags |= MSG_DONTWAIT;
122 #endif
123 
124  ssize_t result = 0;
125  int errsv = errno;
126  for (;;) {
127  errno = errsv;
128  // Try to send a message.
129  result = sendmsg(fd, msg, flags);
130  if (result >= 0)
131  break;
132  if (errno == EINTR)
133  continue;
134  if (!timeout || (errno != EAGAIN && errno != EWOULDBLOCK))
135  return -1;
136  // Wait for the socket to become ready.
137  int events = (flags & MSG_OOB) ? POLLWRBAND : POLLWRNORM;
138  if (io_fd_wait(fd, &events, timeout) == -1)
139  return -1;
140  // Since the timeout is relative, we can only use a positive
141  // value once.
142  if (timeout > 0)
143  timeout = 0;
144  }
145  return result;
146 }
147 
148 #endif // _POSIX_C_SOURCE >= 200112L
int io_fd_set_cloexec(int fd)
Sets the FD_CLOEXEC flag of the file descriptor fd.
Definition: fd.c:33
ssize_t io_fd_sendmsg(int fd, const struct msghdr *msg, int flags, int timeout)
Equivalent to POSIX sendmsg(fd, msg, flags | MSG_NOSIGNAL), except that if fd is non-blocking (or the...
Definition: fd.c:116
ssize_t io_fd_recvmsg(int fd, struct msghdr *msg, int flags, int timeout)
Equivalent to POSIX recvmsg(fd, msg, flags), except that if fd is non-blocking (or the implementation...
Definition: fd.c:80
int io_fd_wait(int fd, int *events, int timeout)
Waits for one or more of the I/O events in *events to occur as if by POSIX poll().
Definition: fd.c:55
int io_fd_set_nonblock(int fd)
Sets the O_NONBLOCK flag of the file descriptor fd.
Definition: fd.c:44
This is the internal header file of the common file descriptor functions.