Lely core libraries 2.3.4
fd.c
Go to the documentation of this file.
1
22#include "fd.h"
23
24#if !LELY_NO_STDIO && _POSIX_C_SOURCE >= 200112L
25
26#include <assert.h>
27#include <errno.h>
28
29#include <fcntl.h>
30#include <poll.h>
31
32int
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
43int
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
54int
55io_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
80io_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
116io_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 // !LELY_NO_STDIO && _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.
ptrdiff_t ssize_t
Used for a count of bytes or an error indication.
Definition types.h:43