source: trunk/src/network/socket/qnativesocketengine_unix.cpp@ 5

Last change on this file since 5 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 29.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtNetwork module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
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.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
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
26** package.
27**
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.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42//#define QNATIVESOCKETENGINE_DEBUG
43
44#include "qnativesocketengine_p.h"
45#include "qiodevice.h"
46#include "qhostaddress.h"
47#include "qvarlengtharray.h"
48#include "qdatetime.h"
49#include <time.h>
50#include <errno.h>
51#include <fcntl.h>
52#ifndef QT_NO_IPV6IFNAME
53#include <net/if.h>
54#endif
55#ifndef QT_NO_IPV6IFNAME
56#include <net/if.h>
57#endif
58#ifdef QT_LINUXBASE
59#include <arpa/inet.h>
60#endif
61
62#if defined QNATIVESOCKETENGINE_DEBUG
63#include <qstring.h>
64#include <ctype.h>
65#endif
66
67QT_BEGIN_NAMESPACE
68
69#if defined QNATIVESOCKETENGINE_DEBUG
70
71/*
72 Returns a human readable representation of the first \a len
73 characters in \a data.
74*/
75static QByteArray qt_prettyDebug(const char *data, int len, int maxSize)
76{
77 if (!data) return "(null)";
78 QByteArray out;
79 for (int i = 0; i < len; ++i) {
80 char c = data[i];
81 if (isprint(c)) {
82 out += c;
83 } else switch (c) {
84 case '\n': out += "\\n"; break;
85 case '\r': out += "\\r"; break;
86 case '\t': out += "\\t"; break;
87 default:
88 QString tmp;
89 tmp.sprintf("\\%o", c);
90 out += tmp.toLatin1();
91 }
92 }
93
94 if (len < maxSize)
95 out += "...";
96
97 return out;
98}
99#endif
100
101static void qt_ignore_sigpipe()
102{
103 // Set to ignore SIGPIPE once only.
104 static QBasicAtomicInt atom = Q_BASIC_ATOMIC_INITIALIZER(0);
105 if (atom.testAndSetRelaxed(0, 1)) {
106 struct sigaction noaction;
107 memset(&noaction, 0, sizeof(noaction));
108 noaction.sa_handler = SIG_IGN;
109 ::sigaction(SIGPIPE, &noaction, 0);
110 }
111}
112
113/*
114 Extracts the port and address from a sockaddr, and stores them in
115 \a port and \a addr if they are non-null.
116*/
117static inline void qt_socket_getPortAndAddress(struct sockaddr *sa, quint16 *port, QHostAddress *addr)
118{
119#if !defined(QT_NO_IPV6)
120 if (sa->sa_family == AF_INET6) {
121 struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
122 Q_IPV6ADDR tmp;
123 memcpy(&tmp, &sa6->sin6_addr.s6_addr, sizeof(tmp));
124 if (addr) {
125 QHostAddress tmpAddress;
126 tmpAddress.setAddress(tmp);
127 *addr = tmpAddress;
128#ifndef QT_NO_IPV6IFNAME
129 char scopeid[IFNAMSIZ];
130 if (::if_indextoname(sa6->sin6_scope_id, scopeid) > 0) {
131 addr->setScopeId(QLatin1String(scopeid));
132 } else
133#endif
134 addr->setScopeId(QString::number(sa6->sin6_scope_id));
135 }
136 if (port)
137 *port = ntohs(sa6->sin6_port);
138 return;
139 }
140#endif
141 struct sockaddr_in *sa4 = (struct sockaddr_in *)sa;
142 if (port)
143 *port = ntohs(sa4->sin_port);
144 if (addr) {
145 QHostAddress tmpAddress;
146 tmpAddress.setAddress(ntohl(sa4->sin_addr.s_addr));
147 *addr = tmpAddress;
148 }
149}
150
151/*! \internal
152
153 Creates and returns a new socket descriptor of type \a socketType
154 and \a socketProtocol. Returns -1 on failure.
155*/
156bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType,
157 QAbstractSocket::NetworkLayerProtocol socketProtocol)
158{
159#ifndef QT_NO_IPV6
160 int protocol = (socketProtocol == QAbstractSocket::IPv6Protocol) ? AF_INET6 : AF_INET;
161#else
162 Q_UNUSED(socketProtocol);
163 int protocol = AF_INET;
164#endif
165 int type = (socketType == QAbstractSocket::UdpSocket) ? SOCK_DGRAM : SOCK_STREAM;
166 int socket = qt_socket_socket(protocol, type, 0);
167
168 if (socket <= 0) {
169 switch (errno) {
170 case EPROTONOSUPPORT:
171 case EAFNOSUPPORT:
172 case EINVAL:
173 setError(QAbstractSocket::UnsupportedSocketOperationError, ProtocolUnsupportedErrorString);
174 break;
175 case ENFILE:
176 case EMFILE:
177 case ENOBUFS:
178 case ENOMEM:
179 setError(QAbstractSocket::SocketResourceError, ResourceErrorString);
180 break;
181 case EACCES:
182 setError(QAbstractSocket::SocketAccessError, AccessErrorString);
183 break;
184 default:
185 break;
186 }
187
188 return false;
189 }
190
191 // Ensure that the socket is closed on exec*().
192 ::fcntl(socket, F_SETFD, FD_CLOEXEC);
193 socketDescriptor = socket;
194 return true;
195}
196
197/*
198 Returns the value of the socket option \a opt.
199*/
200int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) const
201{
202 Q_Q(const QNativeSocketEngine);
203 if (!q->isValid())
204 return -1;
205
206 int n = -1;
207 switch (opt) {
208 case QNativeSocketEngine::ReceiveBufferSocketOption:
209 n = SO_RCVBUF;
210 break;
211 case QNativeSocketEngine::SendBufferSocketOption:
212 n = SO_SNDBUF;
213 break;
214 case QNativeSocketEngine::NonBlockingSocketOption:
215 break;
216 case QNativeSocketEngine::BroadcastSocketOption:
217 break;
218 case QNativeSocketEngine::AddressReusable:
219 n = SO_REUSEADDR;
220 break;
221 case QNativeSocketEngine::BindExclusively:
222 return true;
223 case QNativeSocketEngine::ReceiveOutOfBandData:
224 n = SO_OOBINLINE;
225 break;
226 }
227
228 int v = -1;
229 QT_SOCKOPTLEN_T len = sizeof(v);
230 if (getsockopt(socketDescriptor, SOL_SOCKET, n, (char *) &v, &len) != -1)
231 return v;
232 return -1;
233}
234
235
236/*
237 Sets the socket option \a opt to \a v.
238*/
239bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt, int v)
240{
241 Q_Q(QNativeSocketEngine);
242 if (!q->isValid())
243 return false;
244
245 int n = 0;
246 switch (opt) {
247 case QNativeSocketEngine::ReceiveBufferSocketOption:
248 n = SO_RCVBUF;
249 break;
250 case QNativeSocketEngine::SendBufferSocketOption:
251 n = SO_SNDBUF;
252 break;
253 case QNativeSocketEngine::BroadcastSocketOption:
254 n = SO_BROADCAST;
255 break;
256 case QNativeSocketEngine::NonBlockingSocketOption: {
257 // Make the socket nonblocking.
258 int flags = ::fcntl(socketDescriptor, F_GETFL, 0);
259 if (flags == -1) {
260#ifdef QNATIVESOCKETENGINE_DEBUG
261 perror("QNativeSocketEnginePrivate::setOption(): fcntl(F_GETFL) failed");
262#endif
263 return false;
264 }
265 if (::fcntl(socketDescriptor, F_SETFL, flags | O_NONBLOCK) == -1) {
266#ifdef QNATIVESOCKETENGINE_DEBUG
267 perror("QNativeSocketEnginePrivate::setOption(): fcntl(F_SETFL) failed");
268#endif
269 return false;
270 }
271
272 return true;
273 }
274 case QNativeSocketEngine::AddressReusable:
275#ifdef SO_REUSEPORT
276 n = SO_REUSEPORT;
277#else
278 n = SO_REUSEADDR;
279#endif
280 break;
281 case QNativeSocketEngine::BindExclusively:
282 return true;
283 case QNativeSocketEngine::ReceiveOutOfBandData:
284 n = SO_OOBINLINE;
285 break;
286 }
287
288 return ::setsockopt(socketDescriptor, SOL_SOCKET, n, (char *) &v, sizeof(v)) == 0;
289}
290
291bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 port)
292{
293 struct sockaddr_in sockAddrIPv4;
294 struct sockaddr *sockAddrPtr = 0;
295 QT_SOCKLEN_T sockAddrSize = 0;
296
297#if !defined(QT_NO_IPV6)
298 struct sockaddr_in6 sockAddrIPv6;
299
300 if (addr.protocol() == QAbstractSocket::IPv6Protocol) {
301 memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6));
302 sockAddrIPv6.sin6_family = AF_INET6;
303 sockAddrIPv6.sin6_port = htons(port);
304#ifndef QT_NO_IPV6IFNAME
305 sockAddrIPv6.sin6_scope_id = ::if_nametoindex(addr.scopeId().toLatin1().data());
306#else
307 sockAddrIPv6.sin6_scope_id = addr.scopeId().toInt();
308#endif
309 Q_IPV6ADDR ip6 = addr.toIPv6Address();
310 memcpy(&sockAddrIPv6.sin6_addr.s6_addr, &ip6, sizeof(ip6));
311
312 sockAddrSize = sizeof(sockAddrIPv6);
313 sockAddrPtr = (struct sockaddr *) &sockAddrIPv6;
314 } else
315#if 0
316 {}
317#endif
318#endif
319 if (addr.protocol() == QAbstractSocket::IPv4Protocol) {
320 memset(&sockAddrIPv4, 0, sizeof(sockAddrIPv4));
321 sockAddrIPv4.sin_family = AF_INET;
322 sockAddrIPv4.sin_port = htons(port);
323 sockAddrIPv4.sin_addr.s_addr = htonl(addr.toIPv4Address());
324
325 sockAddrSize = sizeof(sockAddrIPv4);
326 sockAddrPtr = (struct sockaddr *) &sockAddrIPv4;
327 } else {
328 // unreachable
329 }
330
331 int connectResult = QT_SOCKET_CONNECT(socketDescriptor, sockAddrPtr, sockAddrSize);
332 if (connectResult == -1) {
333 switch (errno) {
334 case EISCONN:
335 socketState = QAbstractSocket::ConnectedState;
336 break;
337 case ECONNREFUSED:
338 case EINVAL:
339 setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString);
340 socketState = QAbstractSocket::UnconnectedState;
341 break;
342 case ETIMEDOUT:
343 setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString);
344 break;
345 case EHOSTUNREACH:
346 setError(QAbstractSocket::NetworkError, HostUnreachableErrorString);
347 socketState = QAbstractSocket::UnconnectedState;
348 break;
349 case ENETUNREACH:
350 setError(QAbstractSocket::NetworkError, NetworkUnreachableErrorString);
351 socketState = QAbstractSocket::UnconnectedState;
352 break;
353 case EADDRINUSE:
354 setError(QAbstractSocket::NetworkError, AddressInuseErrorString);
355 break;
356 case EINPROGRESS:
357 case EALREADY:
358 setError(QAbstractSocket::UnfinishedSocketOperationError, InvalidSocketErrorString);
359 socketState = QAbstractSocket::ConnectingState;
360 break;
361 case EAGAIN:
362 setError(QAbstractSocket::UnfinishedSocketOperationError, InvalidSocketErrorString);
363 setError(QAbstractSocket::SocketResourceError, ResourceErrorString);
364 break;
365 case EACCES:
366 case EPERM:
367 setError(QAbstractSocket::SocketAccessError, AccessErrorString);
368 socketState = QAbstractSocket::UnconnectedState;
369 break;
370 case EAFNOSUPPORT:
371 case EBADF:
372 case EFAULT:
373 case ENOTSOCK:
374 socketState = QAbstractSocket::UnconnectedState;
375 default:
376 break;
377 }
378
379 if (socketState != QAbstractSocket::ConnectedState) {
380#if defined (QNATIVESOCKETENGINE_DEBUG)
381 qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == false (%s)",
382 addr.toString().toLatin1().constData(), port,
383 socketState == QAbstractSocket::ConnectingState
384 ? "Connection in progress" : socketErrorString.toLatin1().constData());
385#endif
386 return false;
387 }
388 }
389
390#if defined (QNATIVESOCKETENGINE_DEBUG)
391 qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == true",
392 addr.toString().toLatin1().constData(), port);
393#endif
394
395 socketState = QAbstractSocket::ConnectedState;
396 return true;
397}
398
399bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 port)
400{
401 struct sockaddr_in sockAddrIPv4;
402 struct sockaddr *sockAddrPtr = 0;
403 QT_SOCKLEN_T sockAddrSize = 0;
404
405#if !defined(QT_NO_IPV6)
406 struct sockaddr_in6 sockAddrIPv6;
407
408 if (address.protocol() == QAbstractSocket::IPv6Protocol) {
409 memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6));
410 sockAddrIPv6.sin6_family = AF_INET6;
411 sockAddrIPv6.sin6_port = htons(port);
412#ifndef QT_NO_IPV6IFNAME
413 sockAddrIPv6.sin6_scope_id = ::if_nametoindex(address.scopeId().toLatin1().data());
414#else
415 sockAddrIPv6.sin6_scope_id = address.scopeId().toInt();
416#endif
417 Q_IPV6ADDR tmp = address.toIPv6Address();
418 memcpy(&sockAddrIPv6.sin6_addr.s6_addr, &tmp, sizeof(tmp));
419 sockAddrSize = sizeof(sockAddrIPv6);
420 sockAddrPtr = (struct sockaddr *) &sockAddrIPv6;
421 } else
422#endif
423 if (address.protocol() == QAbstractSocket::IPv4Protocol) {
424 memset(&sockAddrIPv4, 0, sizeof(sockAddrIPv4));
425 sockAddrIPv4.sin_family = AF_INET;
426 sockAddrIPv4.sin_port = htons(port);
427 sockAddrIPv4.sin_addr.s_addr = htonl(address.toIPv4Address());
428 sockAddrSize = sizeof(sockAddrIPv4);
429 sockAddrPtr = (struct sockaddr *) &sockAddrIPv4;
430 } else {
431 // unreachable
432 }
433
434 int bindResult = QT_SOCKET_BIND(socketDescriptor, sockAddrPtr, sockAddrSize);
435 if (bindResult < 0) {
436 switch(errno) {
437 case EADDRINUSE:
438 setError(QAbstractSocket::AddressInUseError, AddressInuseErrorString);
439 break;
440 case EACCES:
441 setError(QAbstractSocket::SocketAccessError, AddressProtectedErrorString);
442 break;
443 case EINVAL:
444 setError(QAbstractSocket::UnsupportedSocketOperationError, OperationUnsupportedErrorString);
445 break;
446 case EADDRNOTAVAIL:
447 setError(QAbstractSocket::SocketAddressNotAvailableError, AddressNotAvailableErrorString);
448 break;
449 default:
450 break;
451 }
452
453#if defined (QNATIVESOCKETENGINE_DEBUG)
454 qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == false (%s)",
455 address.toString().toLatin1().constData(), port, socketErrorString.toLatin1().constData());
456#endif
457
458 return false;
459 }
460
461#if defined (QNATIVESOCKETENGINE_DEBUG)
462 qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == true",
463 address.toString().toLatin1().constData(), port);
464#endif
465 socketState = QAbstractSocket::BoundState;
466 return true;
467}
468
469bool QNativeSocketEnginePrivate::nativeListen(int backlog)
470{
471 if (qt_socket_listen(socketDescriptor, backlog) < 0) {
472 switch (errno) {
473 case EADDRINUSE:
474 setError(QAbstractSocket::AddressInUseError,
475 PortInuseErrorString);
476 break;
477 default:
478 break;
479 }
480
481#if defined (QNATIVESOCKETENGINE_DEBUG)
482 qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == false (%s)",
483 backlog, socketErrorString.toLatin1().constData());
484#endif
485 return false;
486 }
487
488#if defined (QNATIVESOCKETENGINE_DEBUG)
489 qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == true", backlog);
490#endif
491
492 socketState = QAbstractSocket::ListeningState;
493 return true;
494}
495
496int QNativeSocketEnginePrivate::nativeAccept()
497{
498 int acceptedDescriptor = qt_socket_accept(socketDescriptor, 0, 0);
499#if defined (QNATIVESOCKETENGINE_DEBUG)
500 qDebug("QNativeSocketEnginePrivate::nativeAccept() == %i", acceptedDescriptor);
501#endif
502 // Ensure that the socket is closed on exec*()
503 ::fcntl(acceptedDescriptor, F_SETFD, FD_CLOEXEC);
504 return acceptedDescriptor;
505}
506
507qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const
508{
509 /*
510 Apparently, there is not consistency among different operating
511 systems on how to use FIONREAD.
512
513 FreeBSD, Linux and Solaris all expect the 3rd argument to
514 ioctl() to be an int, which is normally 32-bit even on 64-bit
515 machines.
516
517 IRIX, on the other hand, expects a size_t, which is 64-bit on
518 64-bit machines.
519
520 So, the solution is to use size_t initialized to zero to make
521 sure all bits are set to zero, preventing underflow with the
522 FreeBSD/Linux/Solaris ioctls.
523 */
524 size_t nbytes = 0;
525 // gives shorter than true amounts on Unix domain sockets.
526 qint64 available = 0;
527 if (::ioctl(socketDescriptor, FIONREAD, (char *) &nbytes) >= 0)
528 available = (qint64) *((int *) &nbytes);
529
530#if defined (QNATIVESOCKETENGINE_DEBUG)
531 qDebug("QNativeSocketEnginePrivate::nativeBytesAvailable() == %lli", available);
532#endif
533 return available;
534}
535
536bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const
537{
538 // Create a sockaddr struct and reset its port number.
539#if !defined(QT_NO_IPV6)
540 struct sockaddr_storage storage;
541 sockaddr_in6 *storagePtrIPv6 = reinterpret_cast<sockaddr_in6 *>(&storage);
542 storagePtrIPv6->sin6_port = 0;
543#else
544 struct sockaddr storage;
545#endif
546 sockaddr *storagePtr = reinterpret_cast<sockaddr *>(&storage);
547 storagePtr->sa_family = 0;
548
549 sockaddr_in *storagePtrIPv4 = reinterpret_cast<sockaddr_in *>(&storage);
550 storagePtrIPv4->sin_port = 0;
551 QT_SOCKLEN_T storageSize = sizeof(storage);
552
553 // Peek 0 bytes into the next message. The size of the message may
554 // well be 0, so we can't check recvfrom's return value.
555 ssize_t readBytes;
556 do {
557 char c;
558 readBytes = ::recvfrom(socketDescriptor, &c, 1, MSG_PEEK, storagePtr, &storageSize);
559 } while (readBytes == -1 && errno == EINTR);
560
561 // If there's no error, or if our buffer was too small, there must be a
562 // pending datagram.
563 bool result = (readBytes != -1) || errno == EMSGSIZE;
564
565#if defined (QNATIVESOCKETENGINE_DEBUG)
566 qDebug("QNativeSocketEnginePrivate::nativeHasPendingDatagrams() == %s",
567 result ? "true" : "false");
568#endif
569 return result;
570}
571
572qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const
573{
574 QVarLengthArray<char, 8192> udpMessagePeekBuffer(8192);
575 ssize_t recvResult = -1;
576 for (;;) {
577 // the data written to udpMessagePeekBuffer is discarded, so
578 // this function is still reentrant although it might not look
579 // so.
580 recvResult = ::recv(socketDescriptor, udpMessagePeekBuffer.data(),
581 udpMessagePeekBuffer.size(), MSG_PEEK);
582 if (recvResult == -1 && errno == EINTR)
583 continue;
584
585 if (recvResult != (ssize_t) udpMessagePeekBuffer.size())
586 break;
587
588 udpMessagePeekBuffer.resize(udpMessagePeekBuffer.size() * 2);
589 }
590
591#if defined (QNATIVESOCKETENGINE_DEBUG)
592 qDebug("QNativeSocketEnginePrivate::nativePendingDatagramSize() == %i", recvResult);
593#endif
594
595 return qint64(recvResult);
596}
597
598qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize,
599 QHostAddress *address, quint16 *port)
600{
601#if !defined(QT_NO_IPV6)
602 struct sockaddr_storage aa;
603#else
604 struct sockaddr_in aa;
605#endif
606 memset(&aa, 0, sizeof(aa));
607 QT_SOCKLEN_T sz;
608 sz = sizeof(aa);
609
610 ssize_t recvFromResult = 0;
611 do {
612 char c;
613 recvFromResult = ::recvfrom(socketDescriptor, maxSize ? data : &c, maxSize ? maxSize : 1,
614 0, (struct sockaddr *)&aa, &sz);
615 } while (recvFromResult == -1 && errno == EINTR);
616
617 if (recvFromResult == -1) {
618 setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString);
619 } else if (port || address) {
620 qt_socket_getPortAndAddress((struct sockaddr *) &aa, port, address);
621 }
622
623#if defined (QNATIVESOCKETENGINE_DEBUG)
624 qDebug("QNativeSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %lli, %s, %i) == %lli",
625 data, qt_prettyDebug(data, qMin(recvFromResult, ssize_t(16)), recvFromResult).data(), maxSize,
626 address ? address->toString().toLatin1().constData() : "(nil)",
627 port ? *port : 0, (qint64) recvFromResult);
628#endif
629
630 return qint64(maxSize ? recvFromResult : recvFromResult == -1 ? -1 : 0);
631}
632
633qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len,
634 const QHostAddress &host, quint16 port)
635{
636 struct sockaddr_in sockAddrIPv4;
637 struct sockaddr *sockAddrPtr = 0;
638 QT_SOCKLEN_T sockAddrSize = 0;
639
640#if !defined(QT_NO_IPV6)
641 struct sockaddr_in6 sockAddrIPv6;
642 if (host.protocol() == QAbstractSocket::IPv6Protocol) {
643 memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6));
644 sockAddrIPv6.sin6_family = AF_INET6;
645 sockAddrIPv6.sin6_port = htons(port);
646
647 Q_IPV6ADDR tmp = host.toIPv6Address();
648 memcpy(&sockAddrIPv6.sin6_addr.s6_addr, &tmp, sizeof(tmp));
649 sockAddrSize = sizeof(sockAddrIPv6);
650 sockAddrPtr = (struct sockaddr *)&sockAddrIPv6;
651 } else
652#endif
653 if (host.protocol() == QAbstractSocket::IPv4Protocol) {
654 memset(&sockAddrIPv4, 0, sizeof(sockAddrIPv4));
655 sockAddrIPv4.sin_family = AF_INET;
656 sockAddrIPv4.sin_port = htons(port);
657 sockAddrIPv4.sin_addr.s_addr = htonl(host.toIPv4Address());
658 sockAddrSize = sizeof(sockAddrIPv4);
659 sockAddrPtr = (struct sockaddr *)&sockAddrIPv4;
660 }
661
662 // ignore the SIGPIPE signal
663 qt_ignore_sigpipe();
664
665 ssize_t sentBytes;
666 do {
667 sentBytes = ::sendto(socketDescriptor, data, len,
668 0, sockAddrPtr, sockAddrSize);
669 } while (sentBytes == -1 && errno == EINTR);
670
671 if (sentBytes < 0) {
672 switch (errno) {
673 case EMSGSIZE:
674 setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString);
675 break;
676 default:
677 setError(QAbstractSocket::NetworkError, SendDatagramErrorString);
678 }
679 }
680
681#if defined (QNATIVESOCKETENGINE_DEBUG)
682 qDebug("QNativeSocketEngine::sendDatagram(%p \"%s\", %lli, \"%s\", %i) == %lli", data,
683 qt_prettyDebug(data, qMin<int>(len, 16), len).data(), len, host.toString().toLatin1().constData(),
684 port, (qint64) sentBytes);
685#endif
686
687 return qint64(sentBytes);
688}
689
690bool QNativeSocketEnginePrivate::fetchConnectionParameters()
691{
692 localPort = 0;
693 localAddress.clear();
694 peerPort = 0;
695 peerAddress.clear();
696
697 if (socketDescriptor == -1)
698 return false;
699
700#if !defined(QT_NO_IPV6)
701 struct sockaddr_storage sa;
702#else
703 struct sockaddr_in sa;
704#endif
705 struct sockaddr *sockAddrPtr = (struct sockaddr *) &sa;
706 QT_SOCKLEN_T sockAddrSize = sizeof(sa);
707
708 // Determine local address
709 memset(&sa, 0, sizeof(sa));
710 if (::getsockname(socketDescriptor, sockAddrPtr, &sockAddrSize) == 0) {
711 qt_socket_getPortAndAddress(sockAddrPtr, &localPort, &localAddress);
712
713 // Determine protocol family
714 switch (sockAddrPtr->sa_family) {
715 case AF_INET:
716 socketProtocol = QAbstractSocket::IPv4Protocol;
717 break;
718#if !defined (QT_NO_IPV6)
719 case AF_INET6:
720 socketProtocol = QAbstractSocket::IPv6Protocol;
721 break;
722#endif
723 default:
724 socketProtocol = QAbstractSocket::UnknownNetworkLayerProtocol;
725 break;
726 }
727
728 } else if (errno == EBADF) {
729 setError(QAbstractSocket::UnsupportedSocketOperationError, InvalidSocketErrorString);
730 return false;
731 }
732
733 // Determine the remote address
734 if (!::getpeername(socketDescriptor, sockAddrPtr, &sockAddrSize))
735 qt_socket_getPortAndAddress(sockAddrPtr, &peerPort, &peerAddress);
736
737 // Determine the socket type (UDP/TCP)
738 int value = 0;
739 QT_SOCKOPTLEN_T valueSize = sizeof(int);
740 if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_TYPE, &value, &valueSize) == 0) {
741 if (value == SOCK_STREAM)
742 socketType = QAbstractSocket::TcpSocket;
743 else if (value == SOCK_DGRAM)
744 socketType = QAbstractSocket::UdpSocket;
745 else
746 socketType = QAbstractSocket::UnknownSocketType;
747 }
748#if defined (QNATIVESOCKETENGINE_DEBUG)
749 QString socketProtocolStr = "UnknownProtocol";
750 if (socketProtocol == QAbstractSocket::IPv4Protocol) socketProtocolStr = "IPv4Protocol";
751 else if (socketProtocol == QAbstractSocket::IPv6Protocol) socketProtocolStr = "IPv6Protocol";
752
753 QString socketTypeStr = "UnknownSocketType";
754 if (socketType == QAbstractSocket::TcpSocket) socketTypeStr = "TcpSocket";
755 else if (socketType == QAbstractSocket::UdpSocket) socketTypeStr = "UdpSocket";
756
757 qDebug("QNativeSocketEnginePrivate::fetchConnectionParameters() local == %s:%i,"
758 " peer == %s:%i, socket == %s - %s",
759 localAddress.toString().toLatin1().constData(), localPort,
760 peerAddress.toString().toLatin1().constData(), peerPort,socketTypeStr.toLatin1().constData(),
761 socketProtocolStr.toLatin1().constData());
762#endif
763 return true;
764}
765
766void QNativeSocketEnginePrivate::nativeClose()
767{
768#if defined (QNATIVESOCKETENGINE_DEBUG)
769 qDebug("QNativeSocketEngine::nativeClose()");
770#endif
771 ::close(socketDescriptor);
772}
773
774qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len)
775{
776 Q_Q(QNativeSocketEngine);
777
778 // ignore the SIGPIPE signal
779 qt_ignore_sigpipe();
780
781 // loop while ::write() returns -1 and errno == EINTR, in case
782 // of an interrupting signal.
783 ssize_t writtenBytes;
784 do {
785 writtenBytes = ::write(socketDescriptor, data, len);
786 } while (writtenBytes < 0 && errno == EINTR);
787
788 if (writtenBytes < 0) {
789 switch (errno) {
790 case EPIPE:
791 case ECONNRESET:
792 writtenBytes = -1;
793 setError(QAbstractSocket::RemoteHostClosedError, RemoteHostClosedErrorString);
794 q->close();
795 break;
796 case EAGAIN:
797 writtenBytes = 0;
798 break;
799 case EMSGSIZE:
800 setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString);
801 break;
802 default:
803 break;
804 }
805 }
806
807#if defined (QNATIVESOCKETENGINE_DEBUG)
808 qDebug("QNativeSocketEnginePrivate::nativeWrite(%p \"%s\", %llu) == %i",
809 data, qt_prettyDebug(data, qMin((int) len, 16),
810 (int) len).data(), len, (int) writtenBytes);
811#endif
812
813 return qint64(writtenBytes);
814}
815/*
816*/
817qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize)
818{
819 Q_Q(QNativeSocketEngine);
820 if (!q->isValid()) {
821 qWarning("QNativeSocketEngine::unbufferedRead: Invalid socket");
822 return -1;
823 }
824
825 ssize_t r = 0;
826 do {
827 r = ::read(socketDescriptor, data, maxSize);
828 } while (r == -1 && errno == EINTR);
829
830 if (r < 0) {
831 r = -1;
832 switch (errno) {
833#if EWOULDBLOCK-0 && EWOULDBLOCK != EAGAIN
834 case EWOULDBLOCK:
835#endif
836 case EAGAIN:
837 // No data was available for reading
838 r = -2;
839 break;
840 case EBADF:
841 case EINVAL:
842 case EIO:
843 setError(QAbstractSocket::NetworkError, ReadErrorString);
844 break;
845 case ECONNRESET:
846 r = 0;
847 break;
848 default:
849 break;
850 }
851 }
852
853#if defined (QNATIVESOCKETENGINE_DEBUG)
854 qDebug("QNativeSocketEnginePrivate::nativeRead(%p \"%s\", %llu) == %i",
855 data, qt_prettyDebug(data, qMin(r, ssize_t(16)), r).data(),
856 maxSize, r);
857#endif
858
859 return qint64(r);
860}
861
862int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const
863{
864 fd_set fds;
865 FD_ZERO(&fds);
866 FD_SET(socketDescriptor, &fds);
867
868 struct timeval tv;
869 tv.tv_sec = timeout / 1000;
870 tv.tv_usec = (timeout % 1000) * 1000;
871
872 QTime timer;
873 timer.start();
874
875 int retval;
876 do {
877 if (selectForRead)
878 retval = select(socketDescriptor + 1, &fds, 0, 0, timeout < 0 ? 0 : &tv);
879 else
880 retval = select(socketDescriptor + 1, 0, &fds, 0, timeout < 0 ? 0 : &tv);
881
882 if (retval != -1 || errno != EINTR)
883 break;
884
885 if (timeout > 0) {
886 // recalculate the timeout
887 int t = timeout - timer.elapsed();
888 if (t < 0) {
889 // oops, timeout turned negative?
890 retval = -1;
891 break;
892 }
893
894 tv.tv_sec = t / 1000;
895 tv.tv_usec = (t % 1000) * 1000;
896 }
897 } while (true);
898
899 return retval;
900}
901
902int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite,
903 bool *selectForRead, bool *selectForWrite) const
904{
905 fd_set fdread;
906 FD_ZERO(&fdread);
907 if (checkRead)
908 FD_SET(socketDescriptor, &fdread);
909
910 fd_set fdwrite;
911 FD_ZERO(&fdwrite);
912 if (checkWrite)
913 FD_SET(socketDescriptor, &fdwrite);
914
915 struct timeval tv;
916 tv.tv_sec = timeout / 1000;
917 tv.tv_usec = (timeout % 1000) * 1000;
918
919 QTime timer;
920 timer.start();
921
922 int ret;
923 do {
924 ret = select(socketDescriptor + 1, &fdread, &fdwrite, 0, timeout < 0 ? 0 : &tv);
925 if (ret != -1 || errno != EINTR)
926 break;
927
928 if (timeout > 0) {
929 // recalculate the timeout
930 int t = timeout - timer.elapsed();
931 if (t < 0) {
932 // oops, timeout turned negative?
933 ret = -1;
934 break;
935 }
936
937 tv.tv_sec = t / 1000;
938 tv.tv_usec = (t % 1000) * 1000;
939 }
940 } while (true);
941 if (ret <= 0)
942 return ret;
943
944 *selectForRead = FD_ISSET(socketDescriptor, &fdread);
945 *selectForWrite = FD_ISSET(socketDescriptor, &fdwrite);
946 return ret;
947}
948
949QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.