summaryrefslogtreecommitdiffstats
path: root/src/network/socket/qnativesocketengine_unix.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/socket/qnativesocketengine_unix.cpp')
-rw-r--r--src/network/socket/qnativesocketengine_unix.cpp383
1 files changed, 225 insertions, 158 deletions
diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp
index 5cf27ce..39570c8 100644
--- a/src/network/socket/qnativesocketengine_unix.cpp
+++ b/src/network/socket/qnativesocketengine_unix.cpp
@@ -46,6 +46,7 @@
#include "qhostaddress.h"
#include "qelapsedtimer.h"
#include "qvarlengtharray.h"
+#include "qnetworkinterface.h"
#include <time.h>
#include <errno.h>
#include <fcntl.h>
@@ -64,12 +65,7 @@
#include <ctype.h>
#endif
-#ifdef Q_OS_SYMBIAN // ### TODO: Are these headers right?
-#include <sys/socket.h>
-#include <netinet/in.h>
-#else
#include <netinet/tcp.h>
-#endif
QT_BEGIN_NAMESPACE
@@ -173,11 +169,8 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc
int protocol = AF_INET;
#endif
int type = (socketType == QAbstractSocket::UdpSocket) ? SOCK_DGRAM : SOCK_STREAM;
-#ifdef Q_OS_SYMBIAN
- int socket = ::socket(protocol, type, 0);
-#else
+
int socket = qt_safe_socket(protocol, type, 0);
-#endif
if (socket <= 0) {
switch (errno) {
@@ -244,6 +237,30 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co
case QNativeSocketEngine::KeepAliveOption:
n = SO_KEEPALIVE;
break;
+ case QNativeSocketEngine::MulticastTtlOption:
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ level = IPPROTO_IPV6;
+ n = IPV6_MULTICAST_HOPS;
+ } else
+#endif
+ {
+ level = IPPROTO_IP;
+ n = IP_MULTICAST_TTL;
+ }
+ break;
+ case QNativeSocketEngine::MulticastLoopbackOption:
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ level = IPPROTO_IPV6;
+ n = IPV6_MULTICAST_LOOP;
+ } else
+#endif
+ {
+ level = IPPROTO_IP;
+ n = IP_MULTICAST_LOOP;
+ }
+ break;
}
int v = -1;
@@ -295,11 +312,9 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt
}
#else // Q_OS_VXWORKS
int onoff = 1;
-#ifdef Q_OS_SYMBIAN
- if (::ioctl(socketDescriptor, FIONBIO, &onoff) < 0) {
-#else
+
if (qt_safe_ioctl(socketDescriptor, FIONBIO, &onoff) < 0) {
-#endif
+
#ifdef QNATIVESOCKETENGINE_DEBUG
perror("QNativeSocketEnginePrivate::setOption(): ioctl(FIONBIO, 1) failed");
#endif
@@ -309,7 +324,7 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt
return true;
}
case QNativeSocketEngine::AddressReusable:
-#if defined(SO_REUSEPORT) && !defined(Q_OS_SYMBIAN)
+#if defined(SO_REUSEPORT)
n = SO_REUSEPORT;
#else
n = SO_REUSEADDR;
@@ -327,6 +342,30 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt
case QNativeSocketEngine::KeepAliveOption:
n = SO_KEEPALIVE;
break;
+ case QNativeSocketEngine::MulticastTtlOption:
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ level = IPPROTO_IPV6;
+ n = IPV6_MULTICAST_HOPS;
+ } else
+#endif
+ {
+ level = IPPROTO_IP;
+ n = IP_MULTICAST_TTL;
+ }
+ break;
+ case QNativeSocketEngine::MulticastLoopbackOption:
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ level = IPPROTO_IPV6;
+ n = IPV6_MULTICAST_LOOP;
+ } else
+#endif
+ {
+ level = IPPROTO_IP;
+ n = IP_MULTICAST_LOOP;
+ }
+ break;
}
return ::setsockopt(socketDescriptor, level, n, (char *) &v, sizeof(v)) == 0;
@@ -378,11 +417,8 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16
} else {
// unreachable
}
-#ifdef Q_OS_SYMBIAN
- int connectResult = ::connect(socketDescriptor, sockAddrPtr, sockAddrSize);
-#else
+
int connectResult = qt_safe_connect(socketDescriptor, sockAddrPtr, sockAddrSize);
-#endif
if (connectResult == -1) {
switch (errno) {
case EISCONN:
@@ -425,9 +461,6 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16
case EBADF:
case EFAULT:
case ENOTSOCK:
-#ifdef Q_OS_SYMBIAN
- case EPIPE:
-#endif
socketState = QAbstractSocket::UnconnectedState;
default:
break;
@@ -526,11 +559,7 @@ bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16
bool QNativeSocketEnginePrivate::nativeListen(int backlog)
{
-#ifdef Q_OS_SYMBIAN
- if (::listen(socketDescriptor, backlog) < 0) {
-#else
if (qt_safe_listen(socketDescriptor, backlog) < 0) {
-#endif
switch (errno) {
case EADDRINUSE:
setError(QAbstractSocket::AddressInUseError,
@@ -557,25 +586,185 @@ bool QNativeSocketEnginePrivate::nativeListen(int backlog)
int QNativeSocketEnginePrivate::nativeAccept()
{
-#ifdef Q_OS_SYMBIAN
- int acceptedDescriptor = ::accept(socketDescriptor, 0, 0);
-#else
int acceptedDescriptor = qt_safe_accept(socketDescriptor, 0, 0);
-#endif
return acceptedDescriptor;
}
+#ifndef QT_NO_NETWORKINTERFACE
+
+static bool multicastMembershipHelper(QNativeSocketEnginePrivate *d,
+ int how6,
+ int how4,
+ const QHostAddress &groupAddress,
+ const QNetworkInterface &interface)
+{
+ int level = 0;
+ int sockOpt = 0;
+ void *sockArg;
+ int sockArgSize;
+
+ ip_mreq mreq4;
+#ifndef QT_NO_IPV6
+ ipv6_mreq mreq6;
+
+ if (groupAddress.protocol() == QAbstractSocket::IPv6Protocol) {
+ level = IPPROTO_IPV6;
+ sockOpt = how6;
+ sockArg = &mreq6;
+ sockArgSize = sizeof(mreq6);
+ memset(&mreq6, 0, sizeof(mreq6));
+ Q_IPV6ADDR ip6 = groupAddress.toIPv6Address();
+ memcpy(&mreq6.ipv6mr_multiaddr, &ip6, sizeof(ip6));
+ mreq6.ipv6mr_interface = interface.index();
+ } else
+#endif
+ if (groupAddress.protocol() == QAbstractSocket::IPv4Protocol) {
+ level = IPPROTO_IP;
+ sockOpt = how4;
+ sockArg = &mreq4;
+ sockArgSize = sizeof(mreq4);
+ memset(&mreq4, 0, sizeof(mreq4));
+ mreq4.imr_multiaddr.s_addr = htonl(groupAddress.toIPv4Address());
+
+ if (interface.isValid()) {
+ QList<QNetworkAddressEntry> addressEntries = interface.addressEntries();
+ if (!addressEntries.isEmpty()) {
+ QHostAddress firstIP = addressEntries.first().ip();
+ mreq4.imr_interface.s_addr = htonl(firstIP.toIPv4Address());
+ } else {
+ d->setError(QAbstractSocket::NetworkError,
+ QNativeSocketEnginePrivate::NetworkUnreachableErrorString);
+ return false;
+ }
+ } else {
+ mreq4.imr_interface.s_addr = INADDR_ANY;
+ }
+ } else {
+ // unreachable
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QNativeSocketEnginePrivate::ProtocolUnsupportedErrorString);
+ return false;
+ }
+
+ int res = setsockopt(d->socketDescriptor, level, sockOpt, sockArg, sockArgSize);
+ if (res == -1) {
+ switch (errno) {
+ case ENOPROTOOPT:
+ d->setError(QAbstractSocket::UnsupportedSocketOperationError,
+ QNativeSocketEnginePrivate::OperationUnsupportedErrorString);
+ break;
+ case EADDRNOTAVAIL:
+ d->setError(QAbstractSocket::SocketAddressNotAvailableError,
+ QNativeSocketEnginePrivate::AddressNotAvailableErrorString);
+ break;
+ default:
+ d->setError(QAbstractSocket::UnknownSocketError,
+ QNativeSocketEnginePrivate::UnknownSocketErrorString);
+ break;
+ }
+ return false;
+ }
+ return true;
+}
+
+bool QNativeSocketEnginePrivate::nativeJoinMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &interface)
+{
+ return multicastMembershipHelper(this,
+#ifndef QT_NO_IPV6
+ IPV6_JOIN_GROUP,
+#else
+ 0,
+#endif
+ IP_ADD_MEMBERSHIP,
+ groupAddress,
+ interface);
+}
+
+bool QNativeSocketEnginePrivate::nativeLeaveMulticastGroup(const QHostAddress &groupAddress,
+ const QNetworkInterface &interface)
+{
+ return multicastMembershipHelper(this,
+#ifndef QT_NO_IPV6
+ IPV6_LEAVE_GROUP,
+#else
+ 0,
+#endif
+ IP_DROP_MEMBERSHIP,
+ groupAddress,
+ interface);
+}
+
+QNetworkInterface QNativeSocketEnginePrivate::nativeMulticastInterface() const
+{
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ uint v;
+ QT_SOCKOPTLEN_T sizeofv = sizeof(v);
+ if (::getsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, &v, &sizeofv) == -1)
+ return QNetworkInterface();
+ return QNetworkInterface::interfaceFromIndex(v);
+ }
+#endif
+
+ struct in_addr v = { 0 };
+ QT_SOCKOPTLEN_T sizeofv = sizeof(v);
+ if (::getsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, &v, &sizeofv) == -1)
+ return QNetworkInterface();
+ if (v.s_addr != 0 && sizeofv >= sizeof(v)) {
+ QHostAddress ipv4(ntohl(v.s_addr));
+ QList<QNetworkInterface> ifaces = QNetworkInterface::allInterfaces();
+ for (int i = 0; i < ifaces.count(); ++i) {
+ const QNetworkInterface &iface = ifaces.at(i);
+ QList<QNetworkAddressEntry> entries = iface.addressEntries();
+ for (int j = 0; j < entries.count(); ++j) {
+ const QNetworkAddressEntry &entry = entries.at(j);
+ if (entry.ip() == ipv4)
+ return iface;
+ }
+ }
+ }
+ return QNetworkInterface();
+}
+
+bool QNativeSocketEnginePrivate::nativeSetMulticastInterface(const QNetworkInterface &iface)
+{
+#ifndef QT_NO_IPV6
+ if (socketProtocol == QAbstractSocket::IPv6Protocol) {
+ uint v = iface.index();
+ return (::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, &v, sizeof(v)) != -1);
+ }
+#endif
+
+ struct in_addr v;
+ if (iface.isValid()) {
+ QList<QNetworkAddressEntry> entries = iface.addressEntries();
+ for (int i = 0; i < entries.count(); ++i) {
+ const QNetworkAddressEntry &entry = entries.at(i);
+ const QHostAddress &ip = entry.ip();
+ if (ip.protocol() == QAbstractSocket::IPv4Protocol) {
+ v.s_addr = htonl(ip.toIPv4Address());
+ int r = ::setsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, &v, sizeof(v));
+ if (r != -1)
+ return true;
+ }
+ }
+ return false;
+ }
+
+ v.s_addr = INADDR_ANY;
+ return (::setsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, &v, sizeof(v)) != -1);
+}
+
+#endif // QT_NO_NETWORKINTERFACE
+
qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const
{
int nbytes = 0;
// gives shorter than true amounts on Unix domain sockets.
qint64 available = 0;
-#ifdef Q_OS_SYMBIAN
- if (::ioctl(socketDescriptor, FIONREAD, (char *) &nbytes) >= 0)
-#else
if (qt_safe_ioctl(socketDescriptor, FIONREAD, (char *) &nbytes) >= 0)
-#endif
available = (qint64) nbytes;
#if defined (QNATIVESOCKETENGINE_DEBUG)
@@ -594,15 +783,10 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const
// Peek 0 bytes into the next message. The size of the message may
// well be 0, so we can't check recvfrom's return value.
ssize_t readBytes;
-#ifdef Q_OS_SYMBIAN
- char c;
- readBytes = ::recvfrom(socketDescriptor, &c, 1, MSG_PEEK, &storage.a, &storageSize);
-#else
do {
char c;
readBytes = ::recvfrom(socketDescriptor, &c, 1, MSG_PEEK, &storage.a, &storageSize);
} while (readBytes == -1 && errno == EINTR);
-#endif
// If there's no error, or if our buffer was too small, there must be a
// pending datagram.
@@ -615,14 +799,6 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const
return result;
}
-#ifdef Q_OS_SYMBIAN
-qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const
-{
- size_t nbytes = 0;
- ::ioctl(socketDescriptor, E32IONREAD, (char *) &nbytes);
- return qint64(nbytes-28);
-}
-#else
qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const
{
QVarLengthArray<char, 8192> udpMessagePeekBuffer(8192);
@@ -649,7 +825,7 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const
return qint64(recvResult);
}
-#endif
+
qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize,
QHostAddress *address, quint16 *port)
{
@@ -659,17 +835,11 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS
sz = sizeof(aa);
ssize_t recvFromResult = 0;
-#ifdef Q_OS_SYMBIAN
- char c;
- recvFromResult = ::recvfrom(socketDescriptor, maxSize ? data : &c, maxSize ? maxSize : 1,
- 0, &aa.a, &sz);
-#else
do {
char c;
recvFromResult = ::recvfrom(socketDescriptor, maxSize ? data : &c, maxSize ? maxSize : 1,
0, &aa.a, &sz);
} while (recvFromResult == -1 && errno == EINTR);
-#endif
if (recvFromResult == -1) {
setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString);
@@ -718,13 +888,8 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l
// ignore the SIGPIPE signal
qt_ignore_sigpipe();
-#ifdef Q_OS_SYMBIAN
- ssize_t sentBytes = ::sendto(socketDescriptor, data, len,
- 0, sockAddrPtr, sockAddrSize);
-#else
ssize_t sentBytes = qt_safe_sendto(socketDescriptor, data, len,
0, sockAddrPtr, sockAddrSize);
-#endif
if (sentBytes < 0) {
switch (errno) {
@@ -822,11 +987,7 @@ void QNativeSocketEnginePrivate::nativeClose()
qDebug("QNativeSocketEngine::nativeClose()");
#endif
-#ifdef Q_OS_SYMBIAN
- ::close(socketDescriptor);
-#else
- qt_safe_close(socketDescriptor);
-#endif
+ qt_safe_close(socketDescriptor);
}
qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len)
@@ -837,12 +998,7 @@ qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len)
qt_ignore_sigpipe();
ssize_t writtenBytes;
-#ifdef Q_OS_SYMBIAN
- // Symbian does not support signals natively and Open C returns EINTR when moving to offline
- writtenBytes = ::write(socketDescriptor, data, len);
-#else
writtenBytes = qt_safe_write(socketDescriptor, data, len);
-#endif
if (writtenBytes < 0) {
switch (errno) {
@@ -877,16 +1033,12 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize)
{
Q_Q(QNativeSocketEngine);
if (!q->isValid()) {
- qWarning("QNativeSocketEngine::unbufferedRead: Invalid socket");
+ qWarning("QNativeSocketEngine::nativeRead: Invalid socket");
return -1;
}
ssize_t r = 0;
-#ifdef Q_OS_SYMBIAN
- r = ::read(socketDescriptor, data, maxSize);
-#else
r = qt_safe_read(socketDescriptor, data, maxSize);
-#endif
if (r < 0) {
r = -1;
@@ -903,9 +1055,6 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize)
case EIO:
//error string is now set in read(), not here in nativeRead()
break;
-#ifdef Q_OS_SYMBIAN
- case EPIPE:
-#endif
case ECONNRESET:
#if defined(Q_OS_VXWORKS)
case ESHUTDOWN:
@@ -936,40 +1085,11 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
-#ifdef Q_OS_SYMBIAN
- fd_set fdexception;
- FD_ZERO(&fdexception);
- FD_SET(socketDescriptor, &fdexception);
-#endif
-
int retval;
if (selectForRead)
-#ifdef Q_OS_SYMBIAN
- retval = ::select(socketDescriptor + 1, &fds, 0, &fdexception, timeout < 0 ? 0 : &tv);
-#else
retval = qt_safe_select(socketDescriptor + 1, &fds, 0, 0, timeout < 0 ? 0 : &tv);
-#endif
else
-#ifdef Q_OS_SYMBIAN
- retval = ::select(socketDescriptor + 1, 0, &fds, &fdexception, timeout < 0 ? 0 : &tv);
-#else
retval = qt_safe_select(socketDescriptor + 1, 0, &fds, 0, timeout < 0 ? 0 : &tv);
-#endif
-
-
-#ifdef Q_OS_SYMBIAN
- bool selectForExec = false;
- if(retval != 0) {
- if(retval < 0) {
- qWarning("nativeSelect(....) returned < 0 for socket %d", socketDescriptor);
- }
- selectForExec = FD_ISSET(socketDescriptor, &fdexception);
- }
- if(selectForExec) {
- qWarning("nativeSelect (selectForRead %d, retVal %d, errno %d) Unexpected exception for fd %d",
- selectForRead, retval, errno, socketDescriptor);
- }
-#endif
return retval;
}
@@ -987,65 +1107,12 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c
if (checkWrite)
FD_SET(socketDescriptor, &fdwrite);
-#ifdef Q_OS_SYMBIAN
- fd_set fdexception;
- FD_ZERO(&fdexception);
- FD_SET(socketDescriptor, &fdexception);
-#endif
-
struct timeval tv;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
int ret;
-#ifndef Q_OS_SYMBIAN
ret = qt_safe_select(socketDescriptor + 1, &fdread, &fdwrite, 0, timeout < 0 ? 0 : &tv);
-#else
- QElapsedTimer timer;
- timer.start();
-
- do {
- ret = ::select(socketDescriptor + 1, &fdread, &fdwrite, &fdexception, timeout < 0 ? 0 : &tv);
- bool selectForExec = false;
- if(ret != 0) {
- if(ret < 0) {
- qWarning("nativeSelect(....) returned < 0 for socket %d", socketDescriptor);
- }
- selectForExec = FD_ISSET(socketDescriptor, &fdexception);
- }
- if(selectForExec) {
- qWarning("nativeSelect (checkRead %d, checkWrite %d, ret %d, errno %d): Unexpected expectfds ready in fd %d",
- checkRead, checkWrite, ret, errno, socketDescriptor);
- if (checkWrite){
- FD_CLR(socketDescriptor, &fdread);
- FD_SET(socketDescriptor, &fdwrite);
- } else if (checkRead)
- FD_SET(socketDescriptor, &fdread);
-
-
- if ((ret == -1) && ( errno == ECONNREFUSED || errno == EPIPE ))
- ret = 1;
-
- }
-
- if (ret != -1 || errno != EINTR) {
- break;
- }
-
- if (timeout > 0) {
- // recalculate the timeout
- int t = timeout - timer.elapsed();
- if (t < 0) {
- // oops, timeout turned negative?
- ret = -1;
- break;
- }
-
- tv.tv_sec = t / 1000;
- tv.tv_usec = (t % 1000) * 1000;
- }
- } while (true);
-#endif
if (ret <= 0)
return ret;