#REFACTORING by Stefan Reise
authorsr
Thu, 05 Mar 2020 10:53:30 +0100
changeset 5467 914f6955a10a
parent 5466 50ae296c9744
child 5468 e9da15c1a36c
#REFACTORING by Stefan Reise class: Socket added: #blockingNextPutAllForNonBlockingSocket: #systemBlockingNextPutAll: removed: #nonBlockingNextPutAll: #primNonBlockingNextPutAll: changed: #setNonBlocking
Socket.st
--- a/Socket.st	Wed Mar 04 17:07:17 2020 +0100
+++ b/Socket.st	Thu Mar 05 10:53:30 2020 +0100
@@ -16,10 +16,10 @@
 "{ NameSpace: Smalltalk }"
 
 NonPositionableExternalStream subclass:#Socket
-        instanceVariableNames:'domain socketType protocol port peer peerName listening'
-        classVariableNames:''
-        poolDictionaries:''
-        category:'Streams-External'
+	instanceVariableNames:'domain socketType protocol port peer peerName listening'
+	classVariableNames:''
+	poolDictionaries:''
+	category:'Streams-External'
 !
 
 !Socket primitiveDefinitions!
@@ -4375,10 +4375,36 @@
 
 !Socket methodsFor:'support websocket'!
 
-nonBlockingNextPutAll:someBytes
-    "using #primNonBlockingNextPutAll: 
-     because #nextPutAll: handles WSAEWOULDBLOCK / EWOULDBLOCK incorrect (at least for windows)
-     only called by WebSocketStream #criticalSocketNextPutAll:"
+blockingNextPutAllForNonBlockingSocket:someBytes
+    "explanation of the method name:
+     blocking -> this method blocks its STX process until all bytes have been written
+     ForNonBlockingSocket -> this method only works with non-blocking sockets
+
+     the write is done within the current thread, 
+     but the primitiv #send returns because the socket is non-blocking (in case of would block). 
+     of cause if you write big data at once and the socket never would block, STX will freeze,
+     so please split big data into small packages"
+
+    "PROBLEM \ BUG:
+        currently STX will freeze when writing and reading concurrently on the same blocking socket from both ends.
+        even when all those writers and readers have their own thread (by calling via __NOINT_CALL).
+
+     WORKAROUND (or Other Concept):
+        using a non-blocking socket
+
+        NEW PROBLEM: 
+        with non-blocking sockets you can not use the default #nextPut: 
+        because #nextPut: ends up in __NOINT_CALL('send') and probably due to until now not supported non-blocking sockets,
+        it does not set __threadErrno correctly to WOULDBLOCK in case of would block.
+        so by using default #nextPut: with an non-blocking socket you will miss some bytes or 
+        falsely get an error instead of WOULBLOCK
+
+        NEXT WORKAROUND:
+        use a your own #nextPut: method (#blockingNextPutAllForNonBlockingSocket:) and handle WOULDBLOCK correctly
+
+     Notes:
+     - all sockets under windows are created as blocking sockets by default
+     - there is NO query in windows to ask if a socket is blocking or non-blocking"
 
     |bytes countRemainingBytesToWrite result|
 
@@ -4393,7 +4419,7 @@
     countRemainingBytesToWrite := bytes size.
 
     [
-        result := self primNonBlockingNextPutAll:bytes. "/ may just writes a subset or may 0 -> would block
+        result := self systemBlockingNextPutAll:bytes. "/ may just writes a subset or may 0 -> would block
         result >= 0 "/ 0 or more bytes has been written
         and:[result ~= countRemainingBytesToWrite] "/ there are remaining bytes to write 
     ] whileTrue:[
@@ -4406,15 +4432,94 @@
         self writeWaitWithTimeoutMs:1000.
     ].
 
-    "Created: / 30-01-2020 / 16:35:08 / Stefan Reise"
-    "Modified (format): / 06-02-2020 / 13:18:59 / Stefan Reise"
-    "Modified (comment): / 03-03-2020 / 15:25:26 / Stefan Vogel"
+    "Created: / 05-03-2020 / 10:35:54 / Stefan Reise"
 !
 
-primNonBlockingNextPutAll:someBytes
-    "using #primNonBlockingNextPutAll: 
-     because #nextPutAll: handles WSAEWOULDBLOCK / EWOULDBLOCK incorrect (at least for windows)
-     only called by WebSocketStream #criticalSocketNextPutAll:"
+setNonBlocking
+    "DO NO move this functionality into Win32OperatingSystem #setBlocking:fd:, 
+     because it will not work correctly, caused by the following problems. 
+     and even if the problems has been fixed, it would change the behavior for all sockets (not only websockets)"
+
+    "PROBLEM \ BUG:
+        currently STX will freeze when writing and reading concurrently on the same blocking socket from both ends.
+        even when all those writers and readers have their own thread (by calling via __NOINT_CALL).
+
+     WORKAROUND (or Other Concept):
+        using a non-blocking socket
+
+        NEW PROBLEM: 
+        with non-blocking sockets you can not use the default #nextPut: 
+        because #nextPut: ends up in __NOINT_CALL('send') and probably due to until now not supported non-blocking sockets,
+        it does not set __threadErrno correctly to WOULDBLOCK in case of would block.
+        so by using default #nextPut: with an non-blocking socket you will miss some bytes or 
+        falsely get an error instead of WOULBLOCK
+
+        NEXT WORKAROUND:
+        use a your own #nextPut: method (#blockingNextPutAllForNonBlockingSocket:) and handle WOULDBLOCK correctly
+
+     Notes:
+     - all sockets under windows are created as blocking sockets by default
+     - there is NO query in windows to ask if a socket is blocking or non-blocking"
+
+    OperatingSystem isMSWINDOWSlike ifFalse:[
+        "/ this method is for windows os only
+        ^ self
+    ].
+
+%{
+# ifdef __win32__
+    OBJ fp = __INST(handle);
+
+    // ALWAYS check for proper arguments, please
+    if (fp != NULL) {
+        int result;
+        u_long nonBlocking = 1;
+        SOCKET socket = SOCKET_FROM_FILE_OBJECT(fp);
+
+        result = ioctlsocket(socket, FIONBIO, &nonBlocking);
+        if (result == SOCKET_ERROR) {
+            console_fprintf(stderr, "Win32OS [info]: ioctlsocket failed with %d\n", WSAGetLastError());
+            RETURN(false);
+        }
+
+        RETURN(true);
+    }
+#endif // __win32__
+%}.
+
+    self primitiveFailed.
+
+    "Modified: / 03-03-2020 / 15:29:26 / Stefan Vogel"
+    "Modified: / 05-03-2020 / 10:37:12 / Stefan Reise"
+!
+
+systemBlockingNextPutAll:someBytes
+    "explanation of the method name:
+     systemBlocking -> this method blocks the entire STX 
+     until all bytes have been written or until the socket would block
+
+     so please split big data into small packages"
+
+    "PROBLEM \ BUG:
+        currently STX will freeze when writing and reading concurrently on the same blocking socket from both ends.
+        even when all those writers and readers have their own thread (by calling via __NOINT_CALL).
+
+     WORKAROUND (or Other Concept):
+        using a non-blocking socket
+
+        NEW PROBLEM: 
+        with non-blocking sockets you can not use the default #nextPut: 
+        because #nextPut: ends up in __NOINT_CALL('send') and probably due to until now not supported non-blocking sockets,
+        it does not set __threadErrno correctly to WOULDBLOCK in case of would block.
+        so by using default #nextPut: with an non-blocking socket you will miss some bytes or 
+        falsely get an error instead of WOULBLOCK
+
+        NEXT WORKAROUND:
+        use a your own #nextPut: method (#blockingNextPutAllForNonBlockingSocket:) and handle WOULDBLOCK correctly
+
+     Notes:
+     - all sockets under windows are created as blocking sockets by default
+     - there is NO query in windows to ask if a socket is blocking or non-blocking"
 
     |bytes byteLength returnValue wsaError|
 
@@ -4434,10 +4539,11 @@
 
 %{
 # ifdef __win32__
+    OBJ fp = __INST(handle);
+
     // ALWAYS check for proper arguments, please
-    OBJ fp = __INST(handle);
-
-    if (__isExternalAddressLike(bytes) 
+    if (
+        __isExternalAddressLike(bytes) 
         && __isSmallInteger(byteLength) 
         && (fp != NULL)
     ) {
@@ -4468,45 +4574,7 @@
 
     ^ returnValue
 
-    "Modified: / 03-03-2020 / 15:29:09 / Stefan Vogel"
-!
-
-setNonBlocking
-    "using #setNonBlocking 
-     because implementing and using Win32OperatingSystem #setBlocking:fd: 
-     would reset to blocking (see senders of #blocking:)
-     and we need the socket to be non-blocking forever 
-     only called by WebSocketStream #criticalSocketNextPutAll:"
-
-    OperatingSystem isMSWINDOWSlike ifFalse:[
-        "/ this method is for windows os only
-        ^ self
-    ].
-
-%{
-# ifdef __win32__
-    // ALWAYS check for proper arguments, please
-    OBJ fp = __INST(handle);
-
-    if (fp != NULL) {
-        int result;
-        u_long nonBlocking = 1;
-        SOCKET socket = SOCKET_FROM_FILE_OBJECT(fp);
-
-        result = ioctlsocket(socket, FIONBIO, &nonBlocking);
-        if (result == SOCKET_ERROR) {
-            console_fprintf(stderr, "Win32OS [info]: ioctlsocket failed with %d\n", WSAGetLastError());
-            RETURN(false);
-        }
-
-        RETURN(true);
-    }
-#endif // __win32__
-%}.
-
-    self primitiveFailed.
-
-    "Modified: / 03-03-2020 / 15:29:26 / Stefan Vogel"
+    "Created: / 05-03-2020 / 10:48:56 / Stefan Reise"
 ! !
 
 !Socket methodsFor:'testing'!