• R/O
  • SSH
  • HTTPS

tidesnet: Commit


Commit MetaInfo

Revision83 (tree)
Time2020-05-02 00:08:19
Authorquiret

Log Message

- added error codes for socket routines
- reimplemented errno capabilities to certain socket routines because errno became reliable
- reliability upgrades to socket routines related to attack vectors

Change Summary

Incremental Difference

--- library/include/tidesnet/errorsys.h (revision 82)
+++ library/include/tidesnet/errorsys.h (revision 83)
@@ -15,21 +15,59 @@
1515
1616 _NS_BEGIN_TIDESNET
1717
18+// Global error codes for exceptions.
19+enum class eNetExceptCode
20+{
21+ // *** generic.
22+ UNKNOWN_ERROR, // an unknown internal error.
23+ INTERNAL_ERROR, // a known internal error.
24+ MEMORY_EXHAUSTED, // request for memory was denied.
25+ NOT_INITIALIZED, // attempt to use an uninitialized structure in an invalid state.
26+ NETWORK_DOWN, // the network appears to have dropped thus the call could not complete.
27+ PROTOCOL_ERROR, // strange protocol error during connection; you should drop it.
28+ INVALID_PARAMETERS, // invalid parameters passed to function.
29+
30+ // *** socket creation.
31+ NAME_BIND_FAILED,
32+
33+ // *** socket accept.
34+ TOO_MANY_HANDLES, // the OS does not allow another connection by handle-count policies.
35+
36+ // *** socket read/write.
37+
38+};
39+
1840 // TidesNet is designed to be exception-safe. It should be used as static library while
1941 // being compiled with a compatible-to-the-mainprogram compiler.
2042 struct TidesException
2143 {
22- inline TidesException( const char *msg )
44+ inline TidesException( eNetExceptCode code, const char *msg = nullptr )
2345 {
24- this->msg = msg;
46+ this->except_code = code;
47+ this->msg = nullptr;
2548 }
2649
27- inline const char* get_msg( void ) const
50+ inline TidesException( const TidesException& ) noexcept = default;
51+ inline TidesException( TidesException&& ) noexcept = default;
52+
53+ inline TidesException& operator = ( const TidesException& ) noexcept = default;
54+ inline TidesException& operator = ( TidesException&& ) noexcept = default;
55+
56+ // Returns any associated message string for this exception.
57+ // It can be a nullptr to signal no available description.
58+ inline const char* get_opt_msg( void ) const
2859 {
2960 return this->msg;
3061 }
3162
63+ // Returns the applying exception code for this exception.
64+ inline eNetExceptCode get_code( void ) const
65+ {
66+ return this->except_code;
67+ }
68+
3269 private:
70+ eNetExceptCode except_code;
3371 const char *msg;
3472 };
3573
--- library/include/tidesnet/netsocket.h (revision 82)
+++ library/include/tidesnet/netsocket.h (revision 83)
@@ -55,7 +55,7 @@
5555
5656 if ( writeCount < 0 )
5757 {
58- throw TidesException( "failed call to sprintf" );
58+ throw TidesException( eNetExceptCode::INTERNAL_ERROR, "failed call to sprintf" );
5959 }
6060
6161 return eir::String <char, CRTHeapAllocator> ( buf, (size_t)writeCount );
--- library/include/tidesnet/qolhelpers.h (revision 82)
+++ library/include/tidesnet/qolhelpers.h (revision 83)
@@ -31,7 +31,24 @@
3131
3232 this->netMan = TidesNet::Construct( cparams );
3333 }
34+ inline netManInst( TidesNetwork::TidesNet *netPtr )
35+ {
36+ this->netMan = netPtr;
37+ }
3438
39+ static AINLINE netManInst from_exec_man( void *exec_man )
40+ {
41+ netManInst new_inst( nullptr );
42+
43+ TidesNet::constr_params cparams;
44+ cparams.memMan = &new_inst.memMan;
45+ cparams.nativeExecMan = exec_man;
46+
47+ new_inst.netMan = TidesNet::Construct( cparams );
48+
49+ return new_inst;
50+ }
51+
3552 inline netManInst( const netManInst& right ) = delete;
3653 inline netManInst( netManInst&& right )
3754 : memMan( std::move( right.memMan ) )
@@ -64,7 +81,7 @@
6481
6582 if ( our_ptr == nullptr )
6683 {
67- throw TidesException( "no pointer in netManInst" );
84+ throw TidesException( eNetExceptCode::NOT_INITIALIZED, "no pointer in netManInst" );
6885 }
6986
7087 return *our_ptr;
@@ -131,7 +148,7 @@
131148
132149 if ( receiver == nullptr )
133150 {
134- throw TidesException( "no pointer in connRecvInst" );
151+ throw TidesException( eNetExceptCode::NOT_INITIALIZED, "no pointer in connRecvInst" );
135152 }
136153
137154 return *receiver;
@@ -197,7 +214,7 @@
197214
198215 if ( socket == nullptr )
199216 {
200- throw TidesException( "no pointer in netSocketInst" );
217+ throw TidesException( eNetExceptCode::NOT_INITIALIZED, "no pointer in netSocketInst" );
201218 }
202219
203220 return *socket;
--- library/include/tidesnet/tidesnet.h (revision 82)
+++ library/include/tidesnet/tidesnet.h (revision 83)
@@ -57,7 +57,8 @@
5757 // This structure has to be filled out if you want to create a TidesNet manager.
5858 struct constr_params
5959 {
60- MemoryManagerInterface *memMan;
60+ MemoryManagerInterface *memMan = nullptr; // memory system to use for all objects of this library.
61+ void *nativeExecMan = nullptr; // if NativeExecutive is available then use this to enable threading support.
6162 };
6263
6364 // Factory functions.
--- library/src/main.cpp (revision 82)
+++ library/src/main.cpp (revision 83)
@@ -19,6 +19,11 @@
1919
2020 _NS_BEGIN_TIDESNET
2121
22+// A good maximum connection value for connection listener queues.
23+// Maybe think about exposing some smart system to the developer so that he can properly decide on a queue length.
24+// For now we just play it safe.
25+extern const int max_connection_queue_length = 32;
26+
2227 // Zero means that the library is not initialized.
2328 static unsigned int _lib_refCount = 0;
2429
@@ -29,6 +34,10 @@
2934 {
3035 // Store runtime variables.
3136 this->memMan = cparams.memMan;
37+
38+#ifdef TIDESNET_INCLUDE_NATIVEEXEC
39+ this->execMan = (NativeExecutive::CExecutiveManager*)cparams.nativeExecMan;
40+#endif //TIDESNET_INCLUDE_NATIVEEXEC
3241 }
3342
3443 TidesNetImpl::~TidesNetImpl( void )
@@ -146,7 +155,8 @@
146155 if ( netReceiver == nullptr )
147156 {
148157 _connReceiver_cleanupNative( std::move( nativeData ) );
149- return nullptr;
158+
159+ throw TidesException( eNetExceptCode::MEMORY_EXHAUSTED );
150160 }
151161
152162 // Now nothing should fail anymore.
@@ -159,9 +169,9 @@
159169
160170 connReceiverNativeData nativeData;
161171
162- if ( _connReceiver_createNative_anyAddr( port, connFamily, protoType, nativeData ) == false )
172+ if ( _connReceiver_createNative_anyAddr( port, connFamily, protoType, max_connection_queue_length, nativeData ) == false )
163173 {
164- return nullptr;
174+ throw TidesException( eNetExceptCode::NAME_BIND_FAILED );
165175 }
166176
167177 return _connReceiver_fromNativeData( nativeNetMan, std::move( nativeData ) );
@@ -172,7 +182,7 @@
172182 // This method currently only works for the "unix-style" sockets.
173183 if ( connFamily != eConnFamily::UNIX )
174184 {
175- return nullptr;
185+ throw TidesException( eNetExceptCode::INVALID_PARAMETERS );
176186 }
177187
178188 TidesNetImpl *nativeNetMan = (TidesNetImpl*)this;
@@ -181,7 +191,7 @@
181191
182192 if ( _connReceiver_createNativeNamed( portPath, connFamily, protoType, nativeData ) == false )
183193 {
184- return nullptr;
194+ throw TidesException( eNetExceptCode::NAME_BIND_FAILED );
185195 }
186196
187197 return _connReceiver_fromNativeData( nativeNetMan, std::move( nativeData ) );
@@ -193,9 +203,9 @@
193203
194204 connReceiverNativeData nativeData;
195205
196- if ( _connReceiver_createNative_ipv4( bindAddr, port, protoType, nativeData ) == false )
206+ if ( _connReceiver_createNative_ipv4( bindAddr, port, protoType, max_connection_queue_length, nativeData ) == false )
197207 {
198- return nullptr;
208+ throw TidesException( eNetExceptCode::NAME_BIND_FAILED );
199209 }
200210
201211 return _connReceiver_fromNativeData( nativeNetMan, std::move( nativeData ) );
@@ -207,9 +217,9 @@
207217
208218 connReceiverNativeData nativeData;
209219
210- if ( _connReceiver_createNative_ipv6( bindAddr, port, protoType, nativeData ) == false )
220+ if ( _connReceiver_createNative_ipv6( bindAddr, port, protoType, max_connection_queue_length, nativeData ) == false )
211221 {
212- return nullptr;
222+ throw TidesException( eNetExceptCode::NAME_BIND_FAILED );
213223 }
214224
215225 return _connReceiver_fromNativeData( nativeNetMan, std::move( nativeData ) );
--- library/src/mbedtls.cpp (revision 82)
+++ library/src/mbedtls.cpp (revision 83)
@@ -44,7 +44,7 @@
4444
4545 if ( mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen( pers ) ) != 0 )
4646 {
47- throw TidesException( "failed to seed MBEDTLS DRBG counter" );
47+ throw TidesException( eNetExceptCode::INTERNAL_ERROR, "failed to seed MBEDTLS DRBG counter" );
4848 }
4949 }
5050
@@ -130,9 +130,36 @@
130130 {
131131 int write_ret = mbedtls_ssl_write( &ssl, (const unsigned char*)buf, writeCount );
132132
133+ if ( write_ret == 0 )
134+ {
135+ // Make sure we close ourselves.
136+ this->socket->Close();
137+
138+ throw TidesException( eNetExceptCode::NETWORK_DOWN, "connection drop during SSL socket write" );
139+ }
140+
133141 if ( write_ret < 0 )
134142 {
135- throw TidesException( "error while writing to SSL socket" );
143+#ifdef _DEBUG
144+ char errmsg[1024];
145+
146+ mbedtls_strerror( write_ret, errmsg, sizeof(errmsg) );
147+#endif //_DEBUG
148+
149+ if ( write_ret == MBEDTLS_ERR_SSL_WANT_READ ||
150+ write_ret == MBEDTLS_ERR_SSL_WANT_WRITE ||
151+ write_ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ||
152+ write_ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS )
153+ {
154+ throw TidesException( eNetExceptCode::INTERNAL_ERROR, "internal error writing to SSL socket" );
155+ }
156+ else
157+ {
158+ // Drop the socket, please.
159+ this->socket->Close();
160+
161+ throw TidesException( eNetExceptCode::PROTOCOL_ERROR, "fatal error while writing to SSL socket" );
162+ }
136163 }
137164
138165 return (size_t)write_ret;
@@ -143,6 +170,16 @@
143170 {
144171 int read_ret = mbedtls_ssl_read( &ssl, (unsigned char*)buf, readCount );
145172
173+ if ( read_ret == 0 )
174+ {
175+ // We choose to return 0 because that must be recognized by the runtime to
176+ // stop reading because connection dropped.
177+ // Close ourselves if we have not yet done so.
178+ this->socket->Close();
179+
180+ return 0;
181+ }
182+
146183 if ( read_ret < 0 )
147184 {
148185 #ifdef _DEBUG
@@ -151,7 +188,21 @@
151188 mbedtls_strerror( read_ret, errmsg, sizeof(errmsg) );
152189 #endif //_DEBUG
153190
154- throw TidesException( "error while reading from SSL socket" );
191+ if ( read_ret == MBEDTLS_ERR_SSL_WANT_READ ||
192+ read_ret == MBEDTLS_ERR_SSL_WANT_WRITE ||
193+ read_ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ||
194+ read_ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS ||
195+ read_ret == MBEDTLS_ERR_SSL_CLIENT_RECONNECT )
196+ {
197+ throw TidesException( eNetExceptCode::INTERNAL_ERROR, "internal error while reading from SSL socket" );
198+ }
199+ else
200+ {
201+ // Drop the socket, please.
202+ this->socket->Close();
203+
204+ throw TidesException( eNetExceptCode::PROTOCOL_ERROR, "protocol error while reading from SSL socket" );
205+ }
155206 }
156207
157208 return (size_t)read_ret;
@@ -184,7 +235,7 @@
184235 // to preservce the atomicity guarrantee in non-partial transfer setting.
185236 if ( already_tx_count > 0 )
186237 {
187- throw TidesException( "truncated read during TLS non-partial data request" );
238+ throw TidesException( eNetExceptCode::PROTOCOL_ERROR, "truncated read during TLS non-partial data request" );
188239 }
189240
190241 // Probably just a disconnect.
@@ -214,7 +265,7 @@
214265 MBEDTLS_SSL_PRESET_DEFAULT
215266 ) != 0 )
216267 {
217- throw TidesException( "failed to set MBEDTLS ssl config defaults" );
268+ throw TidesException( eNetExceptCode::INTERNAL_ERROR, "failed to set MBEDTLS ssl config defaults" );
218269 }
219270
220271 // We want to verify if we actually did obtain a certificate from the runtime.
@@ -239,7 +290,7 @@
239290 mbedtls_strerror( x509_crt_parse_errcode, errmsg, sizeof(errmsg) );
240291 #endif //_DEBUG
241292
242- throw TidesException( "failed to parse MBEDTLS public certificate(s)" );
293+ throw TidesException( eNetExceptCode::INTERNAL_ERROR, "failed to parse MBEDTLS public certificate(s)" );
243294 }
244295
245296 // Link them with the config.
@@ -251,13 +302,13 @@
251302
252303 if ( config_err != 0 )
253304 {
254- throw TidesException( "failed to setup MBEDTLS ssl context using config" );
305+ throw TidesException( eNetExceptCode::INTERNAL_ERROR, "failed to setup MBEDTLS ssl context using config" );
255306 }
256307
257308 // Meowy meow meow.
258309 if ( mbedtls_ssl_set_hostname( &ssl, hostname ) != 0 )
259310 {
260- throw TidesException( "failed to setup MBEDTLS ssl context connection hostname" );
311+ throw TidesException( eNetExceptCode::INTERNAL_ERROR, "failed to setup MBEDTLS ssl context connection hostname" );
261312 }
262313 }
263314 catch( ... )
@@ -299,7 +350,7 @@
299350 mbedtls_strerror( ssl_config_defaults_errcode, errmsg, sizeof(errmsg) );
300351 #endif //_DEBUG
301352
302- throw TidesException( "failed to set MBEDTLS ssl config defaults" );
353+ throw TidesException( eNetExceptCode::INTERNAL_ERROR, "failed to set MBEDTLS ssl config defaults" );
303354 }
304355
305356 // Not a hax. Nothing to verify because we are the private party everyone
@@ -321,7 +372,7 @@
321372 mbedtls_strerror( pk_parse_key_errcode, errmsg, sizeof(errmsg) );
322373 #endif //_DEBUG
323374
324- throw TidesException( "failed to parse MBEDTLS private key" );
375+ throw TidesException( eNetExceptCode::INTERNAL_ERROR, "failed to parse MBEDTLS private key" );
325376 }
326377
327378 // Also need to configure the certificate chain.
@@ -340,7 +391,7 @@
340391 mbedtls_strerror( x509_crt_parse_errcode, errmsg, sizeof(errmsg) );
341392 #endif //_DEBUG
342393
343- throw TidesException( "failed to parse MBEDTLS public certificate chain" );
394+ throw TidesException( eNetExceptCode::INTERNAL_ERROR, "failed to parse MBEDTLS public certificate chain" );
344395 }
345396
346397 // Now set our own certificate data.
@@ -354,7 +405,7 @@
354405 mbedtls_strerror( ssl_conf_own_cert_errcode, errmsg, sizeof(errmsg) );
355406 #endif //_DEBUG
356407
357- throw TidesException( "failed to assign MBEDTLS public certificate and private key to TLS context" );
408+ throw TidesException( eNetExceptCode::INTERNAL_ERROR, "failed to assign MBEDTLS public certificate and private key to TLS context" );
358409 }
359410
360411 // Link config with SSL.
@@ -368,7 +419,7 @@
368419 mbedtls_strerror( config_err, errmsg, sizeof(errmsg) );
369420 #endif //_DEBUG
370421
371- throw TidesException( "failed to setup MBEDTLS ssl context using config" );
422+ throw TidesException( eNetExceptCode::INTERNAL_ERROR, "failed to setup MBEDTLS ssl context using config" );
372423 }
373424 }
374425 catch( ... )
--- library/src/memory.cpp (revision 82)
+++ library/src/memory.cpp (revision 83)
@@ -21,6 +21,7 @@
2121
2222 // For now we provide our own thing.
2323 // Remember that we are not required to be thread-safe!
24+// We do want to be static because we cannot exclude allocation memory before we hit the init routines.
2425 static NativeHeapAllocator _defaultHeap;
2526
2627 #else
--- library/src/netsocket.cpp (revision 82)
+++ library/src/netsocket.cpp (revision 83)
@@ -26,6 +26,8 @@
2626
2727 _NS_BEGIN_TIDESNET
2828
29+extern const int max_connection_queue_length;
30+
2931 // Need extension methods for TidesNet under operating systems.
3032 #ifdef _WIN32
3133
@@ -107,10 +109,7 @@
107109
108110 if ( wsa_err == WSAECONNABORTED || wsa_err == WSAECONNRESET || wsa_err == WSAENETDOWN || wsa_err == WSAENETRESET )
109111 {
110- // The connection was terminated. We should just quit using this socket.
111- shutdown( sysSocket, SD_BOTH );
112-
113- nativeSocket->isClosed = true;
112+ this->Close();
114113 }
115114
116115 return 0;
@@ -136,11 +135,9 @@
136135 {
137136 int errcode = errno;
138137
139- if ( errcode == ECONNRESET || errcode == EPIPE || EIO )
138+ if ( errcode == ECONNRESET || errcode == EPIPE || errcode == EIO )
140139 {
141- shutdown( sysSocket, SHUT_RDWR );
142-
143- nativeSocket->isClosed = true;
140+ this->Close();
144141 }
145142
146143 return 0;
@@ -203,10 +200,7 @@
203200 wsa_err == WSAENETDOWN ||
204201 wsa_err == WSAETIMEDOUT )
205202 {
206- // Terminate the socket due to erratic behavior.
207- shutdown( sysSocket, SD_BOTH );
208-
209- nativeSocket->isClosed = true;
203+ this->Close();
210204 }
211205
212206 return 0;
@@ -214,10 +208,7 @@
214208
215209 if ( actuallyReceived_count == 0 )
216210 {
217- // Graceful closure.
218- shutdown( sysSocket, SD_BOTH );
219-
220- nativeSocket->isClosed = true;
211+ this->Close();
221212 }
222213
223214 // Yay, we did it!
@@ -297,6 +288,10 @@
297288 {
298289 NetSocketImpl *nativeSocket = (NetSocketImpl*)this;
299290
291+#ifdef TIDESNET_INCLUDE_NATIVEEXEC
292+ NativeExecutive::CReadWriteWriteContextSafe <> ctx_atomic( nativeSocket->lock_atomic );
293+#endif //TIDESNET_INCLUDE_NATIVEEXEC
294+
300295 #ifdef _WIN32
301296 if ( nativeSocket->isClosed == false )
302297 {
@@ -319,6 +314,10 @@
319314 {
320315 const NetSocketImpl *nativeSocket = (const NetSocketImpl*)this;
321316
317+#ifdef TIDESNET_INCLUDE_NATIVEEXEC
318+ NativeExecutive::CReadWriteReadContextSafe <> ctx_atomic( nativeSocket->lock_atomic );
319+#endif //TIDESNET_INCLUDE_NATIVEEXEC
320+
322321 #ifdef _WIN32
323322 return nativeSocket->isClosed;
324323 #elif defined(__linux__)
@@ -339,7 +338,7 @@
339338
340339 if ( fetch_err != 0 )
341340 {
342- throw TidesException( "failed getsockopt call" );
341+ throw TidesException( eNetExceptCode::INTERNAL_ERROR, "failed getsockopt call" );
343342 }
344343 }
345344
@@ -370,6 +369,8 @@
370369 {
371370 const NetSocketImpl *nativeSocket = (const NetSocketImpl*)this;
372371
372+ // No lock required because the OS object is expected to be thread-safe.
373+
373374 #ifdef _WIN32
374375 WSAPROTOCOL_INFOW protoInfo;
375376 get_sys_socket_info( nativeSocket->transportSocket, protoInfo );
@@ -387,7 +388,7 @@
387388 break;
388389 }
389390
390- throw TidesException( "unknown native socket protocol in NetSocket::GetProtocol" );
391+ throw TidesException( eNetExceptCode::UNKNOWN_ERROR, "unknown native socket protocol in NetSocket::GetProtocol" );
391392 #elif defined(__linux__)
392393 int protocol;
393394
@@ -403,10 +404,10 @@
403404 return eConnProtocol::UDP;
404405 }
405406
406- throw TidesException( "unknown native socket protocol in NetSocket::GetProtocol" );
407+ throw TidesException( eNetExceptCode::UNKNOWN_ERROR, "unknown native socket protocol in NetSocket::GetProtocol" );
407408 }
408409
409- throw TidesException( "failed to fetch socket protocol" );
410+ throw TidesException( eNetExceptCode::INTERNAL_ERROR, "failed to fetch socket protocol" );
410411 #else
411412 #error Missing NetSocket::GetProtocol implementation
412413 #endif //CROSS PLATFORM CODE.
@@ -416,6 +417,8 @@
416417 {
417418 const NetSocketImpl *nativeSocket = (const NetSocketImpl*)this;
418419
420+ // No lock required because the OS object is expected to be thread-safe.
421+
419422 #ifdef _WIN32
420423 // Fetch it from the OS.
421424 WSAPROTOCOL_INFOW protoInfo;
@@ -433,7 +436,7 @@
433436 return eConnFamily::IPV6;
434437 }
435438
436- throw TidesException( "unknown native socket addressing family" );
439+ throw TidesException( eNetExceptCode::UNKNOWN_ERROR, "unknown native socket addressing family" );
437440 #elif defined(__linux__)
438441 int addrFamily;
439442
@@ -449,10 +452,10 @@
449452 return eConnFamily::IPV6;
450453 }
451454
452- throw TidesException( "unknown native socket addressing family" );
455+ throw TidesException( eNetExceptCode::UNKNOWN_ERROR, "unknown native socket addressing family" );
453456 }
454457
455- throw TidesException( "failed to fetch native socket addressing family" );
458+ throw TidesException( eNetExceptCode::INTERNAL_ERROR, "failed to fetch native socket addressing family" );
456459 #else
457460 #error Missing NetSocket::GetFamily implementation
458461 #endif //CROSS PLATFORM CODE.
@@ -462,6 +465,8 @@
462465 {
463466 const NetSocketImpl *nativeSocket = (const NetSocketImpl*)this;
464467
468+ // No lock required because the OS object is expected to be thread-safe.
469+
465470 #ifdef _WIN32
466471 tides_sockaddr_in4 name;
467472 int len = sizeof(name);
@@ -515,6 +520,8 @@
515520 {
516521 const NetSocketImpl *nativeSocket = (const NetSocketImpl*)this;
517522
523+ // No lock required because the OS object is expected to be thread-safe.
524+
518525 #ifdef _WIN32
519526 tides_sockaddr_in6 name;
520527 int len = sizeof(name);
@@ -568,6 +575,8 @@
568575 {
569576 const NetSocketImpl *nativeSocket = (const NetSocketImpl*)this;
570577
578+ // No lock required because the OS object is expected to be thread-safe.
579+
571580 #ifdef _WIN32
572581 tides_sockaddr_in4 name;
573582 int len = sizeof(name);
@@ -621,6 +630,8 @@
621630 {
622631 const NetSocketImpl *nativeSocket = (const NetSocketImpl*)this;
623632
633+ // No lock required because the OS object is expected to be thread-safe.
634+
624635 #ifdef _WIN32
625636 tides_sockaddr_in6 name;
626637 int len = sizeof(name);
@@ -674,6 +685,8 @@
674685 {
675686 const NetSocketImpl *nativeSocket = (const NetSocketImpl*)this;
676687
688+ // No lock required because the OS object is expected to be thread-safe.
689+
677690 #ifdef _WIN32
678691 DWORD value;
679692 int valueLen = sizeof(value);
@@ -682,7 +695,7 @@
682695
683696 if ( error != 0 || valueLen != sizeof(value) )
684697 {
685- throw TidesException( "failed to fetch receive time-out in NetSocketImpl::GetReceiveTimeout" );
698+ throw TidesException( eNetExceptCode::INTERNAL_ERROR, "failed to fetch receive time-out in NetSocketImpl::GetReceiveTimeout" );
686699 }
687700
688701 return (unsigned int)value;
@@ -694,7 +707,7 @@
694707
695708 if ( error != 0 || len != sizeof(timeout) )
696709 {
697- throw TidesException( "failed to fetch receive time-out in NetSocketImpl::GetReceiveTimeout" );
710+ throw TidesException( eNetExceptCode::INTERNAL_ERROR, "failed to fetch receive time-out in NetSocketImpl::GetReceiveTimeout" );
698711 }
699712
700713 // Calculate the time in milliseconds.
@@ -711,6 +724,8 @@
711724 {
712725 NetSocketImpl *nativeSocket = (NetSocketImpl*)this;
713726
727+ // No lock required because the OS object is expected to be thread-safe.
728+
714729 #ifdef _WIN32
715730 DWORD value = ms;
716731
@@ -718,7 +733,7 @@
718733
719734 if ( error != 0 )
720735 {
721- throw TidesException( "failed to set receive timeout on socket" );
736+ throw TidesException( eNetExceptCode::INTERNAL_ERROR, "failed to set receive timeout on socket" );
722737 }
723738 #elif defined(__linux__)
724739 // Need to transform to linux representation.
@@ -730,7 +745,7 @@
730745
731746 if ( error != 0 )
732747 {
733- throw TidesException( "failed to set receive timeout on socket" );
748+ throw TidesException( eNetExceptCode::INTERNAL_ERROR, "failed to set receive timeout on socket" );
734749 }
735750 #else
736751 #error Missing NetSocket::SetReceiveTimeout implementation
@@ -744,6 +759,7 @@
744759 // Trim away all incoming and outgoing pipes.
745760 shutdown( socket, SD_BOTH );
746761
762+ // Then cancel any stuff that is currently happening.
747763 if ( win32_natCompatLayer *layer = win32_natCompatLayer_reg.get().GetPluginStruct( netMan ) )
748764 {
749765 // Only perform it if we actually have the function (Windows Vista+)
@@ -761,19 +777,51 @@
761777 }
762778 }
763779
764-#endif //_WIN32
780+static AINLINE void set_socket_linger( SOCKET transportSocket, unsigned short linger_time )
781+{
782+ linger info;
783+ info.l_onoff = 1;
784+ info.l_linger = linger_time;
785+ setsockopt( transportSocket, SOL_SOCKET, SO_LINGER, (const char*)&info, sizeof(info) );
786+}
765787
788+#elif defined(__linux__)
789+
790+static AINLINE void set_socket_linger( int socketFD, unsigned short linger_time )
791+{
792+ linger info;
793+ info.l_onoff = 1;
794+ info.l_linger = linger_time;
795+ setsockopt( transportSocket, SOL_SOCKET, SO_LINGER, (const void*)&info, sizeof(info) );
796+}
797+
798+#endif //CROSS PLATFORM CODE
799+
800+// Cleanly terminates connections to and from the socket.
766801 void NetSocket::Close( void )
767802 {
803+ // Just small enough to be fair for both sides.
804+ static constexpr unsigned short SAFE_LINGER_PERIOD = 3;
805+
768806 // Used to terminate operations on a certain socket.
807+ // Must not invalidate the socket handle itself because calls have to be thread-safe.
808+ // Locking is recommended to prevent double-calling this function.
769809
770810 NetSocketImpl *nativeSocket = (NetSocketImpl*)this;
771811
812+#ifdef TIDESNET_INCLUDE_NATIVEEXEC
813+ NativeExecutive::CReadWriteWriteContextSafe <> ctx_atomic( nativeSocket->lock_atomic );
814+#endif //TIDESNET_INCLUDE_NATIVEEXEC
815+
772816 #ifdef _WIN32
773817 if ( !nativeSocket->isClosed )
774818 {
775819 SOCKET transportSocket = nativeSocket->transportSocket;
776820
821+ // Make sure we linger for a little while.
822+ // This is because we chose to cleanly terminate.
823+ set_socket_linger( transportSocket, SAFE_LINGER_PERIOD );
824+
777825 _terminate_socket_activity( nativeSocket->netMan, transportSocket );
778826
779827 nativeSocket->isClosed = true;
@@ -781,8 +829,12 @@
781829 #elif defined(__linux__)
782830 if ( !nativeSocket->isClosed )
783831 {
784- shutdown( nativeSocket->socketFD, SHUT_RDWR );
832+ int socketFD = nativeSocket->socketFD;
833+
834+ set_socket_linger( socketFD, SAFE_LINGER_PERIOD );
785835
836+ shutdown( socketFD, SHUT_RDWR );
837+
786838 nativeSocket->isClosed = true;
787839 }
788840 #else
@@ -790,10 +842,42 @@
790842 #endif //CROSS PLATFORM CODE.
791843 }
792844
845+NetSocketImpl::~NetSocketImpl( void )
846+{
847+ // Destroy any available data context.
848+ _clear_data_ctx();
849+
850+#ifdef _WIN32
851+ SOCKET curSock = this->transportSocket;
852+#elif defined(__linux__)
853+ int socketFD = this->socketFD;
854+#endif //CROSS PLATFORM CODE
855+
856+ // No bullshit policy.
857+ if ( this->isClosed == false )
858+ {
859+#ifdef _WIN32
860+ set_socket_linger( curSock, 0 );
861+#elif defined(__linux__)
862+ set_socket_linger( socketFD, 0 );
863+#endif //CROSS PLATFORM CODE
864+ }
865+
866+#ifdef _WIN32
867+ closesocket( curSock );
868+#elif defined(__linux__)
869+ _linux_socket_close( socketFD );
870+#else
871+#error Missing NetSocketImpl destructor implementation
872+#endif //CROSS PLATFORM CODE.
873+}
874+
793875 TidesNet* NetSocket::GetNetManager( void )
794876 {
795877 NetSocketImpl *nativeSocket = (NetSocketImpl*)this;
796878
879+ // Immutable variable so no lock necessary.
880+
797881 return nativeSocket->netMan;
798882 }
799883
@@ -894,8 +978,13 @@
894978 {
895979 ConnReceiverImpl *nativeListener = (ConnReceiverImpl*)this;
896980
981+#ifdef TIDESNET_INCLUDE_NATIVEEXEC
982+ NativeExecutive::CReadWriteReadContextSafe <> ctx_atomic( nativeListener->lock_reset );
983+#endif //TIDESNET_INCLUDE_NATIVEEXEC
984+
897985 if ( nativeListener->isClosed )
898986 {
987+ // That's ok because accept we expect to be in a loop which checks for closure of the socket.
899988 return nullptr;
900989 }
901990
@@ -902,7 +991,6 @@
902991 #ifdef _WIN32
903992 SOCKET listenerSocket = nativeListener->listenerSocket;
904993
905-simplyTryAgain:
906994 // Try to fetch a new system socket.
907995 SOCKET acceptedSysSocket = accept( listenerSocket, nullptr, nullptr );
908996
@@ -911,15 +999,26 @@
911999 // Try handling the error condition properly.
9121000 int errcode = WSAGetLastError();
9131001
914- if ( errcode == WSAENOTSOCK || errcode == WSAEFAULT || errcode == WSAEINVAL || errcode == WSAEMFILE || errcode == WSAENETDOWN )
1002+ if ( errcode == WSAENOTSOCK || errcode == WSAEFAULT || errcode == WSAEINVAL )
9151003 {
916- throw TidesException( "error during socket accept function" );
1004+ throw TidesException( eNetExceptCode::INTERNAL_ERROR, "internal error during socket accept function" );
9171005 }
9181006
1007+ if ( errcode == WSAEMFILE )
1008+ {
1009+ throw TidesException( eNetExceptCode::TOO_MANY_HANDLES, "cannot accept more handles in socket accept function" );
1010+ }
1011+
1012+ if ( errcode == WSAENETDOWN )
1013+ {
1014+ throw TidesException( eNetExceptCode::NETWORK_DOWN, "network dropped during socket accept function" );
1015+ }
1016+
9191017 // Somebody is being foolish with their connection logic.
9201018 if ( errcode == WSAECONNRESET )
9211019 {
922- goto simplyTryAgain;
1020+ // Changed this logic to prevent any possible internal dead-lock loops.
1021+ throw TidesException( eNetExceptCode::PROTOCOL_ERROR, "connection closed by peer during socket accept function" );
9231022 }
9241023
9251024 if ( errcode == WSAEINPROGRESS || errcode == WSAENOBUFS || errcode == WSAEINTR )
@@ -929,46 +1028,39 @@
9291028 return nullptr;
9301029 }
9311030
932- throw TidesException( "unknown error in socket accept call" );
1031+ throw TidesException( eNetExceptCode::UNKNOWN_ERROR, "unknown error in socket accept call" );
9331032 }
9341033
935- // Set important properties.
936- {
937- LINGER linger;
938- linger.l_onoff = 1;
939- linger.l_linger = 30;
940- int error = setsockopt( acceptedSysSocket, SOL_SOCKET, SO_LINGER, (const char*)&linger, sizeof(linger) );
941-
942- assert( error == 0 );
943- }
9441034 #elif defined(__linux__)
9451035 int listenFD = nativeListener->listenerFD;
9461036
947-#if 0
948-simplyTryAgain:
949-#endif //0
9501037 int acceptedFD = accept( listenFD, nullptr, nullptr );
9511038
9521039 if ( acceptedFD < 0 )
9531040 {
954- // Long story short we aint got no errno support in NativeExecutive.
955- // But if the error is recoverable then we can return nullptr for retry-if-not-closed.
956- // We use errno here without impact on real runtime because it currently it is not
957- // a thread-safe variable.
958- throw TidesException( _linux_get_accept_errormsg( errno ) );
1041+ // Check for some really nasty errors.
1042+ int errno = errno;
9591043
960-#if 0
961- // Check for some really nasty errors:
962- if ( errno == EBADF || errno == EFAULT || errno == EINVAL || errno == ENOTSOCK || errno == EPROTO ||
963- errno == ENFILE || errno == EMFILE || errno == EPROTO )
1044+ if ( errno == EBADF || errno == EFAULT || errno == EINVAL || errno == ENOTSOCK )
9641045 {
965- throw TidesException( "error during socket accept syscall" );
1046+ throw TidesException( eNetExceptCode::INTERNAL_ERROR, _linux_get_accept_errormsg( errno ) );
9661047 }
9671048
1049+ if ( errno == EPROTO )
1050+ {
1051+ throw TidesException( eNetExceptCode::PROTOCOL_ERROR, _linux_get_accept_errormsg( errno ) );
1052+ }
1053+
1054+ if ( errno == ENFILE || errno == EMFILE )
1055+ {
1056+ throw TidesException( eNetExceptCode::TOO_MANY_HANDLES, _linux_get_accept_errormsg( errno ) );
1057+ }
1058+
9681059 // If somebody closed the connection even before we could serve them we just try the next guy.
9691060 if ( errno == ECONNABORTED )
9701061 {
971- goto simplyTryAgain;
1062+ // Changed to root-out any possible spin-locks.
1063+ throw TidesException( eNetExceptCode::PROTOCOL_ERROR, _linux_get_accept_errormsg( errno ) );
9721064 }
9731065
9741066 if ( errno == ENOBUFS || errno == ENOMEM || errno == EINTR )
@@ -978,19 +1070,8 @@
9781070 return nullptr;
9791071 }
9801072
981- throw TidesException( "unknown error in socket accept syscall" );
982-#endif //0
1073+ throw TidesException( eNetExceptCode::UNKNOWN_ERROR, _linux_get_accept_errormsg( errno ) );
9831074 }
984-
985- // Set important properties.
986- {
987- linger info;
988- info.l_onoff = 1;
989- info.l_linger = 30;
990- int error = setsockopt( acceptedFD, SOL_SOCKET, SO_LINGER, (const void*)&info, sizeof(info) );
991-
992- assert( error == 0 );
993- }
9941075 #else
9951076 #error Missing ConnReceiver::Accept implementation
9961077 #endif //CROSS PLATFORM CODE
@@ -1031,6 +1112,11 @@
10311112 {
10321113 const ConnReceiverImpl *nativeListener = (const ConnReceiverImpl*)this;
10331114
1115+#ifdef TIDESNET_INCLUDE_NATIVEEXEC
1116+ NativeExecutive::CReadWriteReadContextSafe <> ctx_reset( nativeListener->lock_reset );
1117+ NativeExecutive::CReadWriteReadContextSafe <> ctx_atomic( nativeListener->lock_atomic );
1118+#endif //TIDESNET_INCLUDE_NATIVEEXEC
1119+
10341120 #ifdef _WIN32
10351121 return nativeListener->isClosed;
10361122 #elif defined(__linux__)
@@ -1044,7 +1130,10 @@
10441130 {
10451131 ConnReceiverImpl *nativeListener = (ConnReceiverImpl*)this;
10461132
1047- // TODO: apply locks.
1133+#ifdef TIDESNET_INCLUDE_NATIVEEXEC
1134+ NativeExecutive::CReadWriteWriteContextSafe <> ctx_atomic( nativeListener->lock_atomic );
1135+ NativeExecutive::CReadWriteWriteContextSafe <> ctx_reset( nativeListener->lock_reset );
1136+#endif //TIDESNET_INCLUDE_NATIVEEXEC
10481137
10491138 if ( reviveClosed == false && nativeListener->isClosed )
10501139 {
@@ -1075,7 +1164,7 @@
10751164 // Then we must try opening the new socket.
10761165 connReceiverNativeData nativeData;
10771166
1078- if ( _connReceiver_createNative_anyAddr( port, connFamily, protoType, nativeData ) == false )
1167+ if ( _connReceiver_createNative_anyAddr( port, connFamily, protoType, max_connection_queue_length, nativeData ) == false )
10791168 {
10801169 nativeListener->isClosed = true;
10811170 return false;
@@ -1100,6 +1189,11 @@
11001189
11011190 ConnReceiverImpl *nativeListener = (ConnReceiverImpl*)this;
11021191
1192+#ifdef TIDESNET_INCLUDE_NATIVEEXEC
1193+ NativeExecutive::CReadWriteReadContextSafe <> ctx_reset( nativeListener->lock_reset );
1194+ NativeExecutive::CReadWriteWriteContextSafe <> ctx_atomic( nativeListener->lock_atomic );
1195+#endif //TIDESNET_INCLUDE_NATIVEEXEC
1196+
11031197 #ifdef _WIN32
11041198 if ( !nativeListener->isClosed )
11051199 {
@@ -1127,6 +1221,8 @@
11271221 {
11281222 ConnReceiverImpl *nativeListener = (ConnReceiverImpl*)this;
11291223
1224+ // Immutable variable so no lock necessary.
1225+
11301226 return nativeListener->netMan;
11311227 }
11321228
--- library/src/netsocket.impl.hxx (revision 82)
+++ library/src/netsocket.impl.hxx (revision 83)
@@ -100,15 +100,17 @@
100100 SOCKET socketHandle;
101101 };
102102
103-inline bool _connReceiver_setupSocket( SOCKET sysSocket )
103+inline bool _connReceiver_setupSocket( SOCKET sysSocket, int queue_length )
104104 {
105105 // Also give it some backlog.
106- int backlogConfigError = listen( sysSocket, SOMAXCONN );
106+ int backlogConfigError = listen( sysSocket, queue_length );
107107
108108 if ( backlogConfigError != 0 )
109109 {
110110 #ifdef _DEBUG
111111 int sockErr = WSAGetLastError();
112+
113+ (void)sockErr;
112114 #endif //_DEBUG
113115
114116 return false;
@@ -117,7 +119,7 @@
117119 return true;
118120 }
119121
120-inline bool _connReceiver_createNative_anyAddr( std::uint16_t port, eConnFamily connFamily, eConnProtocol protoType, connReceiverNativeData& dataOut )
122+inline bool _connReceiver_createNative_anyAddr( std::uint16_t port, eConnFamily connFamily, eConnProtocol protoType, int queue_length, connReceiverNativeData& dataOut )
121123 {
122124 // This method only works for IP-address based connection families.
123125 if ( connFamily != eConnFamily::IPV4 && connFamily != eConnFamily::IPV6 )
@@ -164,7 +166,7 @@
164166 return false;
165167 }
166168
167- if ( _connReceiver_setupSocket( sysSocket ) == false )
169+ if ( _connReceiver_setupSocket( sysSocket, queue_length ) == false )
168170 {
169171 // Error out.
170172 closesocket( sysSocket );
@@ -176,7 +178,7 @@
176178 return true;
177179 }
178180
179-inline bool _connReceiver_createNative_ipv4( const ipdescIPV4& bindaddr, std::uint16_t port, eConnProtocol protoType, connReceiverNativeData& dataOut )
181+inline bool _connReceiver_createNative_ipv4( const ipdescIPV4& bindaddr, std::uint16_t port, eConnProtocol protoType, int queue_length, connReceiverNativeData& dataOut )
180182 {
181183 short addressFamily;
182184 SOCKET sysSocket = create_system_socket( eConnFamily::IPV4, protoType, addressFamily );
@@ -201,7 +203,7 @@
201203 return false;
202204 }
203205
204- if ( _connReceiver_setupSocket( sysSocket ) == false )
206+ if ( _connReceiver_setupSocket( sysSocket, queue_length ) == false )
205207 {
206208 // Error out.
207209 closesocket( sysSocket );
@@ -213,7 +215,7 @@
213215 return true;
214216 }
215217
216-inline bool _connReceiver_createNative_ipv6( const ipdescIPV6& bindaddr, std::uint16_t port, eConnProtocol protoType, connReceiverNativeData& dataOut )
218+inline bool _connReceiver_createNative_ipv6( const ipdescIPV6& bindaddr, std::uint16_t port, eConnProtocol protoType, int queue_length, connReceiverNativeData& dataOut )
217219 {
218220 short addressFamily;
219221 SOCKET sysSocket = create_system_socket( eConnFamily::IPV6, protoType, addressFamily );
@@ -240,7 +242,7 @@
240242 return false;
241243 }
242244
243- if ( _connReceiver_setupSocket( sysSocket ) == false )
245+ if ( _connReceiver_setupSocket( sysSocket, queue_length ) == false )
244246 {
245247 // Error out.
246248 closesocket( sysSocket );
@@ -304,7 +306,7 @@
304306 return false;
305307 }
306308
307- if ( _connReceiver_setupSocket( sysSocket ) == false )
309+ if ( _connReceiver_setupSocket( sysSocket, SOMAXCONN ) == false )
308310 {
309311 closesocket( sysSocket );
310312 return false;
@@ -420,7 +422,7 @@
420422 return true;
421423 }
422424
423-inline bool _connReceiver_createNative_anyAddr( std::uint16_t port, eConnFamily connFamily, eConnProtocol protoType, connReceiverNativeData& dataOut )
425+inline bool _connReceiver_createNative_anyAddr( std::uint16_t port, eConnFamily connFamily, eConnProtocol protoType, int queue_length, connReceiverNativeData& dataOut )
424426 {
425427 // Only supported for IP-based protocols.
426428 if ( connFamily != eConnFamily::IPV4 && connFamily != eConnFamily::IPV6 )
@@ -465,7 +467,7 @@
465467 return false;
466468 }
467469
468- if ( _connReceiver_setupSocket( socketFD ) == false )
470+ if ( _connReceiver_setupSocket( socketFD, queue_length ) == false )
469471 {
470472 _linux_socket_close( socketFD );
471473 return false;
@@ -476,7 +478,7 @@
476478 return true;
477479 }
478480
479-inline bool _connReceiver_createNative_ipv4( const ipdescIPV4& bindaddr, std::uint16_t port, eConnProtocol protoType, connReceiverNativeData& dataOut )
481+inline bool _connReceiver_createNative_ipv4( const ipdescIPV4& bindaddr, std::uint16_t port, eConnProtocol protoType, int queue_length, connReceiverNativeData& dataOut )
480482 {
481483 std::uint16_t addressFamily;
482484 int socketFD = create_system_socket( eConnFamily::IPV4, protoType, addressFamily );
@@ -499,7 +501,7 @@
499501 return false;
500502 }
501503
502- if ( _connReceiver_setupSocket( socketFD ) == false )
504+ if ( _connReceiver_setupSocket( socketFD, queue_length ) == false )
503505 {
504506 _linux_socket_close( socketFD );
505507 return false;
@@ -510,7 +512,7 @@
510512 return true;
511513 }
512514
513-inline bool _connReceiver_createNative_ipv6( const ipdescIPV6& bindaddr, std::uint16_t port, eConnProtocol protoType, connReceiverNativeData& dataOut )
515+inline bool _connReceiver_createNative_ipv6( const ipdescIPV6& bindaddr, std::uint16_t port, eConnProtocol protoType, int queue_length, connReceiverNativeData& dataOut )
514516 {
515517 std::uint16_t addressFamily;
516518 int socketFD = create_system_socket( eConnFamily::IPV6, protoType, addressFamily );
@@ -535,7 +537,7 @@
535537 return false;
536538 }
537539
538- if ( _connReceiver_setupSocket( socketFD ) == false )
540+ if ( _connReceiver_setupSocket( socketFD, queue_length ) == false )
539541 {
540542 _linux_socket_close( socketFD );
541543 return false;
@@ -591,7 +593,7 @@
591593 return false;
592594 }
593595
594- if ( _connReceiver_setupSocket( socketFD ) == false )
596+ if ( _connReceiver_setupSocket( socketFD, SOMAXCONN ) == false )
595597 {
596598 _linux_socket_close( socketFD );
597599 return false;
--- library/src/netsocket.private.h (revision 82)
+++ library/src/netsocket.private.h (revision 83)
@@ -34,6 +34,9 @@
3434 , int socketFD
3535 #endif //CROSS PLATFORM ARGS
3636 )
37+#ifdef TIDESNET_INCLUDE_NATIVEEXEC
38+ : lock_atomic( netMan->execMan )
39+#endif //TIDESNET_INCLUDE_NATIVEEXEC
3740 {
3841 this->netMan = netMan;
3942
@@ -63,22 +66,8 @@
6366 }
6467 }
6568
66- inline ~NetSocketImpl( void )
67- {
68- // Destroy any available data context.
69- _clear_data_ctx();
69+ ~NetSocketImpl( void );
7070
71-#ifdef _WIN32
72- SOCKET curSock = this->transportSocket;
73-
74- closesocket( curSock );
75-#elif defined(__linux__)
76- _linux_socket_close( this->socketFD );
77-#else
78-#error Missing NetSocketImpl destructor implementation
79-#endif //CROSS PLATFORM CODE.
80- }
81-
8271 TidesNetImpl *netMan;
8372
8473 // Implement the typical socket stuff.
@@ -85,6 +74,11 @@
8574 size_t ReadInternal( void *buf, size_t readCount, eReceiveFlag flags );
8675 size_t WriteInternal( const void *buf, size_t writeCount );
8776
77+#ifdef TIDESNET_INCLUDE_NATIVEEXEC
78+ // Lock for thread-safety.
79+ NativeExecutive::natOptRWLock lock_atomic;
80+#endif //TIDESNET_INCLUDE_NATIVEEXEC
81+
8882 #ifdef _WIN32
8983 SOCKET transportSocket; // network resource allocated in the Windows kernel.
9084 bool isClosed;
@@ -108,6 +102,9 @@
108102 , int listenerFD
109103 #endif //CROSS PLATFORM ARGS.
110104 )
105+#ifdef TIDESNET_INCLUDE_NATIVEEXEC
106+ : lock_atomic( netMan->execMan ), lock_reset( netMan->execMan )
107+#endif //TIDESNET_INCLUDE_NATIVEEXEC
111108 {
112109 this->netMan = netMan;
113110
@@ -145,6 +142,11 @@
145142
146143 TidesNetImpl *netMan;
147144
145+#ifdef TIDESNET_INCLUDE_NATIVEEXEC
146+ NativeExecutive::natOptRWLock lock_atomic; // for safely closing connection listeners.
147+ NativeExecutive::natOptRWLock lock_reset; // for safely resetting connection listeners.
148+#endif //TIDESNET_INCLUDE_NATIVEEXEC
149+
148150 #ifdef _WIN32
149151 SOCKET listenerSocket; // network resource allocated in the Windows kernel.
150152 #elif defined(__linux__)
--- library/src/tidesnet.private.h (revision 82)
+++ library/src/tidesnet.private.h (revision 83)
@@ -18,6 +18,10 @@
1818 #include <sdk/PluginFactory.h>
1919 #include <sdk/eirutils.h>
2020
21+#ifdef TIDESNET_INCLUDE_NATIVEEXEC
22+#include <NativeExecutive/CExecutiveManager.h>
23+#endif //TIDESNET_INCLUDE_NATIVEEXEC
24+
2125 // Need the platform headers for socket functionality (if available).
2226 #ifdef _WIN32
2327 #define NOMINMAX
@@ -41,6 +45,10 @@
4145 ~TidesNetImpl( void );
4246
4347 MemoryManagerInterface *memMan;
48+
49+#ifdef TIDESNET_INCLUDE_NATIVEEXEC
50+ NativeExecutive::CExecutiveManager *execMan;
51+#endif //TIDESNET_INCLUDE_NATIVEEXDC
4452 };
4553
4654 DEFINE_HEAP_ALLOC( TidesNetStaticMemAllocator );
Show on old repository browser