source: trunk/src/network/socket/qnativesocketengine_os2.cpp@ 219

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

network: Implemented QLocalServer/QLocalSocket/QNativeSocketEngine OS/2 bits (basically a copy of the Unix port with IPv6 stuff removed).

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