<?xml version="1.0"?>
<paste-with-annotations>
  <paste>
    <number>
      <integer>27383</integer>
    </number>
    <user>
      <string>kefeer</string>
    </user>
    <title>
      <string>udp for factor</string>
    </title>
    <contents>
      <string>IN: udp
USING: kernel alien io-internals sequences strings generic namespaces threads io-internals arrays errors ;
USE: unix-internals

LIBRARY: libc
FUNCTION: ssize_t recv ( int s, void* buf, size_t nbytes, int flags ) ;
FUNCTION: ssize_t recvfrom ( int s, void* buf, size_t nbytes, int flags, sockaddr-in* from, socklen_t* fromlen ) ;
FUNCTION: ssize_t sendto ( int s, void* buf, size_t len, int flags, sockaddr-in* to, socklen_t tolen ) ;

: SOCK_DGRAM 2 ;

: udp-socket-fd ( -- socket )
    PF_INET SOCK_DGRAM 0 socket dup io-error dup init-handle ;

: do-recv ( socket -- data )
    1500 &quot;char&quot; &lt;c-array&gt; dup &gt;r 1500 0 recv r&gt; swap &gt;string [ swap char-nth ] map-with ;

: do-recvfrom ( socket -- data addr port )
    &quot;sockaddr-in&quot; &lt;c-object&gt; dup &gt;r 
    1500 &quot;char&quot; &lt;c-array&gt; dup &gt;r
    rot
    r&gt; 1500 0 r&gt; &quot;sockaddr-in&quot; c-size &lt;int&gt; recvfrom
    dup -1 = [
	drop 2drop f
    ] [
        &gt;string [ swap char-nth ] map-with
        swap dup sockaddr-in-addr inet-ntoa
        swap sockaddr-in-port ntohs
    ] if ;

: do-sendto ( socket data addr port -- ? )
    client-sockaddr ! socket data sockaddr
    &gt;r dup length swap string&gt;char-alien swap
    0
    r&gt; &quot;sockaddr-in&quot; c-size sendto -1 = not ;
    

! ----------------------------------------------------------------

TUPLE: datagram packet addr port ;

: datagram-socket ( port -- fd )
    server-sockaddr udp-socket-fd
    dup SOL_SOCKET SO_REUSEADDR sockopt
    swap dupd &quot;sockaddr-in&quot; c-size bind drop ;

C: datagram ( port -- datagram )
    [ &gt;r datagram-socket f &lt;port&gt; r&gt; set-delegate ] keep
    datagram over set-port-type ;

! ----------------------------------------------------------------

TUPLE: recv-task ;

C: recv-task ( port -- task )
    [ &gt;r &lt;io-task&gt; r&gt; set-delegate ] keep ;

M: recv-task do-io-task
    io-task-port dup port-handle do-recv
    swap set-datagram-packet t ;

M: recv-task task-container drop read-tasks get ;

: wait-receive ( stream -- )
    [ swap &lt;recv-task&gt; add-io-task stop ] callcc0 drop ;

: receive ( stream -- packet )
    dup wait-receive dup pending-error datagram-packet ;

! ----------------------------------------------------------------

TUPLE: recvfrom-task ;

C: recvfrom-task ( port -- task )
    [ &gt;r &lt;io-task&gt; r&gt; set-delegate ] keep ;

M: recvfrom-task do-io-task
    io-task-port dup &gt;r port-handle do-recvfrom
    r&gt; 
    swap over set-datagram-port
    swap over set-datagram-addr
    set-datagram-packet    
    t ;

M: recvfrom-task task-container drop read-tasks get ;

: wait-receive-from ( stream -- )
    [ swap &lt;recvfrom-task&gt; add-io-task stop ] callcc0 drop ;

: receive-from ( stream -- packet addr port )
    dup wait-receive-from dup pending-error
    dup datagram-packet
    over datagram-addr
    rot datagram-port ;

! ----------------------------------------------------------------

TUPLE: sendto-task packet addr dport ;

C: sendto-task ( port -- task )
    [ &gt;r &lt;io-task&gt; r&gt; set-delegate ] keep ;

M: sendto-task do-io-task
    dup dup io-task-port port-handle
    over sendto-task-packet
    rot dup sendto-task-addr
    swap sendto-task-dport
    [ do-sendto drop ] [ &gt;r 2drop 2drop io-task-port r&gt; swap set-port-error ] recover t ;

M: sendto-task task-container drop write-tasks get ;

: wait-send-to ( stream packet addr port -- )
    [ &gt;r &gt;r rot &lt;sendto-task&gt;
      r&gt; over set-sendto-task-dport
      swap over set-sendto-task-addr
      swap over set-sendto-task-packet
      r&gt; swap add-io-task stop ] callcc0 2drop 2drop ;

: send-to ( stream packet addr port -- )
    2swap over &gt;r 2swap wait-send-to r&gt; pending-error ;

! ----------------------------------------------------------------

: &gt;2array&lt; ( a -- x y )
  dup first swap second ;

: (udp-server) ( quot daragram -- )
	[
		tuck
		receive-from 2array
		rot call
		&gt;2array&lt; send-to
	] 2keep
	(udp-server) ;

: udp-server ( port quot -- )
	swap &lt;datagram&gt; (udp-server) ;

: (test-udp-server) ( -- )
	[ 9999 [ swap &quot;-ok&quot; append swap ] udp-server ] in-thread
	9998 &lt;datagram&gt;
	[ &quot;ay&quot; &quot;localhost&quot; 9999 send-to ] keep
	[ receive-from ] keep
	[ &quot;bi&quot; &quot;localhost&quot; 9999 send-to ] keep
	[ receive-from ] keep
	drop ;

USE: test

: test-udp-server ( -- )
	{ t }
	[ 0 &lt;datagram&gt; &lt;sendto-task&gt;
	  &quot;world&quot; over set-sendto-task-dport
	  &quot;localhost&quot; over set-sendto-task-addr
	  &quot;packet&quot; over set-sendto-task-packet
	  do-io-task
	] unit-test
	

	{ &quot;ay-ok&quot; &quot;127.0.0.1&quot; 9999 &quot;bi-ok&quot; &quot;127.0.0.1&quot; 9999 }
	[ (test-udp-server) ] unit-test

	{ { kernel-error 3 0 &quot;world&quot; } }
	[ [ 0 &lt;datagram&gt; &quot;hello&quot; &quot;localhost&quot; &quot;world&quot; send-to ] catch ] unit-test ;
</string>
    </contents>
    <universal-time>
      <integer>3369023366</integer>
    </universal-time>
    <channel>
      <string>#concatenative</string>
    </channel>
    <colorization-mode>
      <string></string>
    </colorization-mode>
    <maybe-spam>
      <null/>
    </maybe-spam>
    <is-unicode>
      <null/>
    </is-unicode>
  </paste>
  <annotation>
    <number>
      <integer>1</integer>
    </number>
    <user>
      <string>kefeer</string>
    </user>
    <title>
      <string>udp for factor</string>
    </title>
    <contents>
      <string>implementation of udp for factor language</string>
    </contents>
    <universal-time>
      <integer>3369023445</integer>
    </universal-time>
    <channel>
      <string>#concatenative</string>
    </channel>
    <colorization-mode>
      <string></string>
    </colorization-mode>
    <maybe-spam>
      <null/>
    </maybe-spam>
    <is-unicode>
      <null/>
    </is-unicode>
  </annotation>
</paste-with-annotations>