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
main:
Sub Process_Globals
    Private srvr As Server
end sub
Sub AppStart (Args() As String)
    ....
    ...
     srvr.AddHandler("/eclservices/*", "eclservice", False)
     ....
     ...
     StartMessageLoop
 end sub
in eclservice server handler

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


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

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 ?
 

fabton1963

Member
Licensed User
Longtime User
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

log:
[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]
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Two things I would look into:
1) It's a timeout issue. Increase timeout values for both server and client
2) Make sure
B4X:
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

fabton1963

Member
Licensed User
Longtime User
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

OliverA

Expert
Licensed User
Longtime User
This is in Release mode? Debug mode does serialize events (or something like that)
 
Upvote 0
Top