1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtNetwork module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QNET_UNIX_P_H
41#define QNET_UNIX_P_H
42
43//
44// W A R N I N G
45// -------------
46//
47// This file is not part of the Qt API. It exists for the convenience
48// of Qt code on Unix. This header file may change from version to
49// version to version without notice, or even be removed.
50//
51// We mean it.
52//
53
54#include <QtNetwork/private/qtnetworkglobal_p.h>
55#include "private/qcore_unix_p.h"
56
57#include <sys/types.h>
58#include <sys/socket.h>
59#include <netinet/in.h>
60
61#if defined(Q_OS_VXWORKS)
62# include <sockLib.h>
63#endif
64
65// for inet_addr
66#include <netdb.h>
67#include <arpa/inet.h>
68#if defined(Q_OS_VXWORKS)
69# include <hostLib.h>
70#else
71# include <resolv.h>
72#endif
73
74QT_BEGIN_NAMESPACE
75
76// Almost always the same. If not, specify in qplatformdefs.h.
77#if !defined(QT_SOCKOPTLEN_T)
78# define QT_SOCKOPTLEN_T QT_SOCKLEN_T
79#endif
80
81static inline int qt_safe_socket(int domain, int type, int protocol, int flags = 0)
82{
83 Q_ASSERT((flags & ~O_NONBLOCK) == 0);
84
85 int fd;
86#ifdef QT_THREADSAFE_CLOEXEC
87 int newtype = type | SOCK_CLOEXEC;
88 if (flags & O_NONBLOCK)
89 newtype |= SOCK_NONBLOCK;
90 fd = ::socket(domain, newtype, protocol);
91 return fd;
92#else
93 fd = ::socket(domain, type, protocol);
94 if (fd == -1)
95 return -1;
96
97 ::fcntl(fd, F_SETFD, FD_CLOEXEC);
98
99 // set non-block too?
100 if (flags & O_NONBLOCK)
101 ::fcntl(fd, F_SETFL, ::fcntl(fd, F_GETFL) | O_NONBLOCK);
102
103 return fd;
104#endif
105}
106
107static inline int qt_safe_accept(int s, struct sockaddr *addr, QT_SOCKLEN_T *addrlen, int flags = 0)
108{
109 Q_ASSERT((flags & ~O_NONBLOCK) == 0);
110
111 int fd;
112#ifdef QT_THREADSAFE_CLOEXEC
113 // use accept4
114 int sockflags = SOCK_CLOEXEC;
115 if (flags & O_NONBLOCK)
116 sockflags |= SOCK_NONBLOCK;
117# if defined(Q_OS_NETBSD)
118 fd = ::paccept(s, addr, static_cast<QT_SOCKLEN_T *>(addrlen), NULL, sockflags);
119# else
120 fd = ::accept4(s, addr, static_cast<QT_SOCKLEN_T *>(addrlen), sockflags);
121# endif
122 return fd;
123#else
124 fd = ::accept(s, addr, static_cast<QT_SOCKLEN_T *>(addrlen));
125 if (fd == -1)
126 return -1;
127
128 ::fcntl(fd, F_SETFD, FD_CLOEXEC);
129
130 // set non-block too?
131 if (flags & O_NONBLOCK)
132 ::fcntl(fd, F_SETFL, ::fcntl(fd, F_GETFL) | O_NONBLOCK);
133
134 return fd;
135#endif
136}
137
138static inline int qt_safe_listen(int s, int backlog)
139{
140 return ::listen(s, backlog);
141}
142
143static inline int qt_safe_connect(int sockfd, const struct sockaddr *addr, QT_SOCKLEN_T addrlen)
144{
145 int ret;
146 // Solaris e.g. expects a non-const 2nd parameter
147 EINTR_LOOP(ret, QT_SOCKET_CONNECT(sockfd, const_cast<struct sockaddr *>(addr), addrlen));
148 return ret;
149}
150#undef QT_SOCKET_CONNECT
151#define QT_SOCKET_CONNECT qt_safe_connect
152
153#if defined(socket)
154# undef socket
155#endif
156#if defined(accept)
157# undef accept
158#endif
159#if defined(listen)
160# undef listen
161#endif
162
163// VxWorks' headers specify 'int' instead of '...' for the 3rd ioctl() parameter.
164template <typename T>
165static inline int qt_safe_ioctl(int sockfd, unsigned long request, T arg)
166{
167#ifdef Q_OS_VXWORKS
168 return ::ioctl(sockfd, request, (int) arg);
169#else
170 return ::ioctl(sockfd, request, arg);
171#endif
172}
173
174static inline int qt_safe_sendmsg(int sockfd, const struct msghdr *msg, int flags)
175{
176#ifdef MSG_NOSIGNAL
177 flags |= MSG_NOSIGNAL;
178#else
179 qt_ignore_sigpipe();
180#endif
181
182 int ret;
183 EINTR_LOOP(ret, ::sendmsg(sockfd, msg, flags));
184 return ret;
185}
186
187static inline int qt_safe_recvmsg(int sockfd, struct msghdr *msg, int flags)
188{
189 int ret;
190
191 EINTR_LOOP(ret, ::recvmsg(sockfd, msg, flags));
192 return ret;
193}
194
195QT_END_NAMESPACE
196
197#endif // QNET_UNIX_P_H
198