xref: /trafficserver/src/tscore/ink_sock.cc (revision 4cfd5a73)
1 /** @file
2 
3   A brief file description
4 
5   @section license License
6 
7   Licensed to the Apache Software Foundation (ASF) under one
8   or more contributor license agreements.  See the NOTICE file
9   distributed with this work for additional information
10   regarding copyright ownership.  The ASF licenses this file
11   to you under the Apache License, Version 2.0 (the
12   "License"); you may not use this file except in compliance
13   with the License.  You may obtain a copy of the License at
14 
15       http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22  */
23 
24 /***************************************************************************
25   Socket operations
26 
27 
28 
29 ***************************************************************************/
30 #include "tscore/ink_platform.h"
31 #include "tscore/ink_assert.h"
32 #include "tscore/ink_string.h"
33 #include "tscore/ink_inet.h"
34 
35 //
36 // Compilation options
37 //
38 
39 // #define CHECK_PLAUSIBILITY_OF_SOCKADDR
40 
41 #ifdef CHECK_PLAUSIBILITY_OF_SOCKADDR
42 #define CHECK_PLAUSIBLE_SOCKADDR(_n, _f, _l) check_plausible_sockaddr(_n, _f, _n)
43 inline void
check_valid_sockaddr(sockaddr * sa,char * file,int line)44 check_valid_sockaddr(sockaddr *sa, char *file, int line)
45 {
46   sockaddr_in *si     = (sockaddr_in *)sa;
47   unsigned short port = ntohs(si->sin_port);
48   unsigned short addr = ntohl(si->sin_addr.s_addr);
49 
50   if (port > 20000) {
51     cerr << "[byteordering] In " << file << ", line " << line << " the IP port ";
52     cerr << "was found to be " << port << "(in host byte order).\n";
53     cerr << "[byteordering] This seems implausible, so check for byte order problems\n";
54   }
55 }
56 #else
57 #define CHECK_PLAUSIBLE_SOCKADDR(_n, _f, _l)
58 #endif
59 
60 int
safe_setsockopt(int s,int level,int optname,char * optval,int optlevel)61 safe_setsockopt(int s, int level, int optname, char *optval, int optlevel)
62 {
63   int r;
64   do {
65     r = setsockopt(s, level, optname, optval, optlevel);
66   } while (r < 0 && (errno == EAGAIN || errno == EINTR));
67   return r;
68 }
69 
70 int
safe_getsockopt(int s,int level,int optname,char * optval,int * optlevel)71 safe_getsockopt(int s, int level, int optname, char *optval, int *optlevel)
72 {
73   int r;
74   do {
75     r = getsockopt(s, level, optname, optval, reinterpret_cast<socklen_t *>(optlevel));
76   } while (r < 0 && (errno == EAGAIN || errno == EINTR));
77   return r;
78 }
79 
80 int
safe_fcntl(int fd,int cmd,int arg)81 safe_fcntl(int fd, int cmd, int arg)
82 {
83   int r = 0;
84   do {
85     r = fcntl(fd, cmd, arg);
86   } while (r < 0 && (errno == EAGAIN || errno == EINTR));
87   return r;
88 }
89 
90 int
safe_set_fl(int fd,int arg)91 safe_set_fl(int fd, int arg)
92 {
93   int flags = safe_fcntl(fd, F_GETFL, 0);
94   if (flags < 0) {
95     return flags;
96   }
97   flags |= arg;
98   flags = safe_fcntl(fd, F_SETFL, flags);
99   return flags;
100 }
101 
102 int
safe_clr_fl(int fd,int arg)103 safe_clr_fl(int fd, int arg)
104 {
105   int flags = safe_fcntl(fd, F_GETFL, 0);
106   if (flags < 0) {
107     return flags;
108   }
109   flags &= ~arg;
110   flags = safe_fcntl(fd, F_SETFL, flags);
111   return flags;
112 }
113 
114 int
safe_nonblocking(int fd)115 safe_nonblocking(int fd)
116 {
117   return safe_set_fl(fd, O_NONBLOCK);
118 }
119 
120 int
safe_blocking(int fd)121 safe_blocking(int fd)
122 {
123   return safe_clr_fl(fd, O_NONBLOCK);
124 }
125 
126 int
read_ready(int fd,int timeout_msec)127 read_ready(int fd, int timeout_msec)
128 {
129   struct pollfd p;
130   p.events = POLLIN;
131   p.fd     = fd;
132   int r    = poll(&p, 1, timeout_msec);
133   if (r <= 0) {
134     return r;
135   }
136   if (p.revents & (POLLERR | POLLNVAL)) {
137     return -1;
138   }
139   if (p.revents & (POLLIN | POLLHUP)) {
140     return 1;
141   }
142   return 0;
143 }
144 
145 int
safe_ioctl(int fd,int request,char * arg)146 safe_ioctl(int fd, int request, char *arg)
147 {
148   int r = -1;
149   do {
150     r = ioctl(fd, request, arg);
151   } while (r < 0 && (errno == EAGAIN || errno == EINTR));
152   return r;
153 }
154 
155 int
safe_bind(int s,struct sockaddr const * name,int namelen)156 safe_bind(int s, struct sockaddr const *name, int namelen)
157 {
158   int r;
159   CHECK_PLAUSIBLE_SOCKADDR(name, __FILE__, __LINE__);
160   do {
161     r = bind(s, name, namelen);
162   } while (r < 0 && (errno == EAGAIN || errno == EINTR));
163   return r;
164 }
165 
166 int
safe_listen(int s,int backlog)167 safe_listen(int s, int backlog)
168 {
169   int r;
170   do {
171     r = listen(s, backlog);
172   } while (r < 0 && (errno == EAGAIN || errno == EINTR));
173   return r;
174 }
175 
176 int
safe_getsockname(int s,struct sockaddr * name,int * namelen)177 safe_getsockname(int s, struct sockaddr *name, int *namelen)
178 {
179   int r;
180   do {
181     r = getsockname(s, name, reinterpret_cast<socklen_t *>(namelen));
182   } while (r < 0 && (errno == EAGAIN || errno == EINTR));
183   return r;
184 }
185 
186 int
safe_getpeername(int s,struct sockaddr * name,int * namelen)187 safe_getpeername(int s, struct sockaddr *name, int *namelen)
188 {
189   int r;
190   do {
191     r = getpeername(s, name, reinterpret_cast<socklen_t *>(namelen));
192   } while (r < 0 && (errno == EAGAIN || errno == EINTR));
193   return r;
194 }
195 
196 char
fd_read_char(int fd)197 fd_read_char(int fd)
198 {
199   char c;
200   int r;
201   do {
202     r = read(fd, &c, 1);
203     if (r > 0) {
204       return c;
205     }
206   } while (r < 0 && (errno == EAGAIN || errno == EINTR));
207   perror("fd_read_char");
208   ink_assert(!"fd_read_char");
209   return c;
210 }
211 
212 int
fd_read_line(int fd,char * s,int len)213 fd_read_line(int fd, char *s, int len)
214 {
215   char c;
216   int numread = 0, r;
217   do {
218     do {
219       r = read(fd, &c, 1);
220     } while (r < 0 && (errno == EAGAIN || errno == EINTR));
221 
222     if (r <= 0 && numread) {
223       break;
224     }
225 
226     if (r <= 0) {
227       return r;
228     }
229 
230     if (c == '\n') {
231       break;
232     }
233 
234     s[numread++] = c;
235   } while (numread < len - 1);
236 
237   s[numread] = 0;
238   return numread;
239 }
240 
241 int
close_socket(int s)242 close_socket(int s)
243 {
244   return close(s);
245 }
246 
247 int
write_socket(int s,const char * buffer,int length)248 write_socket(int s, const char *buffer, int length)
249 {
250   return write(s, (const void *)buffer, length);
251 }
252 
253 int
read_socket(int s,char * buffer,int length)254 read_socket(int s, char *buffer, int length)
255 {
256   return read(s, (void *)buffer, length);
257 }
258 
259 int
bind_unix_domain_socket(const char * path,mode_t mode)260 bind_unix_domain_socket(const char *path, mode_t mode)
261 {
262   int sockfd;
263   struct sockaddr_un sockaddr;
264   socklen_t socklen;
265 
266   (void)unlink(path);
267 
268   sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
269   if (sockfd < 0) {
270     return sockfd;
271   }
272 
273   if (strlen(path) > sizeof(sockaddr.sun_path) - 1) {
274     errno = ENAMETOOLONG;
275     goto fail;
276   }
277 
278   ink_zero(sockaddr);
279   sockaddr.sun_family = AF_UNIX;
280   ink_strlcpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path));
281 
282 #if defined(darwin) || defined(freebsd)
283   socklen = sizeof(struct sockaddr_un);
284 #else
285   socklen = strlen(sockaddr.sun_path) + sizeof(sockaddr.sun_family);
286 #endif
287 
288   if (safe_setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, SOCKOPT_ON, sizeof(int)) < 0) {
289     goto fail;
290   }
291 
292   if (safe_fcntl(sockfd, F_SETFD, FD_CLOEXEC) < 0) {
293     goto fail;
294   }
295 
296   if (bind(sockfd, reinterpret_cast<struct sockaddr *>(&sockaddr), socklen) < 0) {
297     goto fail;
298   }
299 
300   if (chmod(path, mode) < 0) {
301     goto fail;
302   }
303 
304   if (listen(sockfd, 5) < 0) {
305     goto fail;
306   }
307 
308   return sockfd;
309 
310 fail:
311   int errsav = errno;
312   close(sockfd);
313   errno = errsav;
314   return -1;
315 }
316