forked from billkarsh/SpikeGLX
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSockUtil.cpp
249 lines (184 loc) · 5.74 KB
/
SockUtil.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
#include "SockUtil.h"
#include "Util.h"
#if defined(Q_OS_LINUX)
#include <sys/socket.h>
#endif
#include <QHostAddress>
#define LINELEN 65536
void SockUtil::setLowLatency()
{
#if QT_VERSION >= 0x040600
sock->setSocketOption( QAbstractSocket::LowDelayOption, 1 );
#else
socketNoNagle( sock->socketDescriptor() );
#endif
}
const QString &SockUtil::addr()
{
if( _addr.isEmpty() && sock ) {
_addr = QString("(%1:%2)")
.arg( sock->peerAddress().toString() )
.arg( sock->peerPort() );
}
return _addr;
}
// Lowest cost check against unexpected exit of our own comm. thread,
// hence, deletion of its socket. This doesn't test whether the socket
// is valid/connected, see sockValid().
//
bool SockUtil::sockExists()
{
if( !sock ) {
appendError( errOut, "Socket unexpectedly deleted!" );
return false;
}
return true;
}
// A more expensive test for the useability of a socket.
// It is unclear what isValid() really entails, so we
// check that and, perhaps redundantly, the state.
//
bool SockUtil::sockValid()
{
if( !sockExists() )
return false;
if( !sock->isValid() ) {
appendError( errOut, "Socket invalid" );
return false;
}
if( sock->state() != QAbstractSocket::ConnectedState ) {
appendError( errOut, "Socket disconnected" );
return false;
}
return true;
}
bool SockUtil::connectToServer( const QString &host, quint16 port )
{
sock->connectToHost( host, port );
if( !sock->waitForConnected( timeout_ms ) || !sock->isValid() ) {
QString err = errorToString( sock->error() );
appendError( errOut, err );
QString logMsg = QString("Err %1%2 [%3]")
.arg( _tag ).arg( addr() ).arg( err );
if( sock->error() == QAbstractSocket::ConnectionRefusedError )
Debug() << logMsg;
else
Error() << logMsg;
return false;
}
return true;
}
bool SockUtil::send( const QString &msg, bool debugInput )
{
if( debugInput ) {
Debug()
<< "Snd "
<< _tag << addr()
<< " [" << msg.trimmed() << "]";
}
if( !sockExists() )
return false;
sock->write( STR2CHR( msg ) );
if( sock->bytesToWrite()
&& !sock->waitForBytesWritten( timeout_ms ) ) {
appendError( errOut, errorToString( sock->error() ) );
if( autoAbort )
sock->abort();
return false;
}
return true;
}
bool SockUtil::sendBinary( const void* src, qint64 bytes )
{
if( !sockExists() )
return false;
sock->write( (const char*)src, bytes );
if( sock->bytesToWrite()
&& !sock->waitForBytesWritten( timeout_ms ) ) {
appendError( errOut, errorToString( sock->error() ) );
if( autoAbort )
sock->abort();
return false;
}
return true;
}
// Return data string, or,
// return QString::null to signal end of communication.
//
QString SockUtil::readLine()
{
for( int ct = 0; !sock->canReadLine(); ++ct ) {
if( !sockValid() )
return QString::null;
if( !sock->waitForReadyRead( timeout_ms ) || ct >= 3 ) {
QString err;
if( sock->error() != QAbstractSocket::UnknownSocketError )
err = errorToString( sock->error() );
else
err = "timeout or peer shutdown during read";
appendError( errOut, err );
return QString::null;
}
}
return sock->readLine( LINELEN ).trimmed();
}
// Note:
// -----
// Calling sock->error() on a new healthy socket returns value
// QAbstractSocket::UnknownSocketError (-1). Most likely this
// value reflects NO error rather than a mysterious error type.
//
QString SockUtil::errorToString( QAbstractSocket::SocketError e )
{
switch( e ) {
case QAbstractSocket::UnknownSocketError:
return "Application (not socket) error";
case QAbstractSocket::ConnectionRefusedError:
return "Connection refused (or timed out)";
case QAbstractSocket::RemoteHostClosedError:
return "Remote host closed connection";
case QAbstractSocket::HostNotFoundError:
return "Host address not found";
case QAbstractSocket::SocketAccessError:
return "Socket (application) privilege error";
case QAbstractSocket::SocketResourceError:
return "Socket resources exhausted";
case QAbstractSocket::SocketTimeoutError:
return "Socket operation timed out";
case QAbstractSocket::DatagramTooLargeError:
return "Datagram too large";
case QAbstractSocket::AddressInUseError:
return "Bind() address already in use";
case QAbstractSocket::SocketAddressNotAvailableError:
return "Bind() address not on this host";
case QAbstractSocket::UnsupportedSocketOperationError:
return "Socket operation unsupported on this OS";
case QAbstractSocket::ProxyAuthenticationRequiredError:
return "Socket proxy authentication error";
default:
break;
}
return QString("Untranslated socket error (%1)").arg( e );
}
// Append (';;' separated) eNew to existing eDst (if exists).
//
void SockUtil::appendError( QString *eDst, const QString &eNew )
{
if( eDst && !eNew.isEmpty() ) {
if( !eDst->isEmpty() )
eDst->append( ";;" );
eDst->append( eNew );
}
}
#if defined(Q_OS_LINUX)
void SockUtil::shutdown( QTcpSocket *sock )
{
//#define SHUT_RDWR 2
if( sock && sock->state() == QAbstractSocket::ConnectedState )
shutdown( sock->socketDescriptor(), SHUT_RDWR );
}
#else
void SockUtil::shutdown( QTcpSocket * )
{
}
#endif