B4J Question Problems with http server and multi tread, java.lang.IllegalStateException: STREAM

fabton1963

Member
Licensed User
Longtime User
Hello everybody,
I wrote a simple program to update all my IOT device firmware using OTA, when a remote device need an update call me b4j http server that upload a binary stream.
When called from a single device all works good but when multiple devices try to download firmware I get java.lang.IllegalStateException: STREAM.

in main module I declare the server and
[CODE lang="b4x" title="main"]Sub Process_Globals
Private srvr As Server
end sub
Sub AppStart (Args() As String)
....
...
srvr.AddHandler("/eclservices/*", "eclservice", False)
....
...
StartMessageLoop
end sub[/CODE]
in eclservice server handler

[CODE lang="b4x" title="eclservice"]Sub Class_Globals
Private Request As ServletRequest
Private Response As ServletResponse
Private HRM As HttpResponseMessage
End Sub

Sub Handle (req As ServletRequest, resp As ServletResponse)
Request = req
Response = resp
.......
......
ProcessRequest
end sub

Private Sub ProcessRequest
.....
.....
....
Case "getfirmware"

......
'read from blob field a byte array containing the new firmware
Dim b() As Byte = DB.ReadBlob("my_new_firmware.bin")
utility.ReturnFIRMWARE(b,Response,"my_new_firmware.bin")

....
....
end sub[/CODE]


[CODE lang="b4x" title="utility"]Public Sub ReturnFIRMWARE(b() As Byte, resp As ServletResponse,myfileName As String)

Log("[ReturnFIRMWARE]")
resp.ContentType = "application/octet-stream"

resp.SetHeader("Content-Disposition", $"inline;filename=${myfileName}"$ )
resp.SetHeader("Content-Length", $"${b.Length}"$)
resp.OutputStream.WriteBytes(b, 0, b.Length)
Log("[fine][ReturnFIRMWARE]")

End Sub[/CODE]

the process returnFIRMWARE takes about 10 seconds and when starts several concurrent calls only the first finish the job in the right way all other calls crashes with java.lang.IllegalStateException: STREAM.

What is my mistake ?
 
The first attempt: only one device asks the server to download binary ver 039 with no errors
Code:
[ECLSERVICE]-> /eclservices/getfirmware/Ota/BE3/GAMES/131.106.0039.bin
[eclservice][getfirmware][ReadBlob][BE3.GAMES.131.106.0039.bin]
[ReturnFIRMWARE]
[end][sending FIRMWARE]

second attempt: 4 devices ask to download binary ver 42 only first connection reply correctly all other crash and return null value

[CODE lang="rich" title="log" highlight="11-73,86-143"][ECLSERVICE]-> /eclservices/getfirmware/Ota/BE3/GAMES/131.106.0042.bin
[eclservice][getfirmware][ReadBlob][BE3.GAMES.131.106.0042.bin]
[ReturnFIRMWARE]
[end][sending FIRMWARE]


[ECLSERVICE]-> /eclservices/getfirmware/Ota/BE3/GAMES/131.106.0042.bin
[eclservice][getfirmware][ReadBlob][BE3.GAMES.131.106.0042.bin]
[ReturnFIRMWARE]

Error occurred on line: 98 (utility)


org.eclipse.jetty.io.EofException


at org.eclipse.jetty.io.SocketChannelEndPoint.flush(SocketChannelEndPoint.java:116)


at org.eclipse.jetty.io.WriteFlusher.flush(WriteFlusher.java:421)

at org.eclipse.jetty.io.WriteFlusher.completeWrite(WriteFlusher.java:377)

at org.eclipse.jetty.io.SelectableChannelEndPoint$2.run(SelectableChannelEndPoint.java:67)

at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.runTask(AdaptiveExecutionStrategy.java:412)

at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.consumeTask(AdaptiveExecutionStrategy.java:366)


at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.tryProduce(AdaptiveExecutionStrategy.java:268)


at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.lambda$new$0(AdaptiveExecutionStrategy.java:138)


at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:407)


at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:894)


at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1038)


at java.base/java.lang.Thread.run(Thread.java:834)


Caused by: java.io.IOException: Connessione interrotta dal software del computer host


at java.base/sun.nio.ch.SocketDispatcher.writev0(Native Method)


at java.base/sun.nio.ch.SocketDispatcher.writev(SocketDispatcher.java:55)


at java.base/sun.nio.ch.IOUtil.write(IOUtil.java:182)


at java.base/sun.nio.ch.IOUtil.write(IOUtil.java:130)


at java.base/sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:496)


at java.base/java.nio.channels.SocketChannel.write(SocketChannel.java:507)


at org.eclipse.jetty.io.SocketChannelEndPoint.flush(SocketChannelEndPoint.java:110)


... 11 more


[end][sending FIRMWARE]




[ECLSERVICE]-> /eclservices/getfirmware/Ota/BE3/GAMES/131.106.0042.bin
[eclservice][getfirmware][ReadBlob][BE3.GAMES.131.106.0042.bin]
[ReturnFIRMWARE]


Error occurred on line: 98 (utility)


org.eclipse.jetty.io.EofException


at org.eclipse.jetty.io.SocketChannelEndPoint.flush(SocketChannelEndPoint.java:116)


at org.eclipse.jetty.io.WriteFlusher.flush(WriteFlusher.java:421)

at org.eclipse.jetty.io.WriteFlusher.completeWrite(WriteFlusher.java:377)

at org.eclipse.jetty.io.SelectableChannelEndPoint$2.run(SelectableChannelEndPoint.java:67)

at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.runTask(AdaptiveExecutionStrategy.java:412)

at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.consumeTask(AdaptiveExecutionStrategy.java:366)


at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.tryProduce(AdaptiveExecutionStrategy.java:268)


at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.lambda$new$0(AdaptiveExecutionStrategy.java:138)


at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:407)

at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:894)


at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1038)

at java.base/java.lang.Thread.run(Thread.java:834)

Caused by: java.io.IOException: Connessione interrotta dal software del computer host


at java.base/sun.nio.ch.SocketDispatcher.writev0(Native Method)

at java.base/sun.nio.ch.SocketDispatcher.writev(SocketDispatcher.java:55)

at java.base/sun.nio.ch.IOUtil.write(IOUtil.java:182)


at java.base/sun.nio.ch.IOUtil.write(IOUtil.java:130)


at java.base/sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:496)


at java.base/java.nio.channels.SocketChannel.write(SocketChannel.java:507)


at org.eclipse.jetty.io.SocketChannelEndPoint.flush(SocketChannelEndPoint.java:110)


... 11 more


[end][sending FIRMWARE][/CODE]
 
Upvote 0
Two things I would look into:
1) It's a timeout issue. Increase timeout values for both server and client
2) Make sure
Code:
Dim b() As Byte = DB.ReadBlob("my_new_firmware.bin")
returns that you think it returns (not Null, not a 0-byte array, etc)

Maybe check out #2 before #1
 
Upvote 0
Size of byte array is 1963872 about 1.8, 1.9 MB
calling any method with CallSubDelayed - NO
the array is not null and the first call download correctly the file without any timeout.
I expected that concurrent calls to serverHandler would be treated concurrently and not serialized. However, from debugging and the posted log, it appears that the next serverHandler is not invoked until the Sub ReturnFIRMWARE has finished sending the stream, causing clients to time out as observed by OliverA.

Given that I need to update more than a hundred devices, the timeout is a bit too long. When I make the same type of request to Apache, all devices update simultaneously.
 
Upvote 0
This is in Release mode? Debug mode does serialize events (or something like that)
 
Upvote 0
Back
Top