1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QNET_UNIX_P_H
5#define QNET_UNIX_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists for the convenience
12// of Qt code on Unix. This header file may change from version to
13// version to version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtNetwork/private/qtnetworkglobal_p.h>
19#include "private/qcore_unix_p.h"
20
21#include <sys/types.h>
22#include <sys/socket.h>
23#include <netinet/in.h>
24
25#if defined(Q_OS_VXWORKS)
26# include <sockLib.h>
27#endif
28
29// for inet_addr
30#include <netdb.h>
31#include <arpa/inet.h>
32#if defined(Q_OS_VXWORKS)
33# include <hostLib.h>
34#else
35# include <resolv.h>
36#endif
37
38QT_BEGIN_NAMESPACE
39
40// Almost always the same. If not, specify in qplatformdefs.h.
41#if !defined(QT_SOCKOPTLEN_T)
42# define QT_SOCKOPTLEN_T QT_SOCKLEN_T
43#endif
44
45static inline int qt_safe_socket(int domain, int type, int protocol, int flags = 0)
46{
47 Q_ASSERT((flags & ~O_NONBLOCK) == 0);
48
49 int fd;
50#ifdef QT_THREADSAFE_CLOEXEC
51 int newtype = type | SOCK_CLOEXEC;
52 if (flags & O_NONBLOCK)
53 newtype |= SOCK_NONBLOCK;
54 fd = ::socket(domain: domain, type: newtype, protocol: protocol);
55 return fd;
56#else
57 fd = ::socket(domain, type, protocol);
58 if (fd == -1)
59 return -1;
60
61 ::fcntl(fd, F_SETFD, FD_CLOEXEC);
62
63 // set non-block too?
64 if (flags & O_NONBLOCK)
65 ::fcntl(fd, F_SETFL, ::fcntl(fd, F_GETFL) | O_NONBLOCK);
66
67 return fd;
68#endif
69}
70
71static inline int qt_safe_accept(int s, struct sockaddr *addr, QT_SOCKLEN_T *addrlen, int flags = 0)
72{
73 Q_ASSERT((flags & ~O_NONBLOCK) == 0);
74
75 int fd;
76#ifdef QT_THREADSAFE_CLOEXEC
77 // use accept4
78 int sockflags = SOCK_CLOEXEC;
79 if (flags & O_NONBLOCK)
80 sockflags |= SOCK_NONBLOCK;
81# if defined(Q_OS_NETBSD)
82 fd = ::paccept(s, addr, static_cast<QT_SOCKLEN_T *>(addrlen), NULL, sockflags);
83# else
84 fd = ::accept4(fd: s, addr: addr, addr_len: static_cast<QT_SOCKLEN_T *>(addrlen), flags: sockflags);
85# endif
86 return fd;
87#else
88 fd = ::accept(s, addr, static_cast<QT_SOCKLEN_T *>(addrlen));
89 if (fd == -1)
90 return -1;
91
92 ::fcntl(fd, F_SETFD, FD_CLOEXEC);
93
94 // set non-block too?
95 if (flags & O_NONBLOCK)
96 ::fcntl(fd, F_SETFL, ::fcntl(fd, F_GETFL) | O_NONBLOCK);
97
98 return fd;
99#endif
100}
101
102static inline int qt_safe_listen(int s, int backlog)
103{
104 return ::listen(fd: s, n: backlog);
105}
106
107static inline int qt_safe_connect(int sockfd, const struct sockaddr *addr, QT_SOCKLEN_T addrlen)
108{
109 int ret;
110 // Solaris e.g. expects a non-const 2nd parameter
111 EINTR_LOOP(ret, QT_SOCKET_CONNECT(sockfd, const_cast<struct sockaddr *>(addr), addrlen));
112 return ret;
113}
114#undef QT_SOCKET_CONNECT
115#define QT_SOCKET_CONNECT qt_safe_connect
116
117#if defined(socket)
118# undef socket
119#endif
120#if defined(accept)
121# undef accept
122#endif
123#if defined(listen)
124# undef listen
125#endif
126
127// VxWorks' headers specify 'int' instead of '...' for the 3rd ioctl() parameter.
128template <typename T>
129static inline int qt_safe_ioctl(int sockfd, unsigned long request, T arg)
130{
131#ifdef Q_OS_VXWORKS
132 return ::ioctl(sockfd, request, (int) arg);
133#else
134 return ::ioctl(fd: sockfd, request: request, arg);
135#endif
136}
137
138static inline int qt_safe_sendmsg(int sockfd, const struct msghdr *msg, int flags)
139{
140#ifdef MSG_NOSIGNAL
141 flags |= MSG_NOSIGNAL;
142#else
143 qt_ignore_sigpipe();
144#endif
145
146 int ret;
147 EINTR_LOOP(ret, ::sendmsg(sockfd, msg, flags));
148 return ret;
149}
150
151static inline int qt_safe_recvmsg(int sockfd, struct msghdr *msg, int flags)
152{
153 int ret;
154
155 EINTR_LOOP(ret, ::recvmsg(sockfd, msg, flags));
156 return ret;
157}
158
159QT_END_NAMESPACE
160
161#endif // QNET_UNIX_P_H
162

source code of qtbase/src/network/socket/qnet_unix_p.h