1
1
/****************************************************************************
3
3
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4
** All rights reserved.
4
5
** Contact: Nokia Corporation (qt-info@nokia.com)
6
7
** This file is part of the QtNetwork module of the Qt Toolkit.
8
9
** $QT_BEGIN_LICENSE:LGPL$
10
** Licensees holding valid Qt Commercial licenses may use this file in
11
** accordance with the Qt Commercial License Agreement provided with the
12
** Software or, alternatively, in accordance with the terms contained in
13
** a written agreement between you and Nokia.
10
** No Commercial Usage
11
** This file contains pre-release code and may not be distributed.
12
** You may use this file in accordance with the terms and conditions
13
** contained in the Technology Preview License Agreement accompanying
15
16
** GNU Lesser General Public License Usage
16
17
** Alternatively, this file may be used under the terms of the GNU Lesser
20
21
** ensure the GNU Lesser General Public License version 2.1 requirements
21
22
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23
** In addition, as a special exception, Nokia gives you certain
24
** additional rights. These rights are described in the Nokia Qt LGPL
25
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
28
** GNU General Public License Usage
29
** Alternatively, this file may be used under the terms of the GNU
30
** General Public License version 3.0 as published by the Free Software
31
** Foundation and appearing in the file LICENSE.GPL included in the
32
** packaging of this file. Please review the following information to
33
** ensure the GNU General Public License version 3.0 requirements will be
34
** met: http://www.gnu.org/copyleft/gpl.html.
36
** If you are unsure which license is appropriate for your use, please
37
** contact the sales department at http://www.qtsoftware.com/contact.
24
** In addition, as a special exception, Nokia gives you certain additional
25
** rights. These rights are described in the Nokia Qt LGPL Exception
26
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28
** If you have questions regarding the use of this file, please contact
29
** Nokia at qt-info@nokia.com.
38
38
** $QT_END_LICENSE$
40
40
****************************************************************************/
42
42
//#define QNATIVESOCKETENGINE_DEBUG
44
43
#include "qnativesocketengine_p.h"
44
#include "private/qnet_unix_p.h"
45
45
#include "qiodevice.h"
46
46
#include "qhostaddress.h"
47
47
#include "qvarlengtharray.h"
161
173
int protocol = AF_INET;
163
175
int type = (socketType == QAbstractSocket::UdpSocket) ? SOCK_DGRAM : SOCK_STREAM;
164
int socket = qt_socket_socket(protocol, type, 0);
177
int socket = ::socket(protocol, type, 0);
179
int socket = qt_safe_socket(protocol, type, 0);
166
182
if (socket <= 0) {
221
240
case QNativeSocketEngine::ReceiveOutOfBandData:
222
241
n = SO_OOBINLINE;
243
case QNativeSocketEngine::LowDelayOption:
247
case QNativeSocketEngine::KeepAliveOption:
227
253
QT_SOCKOPTLEN_T len = sizeof(v);
228
if (getsockopt(socketDescriptor, SOL_SOCKET, n, (char *) &v, &len) != -1)
254
if (::getsockopt(socketDescriptor, level, n, (char *) &v, &len) != -1)
299
#else // Q_OS_VXWORKS
302
if (::ioctl(socketDescriptor, FIONBIO, &onoff) < 0) {
304
if (qt_safe_ioctl(socketDescriptor, FIONBIO, &onoff) < 0) {
306
#ifdef QNATIVESOCKETENGINE_DEBUG
307
perror("QNativeSocketEnginePrivate::setOption(): ioctl(FIONBIO, 1) failed");
311
#endif // Q_OS_VXWORKS
272
314
case QNativeSocketEngine::AddressReusable:
315
#if defined(SO_REUSEPORT) && !defined(Q_OS_SYMBIAN)
274
316
n = SO_REUSEPORT;
276
318
n = SO_REUSEADDR;
281
323
case QNativeSocketEngine::ReceiveOutOfBandData:
282
324
n = SO_OOBINLINE;
326
case QNativeSocketEngine::LowDelayOption:
330
case QNativeSocketEngine::KeepAliveOption:
286
return ::setsockopt(socketDescriptor, SOL_SOCKET, n, (char *) &v, sizeof(v)) == 0;
335
return ::setsockopt(socketDescriptor, level, n, (char *) &v, sizeof(v)) == 0;
289
338
bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 port)
340
#ifdef QNATIVESOCKETENGINE_DEBUG
341
qDebug("QNativeSocketEnginePrivate::nativeConnect() : %d ", socketDescriptor);
291
344
struct sockaddr_in sockAddrIPv4;
292
345
struct sockaddr *sockAddrPtr = 0;
293
346
QT_SOCKLEN_T sockAddrSize = 0;
329
int connectResult = QT_SOCKET_CONNECT(socketDescriptor, sockAddrPtr, sockAddrSize);
382
int connectResult = ::connect(socketDescriptor, sockAddrPtr, sockAddrSize);
384
int connectResult = qt_safe_connect(socketDescriptor, sockAddrPtr, sockAddrSize);
330
386
if (connectResult == -1) {
467
524
bool QNativeSocketEnginePrivate::nativeListen(int backlog)
469
if (qt_socket_listen(socketDescriptor, backlog) < 0) {
527
if (::listen(socketDescriptor, backlog) < 0) {
529
if (qt_safe_listen(socketDescriptor, backlog) < 0) {
472
533
setError(QAbstractSocket::AddressInUseError,
494
555
int QNativeSocketEnginePrivate::nativeAccept()
496
int acceptedDescriptor = qt_socket_accept(socketDescriptor, 0, 0);
497
#if defined (QNATIVESOCKETENGINE_DEBUG)
498
qDebug("QNativeSocketEnginePrivate::nativeAccept() == %i", acceptedDescriptor);
500
// Ensure that the socket is closed on exec*()
501
::fcntl(acceptedDescriptor, F_SETFD, FD_CLOEXEC);
558
int acceptedDescriptor = ::accept(socketDescriptor, 0, 0);
560
int acceptedDescriptor = qt_safe_accept(socketDescriptor, 0, 0);
562
//check if we have vaild descriptor at all
563
if(acceptedDescriptor > 0) {
564
// Ensure that the socket is closed on exec*()
565
::fcntl(acceptedDescriptor, F_SETFD, FD_CLOEXEC);
569
qWarning("QNativeSocketEnginePrivate::nativeAccept() - acceptedDescriptor <= 0");
502
573
return acceptedDescriptor;
508
579
// gives shorter than true amounts on Unix domain sockets.
509
580
qint64 available = 0;
510
if (::ioctl(socketDescriptor, FIONREAD, (char *) &nbytes) >= 0)
582
if (::ioctl(socketDescriptor, FIONREAD, (char *) &nbytes) >= 0)
584
if (qt_safe_ioctl(socketDescriptor, FIONREAD, (char *) &nbytes) >= 0)
511
586
available = (qint64) nbytes;
513
588
#if defined (QNATIVESOCKETENGINE_DEBUG)
621
qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const
624
::ioctl(socketDescriptor, E32IONREAD, (char *) &nbytes);
625
return qint64(nbytes-28);
545
628
qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const
547
630
QVarLengthArray<char, 8192> udpMessagePeekBuffer(8192);
548
631
ssize_t recvResult = -1;
550
634
// the data written to udpMessagePeekBuffer is discarded, so
551
635
// this function is still reentrant although it might not look
553
637
recvResult = ::recv(socketDescriptor, udpMessagePeekBuffer.data(),
554
udpMessagePeekBuffer.size(), MSG_PEEK);
638
udpMessagePeekBuffer.size(), MSG_PEEK);
555
639
if (recvResult == -1 && errno == EINTR)
609
693
#if !defined(QT_NO_IPV6)
610
694
struct sockaddr_in6 sockAddrIPv6;
611
695
if (host.protocol() == QAbstractSocket::IPv6Protocol) {
612
memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6));
613
sockAddrIPv6.sin6_family = AF_INET6;
614
sockAddrIPv6.sin6_port = htons(port);
696
memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6));
697
sockAddrIPv6.sin6_family = AF_INET6;
698
sockAddrIPv6.sin6_port = htons(port);
616
Q_IPV6ADDR tmp = host.toIPv6Address();
617
memcpy(&sockAddrIPv6.sin6_addr.s6_addr, &tmp, sizeof(tmp));
618
sockAddrSize = sizeof(sockAddrIPv6);
619
sockAddrPtr = (struct sockaddr *)&sockAddrIPv6;
700
Q_IPV6ADDR tmp = host.toIPv6Address();
701
memcpy(&sockAddrIPv6.sin6_addr.s6_addr, &tmp, sizeof(tmp));
702
sockAddrSize = sizeof(sockAddrIPv6);
703
sockAddrPtr = (struct sockaddr *)&sockAddrIPv6;
622
706
if (host.protocol() == QAbstractSocket::IPv4Protocol) {
623
memset(&sockAddrIPv4, 0, sizeof(sockAddrIPv4));
624
sockAddrIPv4.sin_family = AF_INET;
625
sockAddrIPv4.sin_port = htons(port);
626
sockAddrIPv4.sin_addr.s_addr = htonl(host.toIPv4Address());
627
sockAddrSize = sizeof(sockAddrIPv4);
628
sockAddrPtr = (struct sockaddr *)&sockAddrIPv4;
707
memset(&sockAddrIPv4, 0, sizeof(sockAddrIPv4));
708
sockAddrIPv4.sin_family = AF_INET;
709
sockAddrIPv4.sin_port = htons(port);
710
sockAddrIPv4.sin_addr.s_addr = htonl(host.toIPv4Address());
711
sockAddrSize = sizeof(sockAddrIPv4);
712
sockAddrPtr = (struct sockaddr *)&sockAddrIPv4;
631
715
// ignore the SIGPIPE signal
632
716
qt_ignore_sigpipe();
636
sentBytes = ::sendto(socketDescriptor, data, len,
637
0, sockAddrPtr, sockAddrSize);
638
} while (sentBytes == -1 && errno == EINTR);
718
ssize_t sentBytes = ::sendto(socketDescriptor, data, len,
719
0, sockAddrPtr, sockAddrSize);
721
ssize_t sentBytes = qt_safe_sendto(socketDescriptor, data, len,
722
0, sockAddrPtr, sockAddrSize);
640
725
if (sentBytes < 0) {
746
836
// of an interrupting signal.
747
837
ssize_t writtenBytes;
749
writtenBytes = ::write(socketDescriptor, data, len);
840
writtenBytes = ::write(socketDescriptor, data, len);
842
writtenBytes = qt_safe_write(socketDescriptor, data, len);
844
// writtenBytes = QT_WRITE(socketDescriptor, data, len); ### TODO S60: Should this line be removed or the one above it?
750
845
} while (writtenBytes < 0 && errno == EINTR);
752
847
if (writtenBytes < 0) {
833
938
tv.tv_sec = timeout / 1000;
834
939
tv.tv_usec = (timeout % 1000) * 1000;
943
FD_ZERO(&fdexception);
944
FD_SET(socketDescriptor, &fdexception);
842
retval = select(socketDescriptor + 1, &fds, 0, 0, timeout < 0 ? 0 : &tv);
844
retval = select(socketDescriptor + 1, 0, &fds, 0, timeout < 0 ? 0 : &tv);
846
if (retval != -1 || errno != EINTR)
850
// recalculate the timeout
851
int t = timeout - timer.elapsed();
853
// oops, timeout turned negative?
950
retval = ::select(socketDescriptor + 1, &fds, 0, &fdexception, timeout < 0 ? 0 : &tv);
952
retval = qt_safe_select(socketDescriptor + 1, &fds, 0, 0, timeout < 0 ? 0 : &tv);
956
retval = ::select(socketDescriptor + 1, 0, &fds, &fdexception, timeout < 0 ? 0 : &tv);
958
retval = qt_safe_select(socketDescriptor + 1, 0, &fds, 0, timeout < 0 ? 0 : &tv);
963
bool selectForExec = false;
966
qWarning("nativeSelect(....) returned < 0 for socket %d", socketDescriptor);
858
tv.tv_sec = t / 1000;
859
tv.tv_usec = (t % 1000) * 1000;
968
selectForExec = FD_ISSET(socketDescriptor, &fdexception);
971
qWarning("nativeSelect (selectForRead %d, retVal %d, errno %d) Unexpected exception for fd %d",
972
selectForRead, retval, errno, socketDescriptor);
866
979
int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite,
867
bool *selectForRead, bool *selectForWrite) const
980
bool *selectForRead, bool *selectForWrite) const
870
983
FD_ZERO(&fdread);
877
990
FD_SET(socketDescriptor, &fdwrite);
994
FD_ZERO(&fdexception);
995
FD_SET(socketDescriptor, &fdexception);
879
998
struct timeval tv;
880
999
tv.tv_sec = timeout / 1000;
881
1000
tv.tv_usec = (timeout % 1000) * 1000;
1003
#ifndef Q_OS_SYMBIAN
1004
ret = qt_safe_select(socketDescriptor + 1, &fdread, &fdwrite, 0, timeout < 0 ? 0 : &tv);
888
ret = select(socketDescriptor + 1, &fdread, &fdwrite, 0, timeout < 0 ? 0 : &tv);
889
if (ret != -1 || errno != EINTR)
1010
ret = ::select(socketDescriptor + 1, &fdread, &fdwrite, &fdexception, timeout < 0 ? 0 : &tv);
1011
bool selectForExec = false;
1014
qWarning("nativeSelect(....) returned < 0 for socket %d", socketDescriptor);
1016
selectForExec = FD_ISSET(socketDescriptor, &fdexception);
1019
qWarning("nativeSelect (checkRead %d, checkWrite %d, ret %d, errno %d): Unexpected expectfds ready in fd %d",
1020
checkRead, checkWrite, ret, errno, socketDescriptor);
1022
FD_CLR(socketDescriptor, &fdread);
1023
FD_SET(socketDescriptor, &fdwrite);
1024
} else if (checkRead)
1025
FD_SET(socketDescriptor, &fdread);
1028
if ((ret == -1) && ( errno == ECONNREFUSED || errno == EPIPE ))
1033
if (ret != -1 || errno != EINTR) {
892
1037
if (timeout > 0) {
893
1038
// recalculate the timeout