This is the mail archive of the guile@cygnus.com mailing list for the guile project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
I think this bug and its solution might be of interest to anyone writing servers in Guile. > We have found that guile provokes a problem with communicating over > sockets, which we believe is due to a problem in solaris libc. Below > is a patch that implements a workaround. I don't really like this solution, but here goes: It's not a bug in the Solaris C library. Basically, Guile is running afoul of the following paragraph in the man page for fdopen, which Guile's `accept' function uses to turn the socket's file descriptor into a buffered I/O port: When a file is opened for update, both input and output may be done on the resulting stream. However, output may not be directly followed by input without an intervening fflush(), fseek(), fsetpos(), or rewind(), and input may not be directly followed by output without an intervening fseek(), fsetpos(), or rewind(), or an input operation that encounters end-of-file. Basically, they're cheap, and the stdio stream only has one buffer, and one pointer into that buffer, for both input and output. So you have to empty the buffer whenever you change directions. When switching from writing to reading, this isn't a problem --- you flush the buffer, and away you go. However, in order to switch from reading to writing, you have to turn off all input buffering, or else the writing will wipe out your unread input. Anyway, the long and the short of it is: for now, just call (fseek PORT 0 SEEK_CUR) between reading and writing, and (force-output PORT) between writing and reading, and things should work. For example, the following version of your Guile server works correctly for me: (define lsocket (socket AF_INET SOCK_STREAM 0)) (define portno 8765) (setsockopt lsocket SOL_SOCKET SO_REUSEADDR 1) (bind lsocket AF_INET INADDR_ANY portno) (listen lsocket 5) (define newconnection #f) (display "Waiting for connections...\n") (set! newconnection (accept lsocket)) (let* ((handle newconnection) (thissock (car handle))) (display "Waiting for input...\n") (let ((input (read thissock))) (display "Has read: ") (write input) (newline) (fseek thissock 0 SEEK_CUR) (write input thissock) (newline thissock))) In the long run, I want to put some logic into Guile to handle this transparently, but it requires a non-trivial change to the port system to do it right, so it's not going to be in 1.3.