1 /*
2 * libusual - Utility library for C
3 *
4 * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 /*
20 * Wrappers around regular I/O functions (send/recv/read/write)
21 * that survive EINTR and also can log problems.
22 */
23
24 #include <usual/safeio.h>
25
26 #include <usual/socket.h>
27 #include <usual/logging.h>
28 #include <usual/string.h>
29 #include <usual/time.h>
30
safe_read(int fd,void * buf,size_t len)31 ssize_t safe_read(int fd, void *buf, size_t len)
32 {
33 ssize_t res;
34 loop:
35 res = read(fd, buf, len);
36 if (res < 0 && errno == EINTR)
37 goto loop;
38 return res;
39 }
40
safe_write(int fd,const void * buf,size_t len)41 ssize_t safe_write(int fd, const void *buf, size_t len)
42 {
43 ssize_t res;
44 loop:
45 res = write(fd, buf, len);
46 if (res < 0 && errno == EINTR)
47 goto loop;
48 return res;
49 }
50
safe_recv(int fd,void * buf,size_t len,int flags)51 ssize_t safe_recv(int fd, void *buf, size_t len, int flags)
52 {
53 ssize_t res;
54 char ebuf[128];
55 loop:
56 res = recv(fd, buf, len, flags);
57 if (res < 0 && errno == EINTR)
58 goto loop;
59 if (res < 0)
60 log_noise("safe_recv(%d, %zu) = %s", fd, len,
61 strerror_r(errno, ebuf, sizeof(ebuf)));
62 else if (cf_verbose > 2)
63 log_noise("safe_recv(%d, %zu) = %zd", fd, len, res);
64 return res;
65 }
66
safe_send(int fd,const void * buf,size_t len,int flags)67 ssize_t safe_send(int fd, const void *buf, size_t len, int flags)
68 {
69 ssize_t res;
70 char ebuf[128];
71 loop:
72 res = send(fd, buf, len, flags);
73 if (res < 0 && errno == EINTR)
74 goto loop;
75 if (res < 0)
76 log_noise("safe_send(%d, %zu) = %s", fd, len,
77 strerror_r(errno, ebuf, sizeof(ebuf)));
78 else if (cf_verbose > 2)
79 log_noise("safe_send(%d, %zu) = %zd", fd, len, res);
80 return res;
81 }
82
safe_close(int fd)83 int safe_close(int fd)
84 {
85 int res;
86
87 #ifndef WIN32
88 /*
89 * POSIX says close() can return EINTR but fd state is "undefined"
90 * later. Seems Linux and BSDs close the fd anyway and EINTR is
91 * simply informative. Thus retry is dangerous.
92 */
93 res = close(fd);
94 #else
95 /*
96 * Seems on windows it can returns proper EINTR but only when
97 * WSACancelBlockingCall() is called. As we don't do it,
98 * ignore EINTR on win32 too.
99 */
100 res = closesocket(fd);
101 #endif
102 if (res < 0) {
103 char ebuf[128];
104 log_warning("safe_close(%d) = %s", fd,
105 strerror_r(errno, ebuf, sizeof(ebuf)));
106 } else if (cf_verbose > 2) {
107 log_noise("safe_close(%d) = %d", fd, res);
108 }
109
110 /* ignore EINTR */
111 if (res < 0 && errno == EINTR)
112 return 0;
113
114 return res;
115 }
116
safe_recvmsg(int fd,struct msghdr * msg,int flags)117 ssize_t safe_recvmsg(int fd, struct msghdr *msg, int flags)
118 {
119 ssize_t res;
120 char ebuf[128];
121 loop:
122 res = recvmsg(fd, msg, flags);
123 if (res < 0 && errno == EINTR)
124 goto loop;
125 if (res < 0)
126 log_warning("safe_recvmsg(%d, msg, %d) = %s", fd, flags,
127 strerror_r(errno, ebuf, sizeof(ebuf)));
128 else if (cf_verbose > 2)
129 log_noise("safe_recvmsg(%d, msg, %d) = %zd", fd, flags, res);
130 return res;
131 }
132
safe_sendmsg(int fd,const struct msghdr * msg,int flags)133 ssize_t safe_sendmsg(int fd, const struct msghdr *msg, int flags)
134 {
135 ssize_t res;
136 int msgerr_count = 0;
137 char ebuf[128];
138 loop:
139 res = sendmsg(fd, msg, flags);
140 if (res < 0 && errno == EINTR)
141 goto loop;
142
143 if (res < 0) {
144 log_warning("safe_sendmsg(%d, msg[%d,%d], %d) = %s", fd,
145 (int)msg->msg_iov[0].iov_len,
146 (int)msg->msg_controllen,
147 flags, strerror_r(errno, ebuf, sizeof(ebuf)));
148
149 /* with ancillary data on blocking socket OSX returns
150 * EMSGSIZE instead of blocking. try to solve it by waiting */
151 if (errno == EMSGSIZE && msgerr_count < 20) {
152 struct timeval tv = {1, 0};
153 log_warning("trying to sleep a bit");
154 select(0, NULL, NULL, NULL, &tv);
155 msgerr_count++;
156 goto loop;
157 }
158 } else if (cf_verbose > 2)
159 log_noise("safe_sendmsg(%d, msg, %d) = %zd", fd, flags, res);
160 return res;
161 }
162
safe_connect(int fd,const struct sockaddr * sa,socklen_t sa_len)163 int safe_connect(int fd, const struct sockaddr *sa, socklen_t sa_len)
164 {
165 int res;
166 char buf[128];
167 char ebuf[128];
168 loop:
169 res = connect(fd, sa, sa_len);
170 if (res < 0 && errno == EINTR)
171 goto loop;
172 if (res < 0 && (errno != EINPROGRESS || cf_verbose > 2))
173 log_noise("connect(%d, %s) = %s", fd,
174 sa2str(sa, buf, sizeof(buf)),
175 strerror_r(errno, ebuf, sizeof(ebuf)));
176 else if (cf_verbose > 2)
177 log_noise("connect(%d, %s) = %d", fd, sa2str(sa, buf, sizeof(buf)), res);
178 return res;
179 }
180
safe_accept(int fd,struct sockaddr * sa,socklen_t * sa_len_p)181 int safe_accept(int fd, struct sockaddr *sa, socklen_t *sa_len_p)
182 {
183 int res;
184 char buf[128];
185 char ebuf[128];
186 loop:
187 res = accept(fd, sa, sa_len_p);
188 if (res < 0 && errno == EINTR)
189 goto loop;
190 if (res < 0)
191 log_noise("safe_accept(%d) = %s", fd,
192 strerror_r(errno, ebuf, sizeof(ebuf)));
193 else if (cf_verbose > 2) {
194 if (sa->sa_family == AF_UNIX)
195 /* sa2str() won't work here since accept() doesn't set sun_path */
196 log_noise("safe_accept(%d) = %d (unix)", fd, res);
197 else
198 log_noise("safe_accept(%d) = %d (%s)", fd, res, sa2str(sa, buf, sizeof(buf)));
199 }
200 return res;
201 }
202