[R-pkg-devel] socketConnection, delay when reading from

Tomas Kalibera tom@@@k@||ber@ @end|ng |rom gm@||@com
Wed Dec 8 12:40:19 CET 2021


On 12/8/21 12:20 PM, Ben Engbers wrote:
> Op 07-12-2021 om 23:49 schreef Ben Engbers:
>
> After a long nightly session, I ended up with inserting a wait between 
> sending the authentication nonce and reading the status byte.
>
> writeBin(auth, private$conn)
> Sys.sleep(.1)
> Accepted <- readBin(conn, what = "raw", n = 1)
>
> The new code, which now uses a non-blocking socket, takes less than 4 
> seconds to execute the 53 tests. Compared to the 120 seconds when 
> using a blocking socket, this was worth the effort.

Ok, this confirms there is a race condition, but the next step should be 
removing it, so that it works reliably. Actually, one way to test that 
such programs are race-free is to actually on purpose insert sleeps at 
various locations - the programs then should still work.

I am not able to give more specific advice based on the code snippet you 
sent yesterday, but in principle, you can use socketSelect() to wait for 
the connection to become ready to be read from. In either case, there 
needs to be some way to tell whether the received data is complete. 
Either you know the length, or there is some special mark in the data, 
there has to be something.

If you need more help from people on the list, it might be better to 
send a small, but full complete example, so also with a server, so that 
it is something people could run and reproduce.

Best
Tomas

>
> Ben
>
>
>> Hi Tomas,
>>
>> I have implemented your suggestions as follows: (I'm not certain yet 
>> if the first check in done - total_length == 0 is realy needed)
>>
>> Creating the socket:
>>
>> CreateSocket = function(host, port = 1984L, username, password) {
>>    tryCatch(
>>      {conn <- private$conn <- socketConnection(
>>        host = "localhost", port,
>>        open = "w+b", server = FALSE, blocking = FALSE, encoding = 
>> "UTF-8")
>>      }, error = function(e) {
>>        stop("Cannot open the connection")
>>       }
>>    )
>>
>> #### Authenticating
>>
>> response <- readBin_(conn) %>% rawToChar()
>> ===> # browser()
>> splitted <-strsplit(response, "\\:")
>> ifelse(length(splitted[[1]]) > 1,
>>    { realm <- splitted[[1]][1]
>>      code  <- paste(username, realm, password, sep=":")
>>      nonce <- splitted[[1]][2] },
>>    { code  <- password
>>      nonce <- splitted[[1]][1]}
>>    )
>> code <- md5(paste(md5(code), nonce, sep = "")) %>% charToRaw()
>> # send username + code
>> auth <- c(charToRaw(username), as.raw(0x00), code, as.raw(0x00))
>> writeBin(auth, private$conn)
>> Accepted <- readBin(conn, what = "raw", n = 1) == 0x00
>> if (!Accepted) {
>> close(private$conn)
>> stop("Access denied")
>> }
>
>> The first time readBin is used is while authenticating a new session.
>> This code fails ;-(
>>
>> But when I insert a  call to browser() after the first authentication 
>> line, I can execute all the following code without problems. This 
>> results in a fully functional session. And all the other following 
>> calls to readBin_ return the correct data.
>> This means that 'done' and 'readBin' do exactly what they are 
>> intended to do.
>>
>> Question
>> Why does creating and authenticating fail when a call to browser() is 
>> missing? (Or why does authentication succeed after I have used the 
>> debugger?
>>
>> Best,
>> Ben



More information about the R-package-devel mailing list