Lispworks Windows UDP behaviour

Frank James frank.a.james at gmail.com
Sun May 24 19:57:25 UTC 2015


Hi Chun,

Thanks for looking into this. I've just pulled the most recent codes from
github and have had a little play with them. I now get an error signalled
on the socket-receive when I expect an error (rather than a simple -1 count
as before). This is good.

However, I am still seeing the socket-state behaviour I described before,
along with a new bug that has probably been introduced by the recent
changes.

Consider the following simple function which listens for UDP port 8001 for
up to 4 iterations:

(defun usocket-test ()
 (let ((s (usocket:socket-connect nil nil
   :protocol :datagram
  :element-type '(unsigned-byte 8)
  :local-port 8001)))
   (unwind-protect
       (do ((i 0 (1+ i))
            (buffer (make-array 1024 :element-type '(unsigned-byte 8)
:initial-element 0))
            (done nil))
           ((or done (= i 4))
            nil)
         (when (usocket:wait-for-input s :ready-only t :timeout 10)
           (format t "~D state ~S~%" i (usocket::state s))
           (handler-case
               (multiple-value-bind (buffer count remote-host remote-port)

                   (usocket:socket-receive s buffer 1024)
                 (handler-case
                     (usocket:socket-send s (subseq buffer 0 count)
                                          :host remote-host
                                          :port remote-port)
                   (error (c)
                     (format t "socket-send error: ~A~%" c))))
             (error (c)
               (format t "socket-receive error: ~A~%" c)))))
     (usocket:socket-close s))))


after calling this from your repl, from another process send a UDP packet
to port 8001 to get things going. I get the following output:

0 state :READ
socket-send error: #<STANDARD-GENERIC-FUNCTION USOCKET:SOCKET-SEND
21CADCFA> is called with unpaired keyword in (2130706433 :PORT 58279).
1 state :READ
socket-receive error: MAKE-INSTANCE is called with keyword :SOCKET among
the arguments (USOCKET:NS-TRY-AGAIN-CONDITION :SOCKET 2604) which is not
one of (:HOST-OR-IP).
2 state :READ
socket-receive error: MAKE-INSTANCE is called with keyword :SOCKET among
the arguments (USOCKET:NS-TRY-AGAIN-CONDITION :SOCKET 2604) which is not
one of (:HOST-OR-IP).
3 state :READ
socket-receive error: MAKE-INSTANCE is called with keyword :SOCKET among
the arguments (USOCKET:NS-TRY-AGAIN-CONDITION :SOCKET 2604) which is not
one of (:HOST-OR-IP).
NIL

My observations:
1. The initial socket-receive succeeds (as expected).
2. The initial socket-send fails with an error I've not seen before and
can't diagnose...
3. Subsequent calls to wait-for-input return immediately because the socket
is still in a :READ state, even though I already successfully called
socket-receive in the first iteration.
4. Subsequent calls to socket-receive now fail with a different error I
can't diagnose.

If I didn't have the max iteration cap, this would spin using 100% of a CPU
core and adding around 2MB to the heap per second (on my machine), maxing
out the 1GB personal edition heap limit in a short space of time. So I
think it's a pretty serious issue. I mainly use SBCL, I use LispWorks
occasionally to make sure my codes work on at least 1 other implementation,
so I'm not exactly a LispWorks expert.

If you want any more explanations, clarifications or examples I'll be happy
to do my best to help.

As before, I'm using LispWorks personal edition 6.1.1 on Windows 8.1.

Frank.



On 22 May 2015 at 09:24, Chun Tian (binghe) <binghe.lisp at gmail.com> wrote:

> Hi Frank,
>
> Today I have modified SOCKET-SEND and SOCKET-RECEIVE for LispWorks, to be
> able to detect and report socket errors.  I think in this way, these APIs
> on LispWorks could behavior closer to other platforms.
>
> Now on Windows, your test code should return a
> USOCKET:CONNECTION-RESET-ERROR condition, which equals to WSA error
> ECONNRESET.  However, when I test the same code on Mac OS X, it instead
> returns USOCKET:CONNECTION-REFUSED-ERROR, I think this is a behavior of BSD
> sockets.
>
> I hope you can try latest usocket code from Git [1], to see if it works
> better for your case now. My code changes commit can be seen here [2].
>
> For wait-for-input, I can’t see what you see (the socket object remains in
> a :READ state), if you still think this is an issue, I hope you can create
> another test code to demonstrate this issue.
>
> Regards,
>
> Chun
>
> [1] https://github.com/usocket/usocket
> [2]
> https://github.com/usocket/usocket/commit/13386639889fa812540fc4f77824c47e7616db37
>
> Il giorno 10/apr/2015, alle ore 23:00, Frank James <
> frank.a.james at gmail.com> ha scritto:
>
> > I've been testing some UDP codes on Lispworks (personal 32bit Windows
> version) and have encountered some undocumented behaviour, I think it's a
> matter of opinion whether it's a bug or not but it should probably have a
> sentence or two documenting it somewhere.
> >
> > Basically I'm sending a UDP packet to a host and listening for a reply,
> using socket-send and socket-receive. If the host in question is not
> listening for UDP traffic on that particular port, the Windows socket API
> says it should return an ECONNRESET error immediately on the socket-receive
> call, this is indicated by a -1 return value from the underlying recvfrom
> call.
> >
> > When this happens the Lispworks backend code returns a length of -1 (and
> buffer nil). This is perfectly acceptable behaviour I think (although it'd
> be somewhat nicer to signal an error, but that's a matter of taste). But it
> should be documented that checking the length here is the correct way to
> detect an error occurred.
> >
> > Example code would be something like:
> >
> > (let ((sock (usocket:socket-connect "localhost" 1234 :protocol :datagram
> :element-type '(unsigned-byte 8))))
> >   (unwind-protect
> >     (progn
> >       (usocket:socket-send sock (make-array 16 :element-type
> '(unsigned-byte 8) :initial-element 0) 16)
> >       (let ((buffer (make-array 16 :element-type '(unsigned-byte 8)
> :initial-element 0)))
> >         (usocket:socket-receive sock buffer 16)))
> >     (usocket:socket-close sock)))
> >
> >
> > What is somewhat more annoying is that the socket object remains in a
> :READ state. This means that a polling loop using wait-for-input spins
> continuously, with each socket-receive returning -1 (as explained above).
> Probably the socket state should be cleared if a socket-receive fails.
> >
> > Apologies if this is all well-known to those reading this list, but it
> caused me 10 minutes of head scratching earlier today and thought it was
> worth mentioning.
> >
> > Frank.
> >
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mailman.common-lisp.net/pipermail/usocket-devel/attachments/20150524/4f8ab70e/attachment.html>


More information about the usocket-devel mailing list