--- a/Socket.st Thu Jan 30 12:50:19 2020 +0100
+++ b/Socket.st Fri Jan 31 14:00:51 2020 +0100
@@ -1,3 +1,5 @@
+"{ Encoding: utf8 }"
+
"
COPYRIGHT (c) 1992 by Claus Gittinger
All Rights Reserved
@@ -4037,7 +4039,6 @@
"
! !
-
!Socket methodsFor:'specials'!
linger:anIntegerOrNil
@@ -4374,6 +4375,159 @@
^ self setSocketOption:#'TCP_NODELAY' argument:aBoolean argument:nil.
! !
+!Socket methodsFor:'support websocket windows'!
+
+nonBlockingNextPutAll:someBytes
+ "all sockets created under windows os are blocking.
+
+ in case for web sockets,
+ concurrent write actions needs to be supported properly,
+ therefor the socket must be forced to be non blocking.
+
+ especially if the client and the server are running within the same stx,
+ because stx can not read from the socket, when the write is blocking -> freeze forever
+
+ it does not help to just wait before a blocking write action,
+ because the other web socket side could do write actions between our wait and our write action,
+ in this case (the usual case) our write action will block even with the pre called wait
+
+ by forcing the socket to be non blocking, we simply call the write action,
+ the primitiv #send returns a 'would block' flag if it would block, then we wait and try again"
+
+ |bytes countRemainingBytesToWrite result|
+
+ OperatingSystem isMSWINDOWSlike ifFalse:[
+ self error:'this method is for windows os only'.
+ ].
+
+ bytes := someBytes asByteArray.
+ countRemainingBytesToWrite := bytes size.
+
+ [
+ result := self primNonBlockingNextPutAll: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:[
+ result > 0 ifTrue:[
+ bytes := bytes copyFrom:result + 1.
+ countRemainingBytesToWrite := bytes size.
+ ].
+
+ "/ timeout does not matter, we wait infinitv
+ self writeWaitWithTimeoutMs:1000.
+ ].
+
+ "Created: / 30-01-2020 / 16:35:08 / Stefan Reise"
+ "Modified (comment): / 31-01-2020 / 13:59:12 / Stefan Reise"
+!
+
+primNonBlockingNextPutAll:someBytes
+ "all sockets created under windows os are blocking.
+
+ in case for web sockets,
+ concurrent write actions needs to be supported properly,
+ therefor the socket must be forced to be non blocking.
+
+ especially if the client and the server are running within the same stx,
+ because stx can not read from the socket, when the write is blocking -> freeze forever
+
+ it does not help to just wait before a blocking write action,
+ because the other web socket side could do write actions between our wait and our write action,
+ in this case (the usual case) our write action will block even with the pre called wait
+
+ by forcing the socket to be non blocking, we simply call the write action,
+ the primitiv #send returns a 'would block' flag if it would block, then we wait and try again"
+
+ |bytes byteLength returnValue|
+
+ OperatingSystem isMSWINDOWSlike ifFalse:[
+ self error:'this method is for windows os only'.
+ ].
+
+ bytes := someBytes asExternalBytes.
+ byteLength := bytes size.
+
+ "
+ -1 error
+ 0 0 bytes sent or would block -> try again after wait
+ > 0 bytes sent (recall myself with the remaining bytes)
+ "
+ returnValue := -1.
+
+ %{
+ int sendResult;
+ int wsaErrorNo;
+ char *pBytes = __externalAddressVal(bytes);
+ SOCKET socket = SOCKET_FROM_FILE_OBJECT(__INST(handle));
+
+ sendResult = send(socket, pBytes, __intVal(byteLength), 0);
+ if (sendResult == SOCKET_ERROR) {
+ wsaErrorNo = WSAGetLastError();
+ if (wsaErrorNo == WSAEWOULDBLOCK) {
+ returnValue = __MKSMALLINT(0);
+ } else {
+ console_printf("send failed with: %d\n", wsaErrorNo);
+ }
+ } else {
+ returnValue = __MKSMALLINT(sendResult);
+ }
+ %}.
+
+ returnValue < 0 ifTrue:[
+ self primitiveFailed.
+ ].
+
+ ^ returnValue
+
+ "Created: / 30-01-2020 / 16:36:01 / Stefan Reise"
+ "Modified: / 31-01-2020 / 11:53:01 / Stefan Reise"
+ "Modified (format): / 31-01-2020 / 13:59:56 / Stefan Reise"
+!
+
+setNonBlocking
+ "all sockets created under windows os are blocking.
+
+ in case for web sockets,
+ concurrent write actions needs to be supported properly,
+ therefor the socket must be forced to be non blocking.
+
+ especially if the client and the server are running within the same stx,
+ because stx can not read from the socket, when the write is blocking -> freeze forever
+
+ it does not help to just wait before a blocking write action,
+ because the other web socket side could do write actions between our wait and our write action,
+ in this case (the usual case) our write action will block even with the pre called wait
+
+ by forcing the socket to be non blocking, we simply call the write action,
+ the primitiv #send returns a 'would block' flag if it would block, then we wait and try again"
+
+ |succeeded|
+
+ OperatingSystem isMSWINDOWSlike ifFalse:[
+ self error:'this method is for windows os only'.
+ ].
+
+ succeeded := false.
+
+ %{
+ int result;
+ u_long nonBlocking = 1;
+ SOCKET socket = SOCKET_FROM_FILE_OBJECT(__INST(handle));
+
+ result = ioctlsocket(socket, FIONBIO, &nonBlocking);
+ if (result == SOCKET_ERROR) {
+ console_printf("ioctlsocket failed with %d\n", WSAGetLastError());
+ } else {
+ succeeded = true;
+ }
+ %}.
+
+ succeeded ifFalse:[
+ self primitiveFailed.
+ ].
+
+ "Created: / 31-01-2020 / 11:23:48 / Stefan Reise"
+! !
!Socket methodsFor:'waiting'!