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 
26   UnixSocketManager.h
27 
28   Handle the allocation of the socket descriptor (fd) resource.
29 
30 
31 ****************************************************************************/
32 #pragma once
33 
34 #include "tscore/ink_platform.h"
35 #include "tscore/ink_sock.h"
36 #include "I_SocketManager.h"
37 
38 //
39 // These limits are currently disabled
40 //
41 // 1024 - stdin, stderr, stdout
42 #define EPOLL_MAX_DESCRIPTOR_SIZE 32768
43 
44 TS_INLINE bool
transient_error()45 transient_error()
46 {
47   bool transient = (errno == EINTR);
48 #ifdef ENOMEM
49   transient = transient || (errno == ENOMEM);
50 #endif
51 #ifdef ENOBUFS
52   transient = transient || (errno == ENOBUFS);
53 #endif
54   return transient;
55 }
56 
57 TS_INLINE int
open(const char * path,int oflag,mode_t mode)58 SocketManager::open(const char *path, int oflag, mode_t mode)
59 {
60   int s;
61   do {
62     s = ::open(path, oflag, mode);
63     if (likely(s >= 0)) {
64       break;
65     }
66     s = -errno;
67   } while (transient_error());
68   return s;
69 }
70 
71 TS_INLINE int64_t
read(int fd,void * buf,int size,void *)72 SocketManager::read(int fd, void *buf, int size, void * /* pOLP ATS_UNUSED */)
73 {
74   int64_t r;
75   do {
76     r = ::read(fd, buf, size);
77     if (likely(r >= 0)) {
78       break;
79     }
80     r = -errno;
81   } while (r == -EINTR);
82   return r;
83 }
84 
85 TS_INLINE int64_t
pread(int fd,void * buf,int size,off_t offset,char *)86 SocketManager::pread(int fd, void *buf, int size, off_t offset, char * /* tag ATS_UNUSED */)
87 {
88   int64_t r;
89   do {
90     r = ::pread(fd, buf, size, offset);
91     if (r < 0) {
92       r = -errno;
93     }
94   } while (r == -EINTR);
95   return r;
96 }
97 
98 TS_INLINE int64_t
readv(int fd,struct iovec * vector,size_t count)99 SocketManager::readv(int fd, struct iovec *vector, size_t count)
100 {
101   int64_t r;
102   do {
103     // coverity[tainted_data_argument]
104     if (likely((r = ::readv(fd, vector, count)) >= 0)) {
105       break;
106     }
107     r = -errno;
108   } while (transient_error());
109   return r;
110 }
111 
112 TS_INLINE int64_t
vector_io(int fd,struct iovec * vector,size_t count,int read_request,void *)113 SocketManager::vector_io(int fd, struct iovec *vector, size_t count, int read_request, void * /* pOLP ATS_UNUSED */)
114 {
115   const int max_iovecs_per_request = 16;
116   int n;
117   int64_t r;
118   int n_vec;
119   int64_t bytes_xfered = 0;
120 
121   for (n_vec = 0; n_vec < (int)count; n_vec += max_iovecs_per_request) {
122     int current_count = std::min(max_iovecs_per_request, ((int)(count - n_vec)));
123     do {
124       // coverity[tainted_data_argument]
125       r = read_request ? ::readv(fd, &vector[n_vec], current_count) : ::writev(fd, &vector[n_vec], current_count);
126       if (likely(r >= 0)) {
127         break;
128       }
129       r = -errno;
130     } while (transient_error());
131 
132     if (r <= 0) {
133       return (bytes_xfered && (r == -EAGAIN)) ? bytes_xfered : r;
134     }
135     bytes_xfered += r;
136 
137     if ((n_vec + max_iovecs_per_request) >= (int)count) {
138       break;
139     }
140 
141     // Compute bytes in current vector
142     int64_t current_request_bytes = 0;
143     for (n = n_vec; n < (n_vec + current_count); ++n) {
144       current_request_bytes += vector[n].iov_len;
145     }
146 
147     // Exit if we were unable to read all data in the current vector
148     if (r != current_request_bytes) {
149       break;
150     }
151   }
152   return bytes_xfered;
153 }
154 
155 TS_INLINE int64_t
read_vector(int fd,struct iovec * vector,size_t count,void * pOLP)156 SocketManager::read_vector(int fd, struct iovec *vector, size_t count, void *pOLP)
157 {
158   return vector_io(fd, vector, count, 1, pOLP);
159 }
160 
161 TS_INLINE int
recv(int fd,void * buf,int size,int flags)162 SocketManager::recv(int fd, void *buf, int size, int flags)
163 {
164   int r;
165   do {
166     if (unlikely((r = ::recv(fd, (char *)buf, size, flags)) < 0)) {
167       r = -errno;
168     }
169   } while (r == -EINTR);
170   return r;
171 }
172 
173 TS_INLINE int
recvfrom(int fd,void * buf,int size,int flags,struct sockaddr * addr,socklen_t * addrlen)174 SocketManager::recvfrom(int fd, void *buf, int size, int flags, struct sockaddr *addr, socklen_t *addrlen)
175 {
176   int r;
177   do {
178     r = ::recvfrom(fd, (char *)buf, size, flags, addr, addrlen);
179     if (unlikely(r < 0)) {
180       r = -errno;
181     }
182   } while (r == -EINTR);
183   return r;
184 }
185 
186 TS_INLINE int
recvmsg(int fd,struct msghdr * m,int flags,void *)187 SocketManager::recvmsg(int fd, struct msghdr *m, int flags, void * /* pOLP ATS_UNUSED */)
188 {
189   int r;
190   do {
191     if (unlikely((r = ::recvmsg(fd, m, flags)) < 0)) {
192       r = -errno;
193     }
194   } while (r == -EINTR);
195   return r;
196 }
197 
198 TS_INLINE int64_t
write(int fd,void * buf,int size,void *)199 SocketManager::write(int fd, void *buf, int size, void * /* pOLP ATS_UNUSED */)
200 {
201   int64_t r;
202   do {
203     if (likely((r = ::write(fd, buf, size)) >= 0)) {
204       break;
205     }
206     r = -errno;
207   } while (r == -EINTR);
208   return r;
209 }
210 
211 TS_INLINE int64_t
pwrite(int fd,void * buf,int size,off_t offset,char *)212 SocketManager::pwrite(int fd, void *buf, int size, off_t offset, char * /* tag ATS_UNUSED */)
213 {
214   int64_t r;
215   do {
216     if (unlikely((r = ::pwrite(fd, buf, size, offset)) < 0)) {
217       r = -errno;
218     }
219   } while (r == -EINTR);
220   return r;
221 }
222 
223 TS_INLINE int64_t
writev(int fd,struct iovec * vector,size_t count)224 SocketManager::writev(int fd, struct iovec *vector, size_t count)
225 {
226   int64_t r;
227   do {
228     if (likely((r = ::writev(fd, vector, count)) >= 0)) {
229       break;
230     }
231     r = -errno;
232   } while (transient_error());
233   return r;
234 }
235 
236 TS_INLINE int64_t
write_vector(int fd,struct iovec * vector,size_t count,void * pOLP)237 SocketManager::write_vector(int fd, struct iovec *vector, size_t count, void *pOLP)
238 {
239   return vector_io(fd, vector, count, 0, pOLP);
240 }
241 
242 TS_INLINE int
send(int fd,void * buf,int size,int flags)243 SocketManager::send(int fd, void *buf, int size, int flags)
244 {
245   int r;
246   do {
247     if (unlikely((r = ::send(fd, (char *)buf, size, flags)) < 0)) {
248       r = -errno;
249     }
250   } while (r == -EINTR);
251   return r;
252 }
253 
254 TS_INLINE int
sendto(int fd,void * buf,int len,int flags,struct sockaddr const * to,int tolen)255 SocketManager::sendto(int fd, void *buf, int len, int flags, struct sockaddr const *to, int tolen)
256 {
257   int r;
258   do {
259     if (unlikely((r = ::sendto(fd, (char *)buf, len, flags, to, tolen)) < 0)) {
260       r = -errno;
261     }
262   } while (r == -EINTR);
263   return r;
264 }
265 
266 TS_INLINE int
sendmsg(int fd,struct msghdr * m,int flags,void *)267 SocketManager::sendmsg(int fd, struct msghdr *m, int flags, void * /* pOLP ATS_UNUSED */)
268 {
269   int r;
270   do {
271     if (unlikely((r = ::sendmsg(fd, m, flags)) < 0)) {
272       r = -errno;
273     }
274   } while (r == -EINTR);
275   return r;
276 }
277 
278 TS_INLINE int64_t
lseek(int fd,off_t offset,int whence)279 SocketManager::lseek(int fd, off_t offset, int whence)
280 {
281   int64_t r;
282   do {
283     if ((r = ::lseek(fd, offset, whence)) < 0) {
284       r = -errno;
285     }
286   } while (r == -EINTR);
287   return r;
288 }
289 
290 TS_INLINE int
fstat(int fd,struct stat * buf)291 SocketManager::fstat(int fd, struct stat *buf)
292 {
293   int r;
294   do {
295     if ((r = ::fstat(fd, buf)) >= 0) {
296       break;
297     }
298     r = -errno;
299   } while (transient_error());
300   return r;
301 }
302 
303 TS_INLINE int
unlink(char * buf)304 SocketManager::unlink(char *buf)
305 {
306   int r;
307   do {
308     if ((r = ::unlink(buf)) < 0) {
309       r = -errno;
310     }
311   } while (r == -EINTR);
312   return r;
313 }
314 
315 TS_INLINE int
fsync(int fildes)316 SocketManager::fsync(int fildes)
317 {
318   int r;
319   do {
320     if ((r = ::fsync(fildes)) < 0) {
321       r = -errno;
322     }
323   } while (r == -EINTR);
324   return r;
325 }
326 
327 TS_INLINE int
ftruncate(int fildes,off_t length)328 SocketManager::ftruncate(int fildes, off_t length)
329 {
330   int r;
331   do {
332     if ((r = ::ftruncate(fildes, length)) < 0) {
333       r = -errno;
334     }
335   } while (r == -EINTR);
336   return r;
337 }
338 
339 TS_INLINE int
poll(struct pollfd * fds,unsigned long nfds,int timeout)340 SocketManager::poll(struct pollfd *fds, unsigned long nfds, int timeout)
341 {
342   int r;
343   do {
344     if ((r = ::poll(fds, nfds, timeout)) >= 0) {
345       break;
346     }
347     r = -errno;
348   } while (transient_error());
349   return r;
350 }
351 
352 #if TS_USE_EPOLL
353 TS_INLINE int
epoll_create(int size)354 SocketManager::epoll_create(int size)
355 {
356   int r;
357   if (size <= 0) {
358     size = EPOLL_MAX_DESCRIPTOR_SIZE;
359   }
360   do {
361     if (likely((r = ::epoll_create(size)) >= 0)) {
362       break;
363     }
364     r = -errno;
365   } while (errno == -EINTR);
366   return r;
367 }
368 
369 TS_INLINE int
epoll_close(int epfd)370 SocketManager::epoll_close(int epfd)
371 {
372   int r = 0;
373   if (likely(epfd >= 0)) {
374     do {
375       if (likely((r = ::close(epfd)) == 0)) {
376         break;
377       }
378       r = -errno;
379     } while (errno == -EINTR);
380   }
381   return r;
382 }
383 
384 TS_INLINE int
epoll_ctl(int epfd,int op,int fd,struct epoll_event * event)385 SocketManager::epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
386 {
387   int r;
388   do {
389     if (likely((r = ::epoll_ctl(epfd, op, fd, event)) == 0)) {
390       break;
391     }
392     r = -errno;
393   } while (errno == -EINTR);
394   return r;
395 }
396 
397 TS_INLINE int
epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout)398 SocketManager::epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
399 {
400   int r;
401   do {
402     if ((r = ::epoll_wait(epfd, events, maxevents, timeout)) >= 0) {
403       break;
404     }
405     r = -errno;
406   } while (errno == -EINTR);
407   return r;
408 }
409 
410 #endif /* TS_USE_EPOLL */
411 
412 #if TS_USE_KQUEUE
413 TS_INLINE int
kqueue()414 SocketManager::kqueue()
415 {
416   return ::kqueue();
417 }
418 
419 TS_INLINE int
kevent(int kq,const struct kevent * changelist,int nchanges,struct kevent * eventlist,int nevents,const struct timespec * timeout)420 SocketManager::kevent(int kq, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents,
421                       const struct timespec *timeout)
422 {
423   int r;
424   do {
425     r = ::kevent(kq, changelist, nchanges, eventlist, nevents, timeout);
426     if (likely(r >= 0)) {
427       break;
428     }
429     r = -errno;
430   } while (errno == -EINTR);
431   return r;
432 }
433 #endif /* TS_USE_KQUEUE */
434 
435 #if TS_USE_PORT
436 TS_INLINE int
port_create()437 SocketManager::port_create()
438 {
439   return ::port_create();
440 }
441 
442 TS_INLINE int
port_associate(int port,int source,uintptr_t obj,int events,void * user)443 SocketManager::port_associate(int port, int source, uintptr_t obj, int events, void *user)
444 {
445   int r;
446   r = ::port_associate(port, source, obj, events, user);
447   if (r < 0)
448     r = -errno;
449   return r;
450 }
451 
452 TS_INLINE int
port_dissociate(int port,int source,uintptr_t obj)453 SocketManager::port_dissociate(int port, int source, uintptr_t obj)
454 {
455   int r;
456   r = ::port_dissociate(port, source, obj);
457   if (r < 0)
458     r = -errno;
459   return r;
460 }
461 
462 TS_INLINE int
port_getn(int port,port_event_t * list,uint_t max,uint_t * nget,timespec_t * timeout)463 SocketManager::port_getn(int port, port_event_t *list, uint_t max, uint_t *nget, timespec_t *timeout)
464 {
465   int r;
466   do {
467     if ((r = ::port_getn(port, list, max, nget, timeout)) >= 0)
468       break;
469     r = -errno;
470   } while (errno == -EINTR); // TODO: possible EAGAIN(undocumented)
471   return r;
472 }
473 #endif /* TS_USE_PORT */
474 
475 TS_INLINE int
get_sndbuf_size(int s)476 SocketManager::get_sndbuf_size(int s)
477 {
478   int bsz = 0;
479   int bszsz, r;
480 
481   bszsz = sizeof(bsz);
482   r     = safe_getsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&bsz, &bszsz);
483   return (r == 0 ? bsz : r);
484 }
485 
486 TS_INLINE int
get_rcvbuf_size(int s)487 SocketManager::get_rcvbuf_size(int s)
488 {
489   int bsz = 0;
490   int bszsz, r;
491 
492   bszsz = sizeof(bsz);
493   r     = safe_getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&bsz, &bszsz);
494   return (r == 0 ? bsz : r);
495 }
496 
497 TS_INLINE int
set_sndbuf_size(int s,int bsz)498 SocketManager::set_sndbuf_size(int s, int bsz)
499 {
500   return safe_setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&bsz, sizeof(bsz));
501 }
502 
503 TS_INLINE int
set_rcvbuf_size(int s,int bsz)504 SocketManager::set_rcvbuf_size(int s, int bsz)
505 {
506   return safe_setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&bsz, sizeof(bsz));
507 }
508 
509 TS_INLINE int
getsockname(int s,struct sockaddr * sa,socklen_t * sz)510 SocketManager::getsockname(int s, struct sockaddr *sa, socklen_t *sz)
511 {
512   return ::getsockname(s, sa, sz);
513 }
514 
515 TS_INLINE int
socket(int domain,int type,int protocol)516 SocketManager::socket(int domain, int type, int protocol)
517 {
518   return ::socket(domain, type, protocol);
519 }
520 
521 TS_INLINE int
shutdown(int s,int how)522 SocketManager::shutdown(int s, int how)
523 {
524   int res;
525   do {
526     if (unlikely((res = ::shutdown(s, how)) < 0)) {
527       res = -errno;
528     }
529   } while (res == -EINTR);
530   return res;
531 }
532 
533 TS_INLINE int
lockf(int s,int f,off_t size)534 SocketManager::lockf(int s, int f, off_t size)
535 {
536   int res;
537   do {
538     if ((res = ::lockf(s, f, size)) < 0) {
539       res = -errno;
540     }
541   } while (res == -EINTR);
542   return res;
543 }
544 
545 TS_INLINE int
dup(int s)546 SocketManager::dup(int s)
547 {
548   int res;
549   do {
550     if ((res = ::dup(s)) >= 0) {
551       break;
552     }
553     res = -errno;
554   } while (res == -EINTR);
555   return res;
556 }
557