chickadee » udp6

udp6

udp6 is an interface to User Datagram Protocol sockets over IPv4 and IPv6.

Overview

This is a superset of the functionality of the udp extension, primarily adding IPv6 support while maintaining a backwards-compatible API. It is implemented on top of the socket egg,

Interface

udp-open-socket #!optional familyprocedure
udp-open-socket* #!optional familyprocedure

Returns a new UDP socket object, which is simply a datagram socket object created by the socket egg.

The optional argument family can be 'inet for IPv4 or 'inet6 for IPv6; the default is 'inet.

(Note: The starred version is provided for API compatibility; it is exactly the same as the unstarred version, as all sockets in the socket egg are nonblocking at the OS level.)

udp-bind! SOCKET HOST PORTprocedure

Binds a UDP socket to an address and port as specified by HOST and PORT. HOST may be a string consisting of an IP address or hostname, or #f, in which case the unspecified address is used. If PORT is 0, a port will be allocated by the system automatically.

To use IPv6, create a UDP socket with family 'inet6. If the socket is in the IPv4 address family, as is the default, binding to an IPv6 address will raise an exception. Example:

(define s (udp-open-socket 'inet6))
(udp-bind! s "::" 1337)

Binding to the unspecified IPv6 address "::" may, depending on your OS, also allow connections via IPv4. See socket-bind in the socket egg for an example of disabling this behavior.

udp-connect! SOCKET HOST PORTprocedure

Connect a socket. In the case of UDP this does nothing more than associate a peer address with the socket in the kernel for use with later calls to send(2). UDP is a connectionless protocol.

udp-send SOCKET STRINGprocedure

Send the bytes in STRING through SOCKET to its peer, as specified with a previous call to udp-connect!. If the socket is not connected, the system will return an error.

udp-sendto SOCKET HOST PORT STRINGprocedure

Send the bytes in STRING through SOCKET to PORT on HOST.

udp-recv SOCKET LENGTHprocedure

Receive a packet of up to LENGTH bytes, blocking the current thread until data is available.

Returns two values: the number of bytes received and a string containing the message received.

udp-recvfrom SOCKET LENGTHprocedure

Same as udp-recv except that two additional values are returned: the host string and port number from which the packet was received.

udp-close-socket SOCKETprocedure

Close a socket.

udp-socket? THINGprocedure

Test whether THING is a UDP socket.

udp-bound? SOCKETprocedure

Test whether a UDP socket is bound to a local address and port.

udp-connected? SOCKETprocedure

Test whether a peer address and port has been associated with a UDP socket with a call to udp-connect!.

udp-bound-port SOCKETprocedure

Returns the port to which the socket is bound.

UDP ports

Input and output Scheme ports can be created from a connected UDP socket using socket-i/o-ports from the socket egg. An example will be provided in the future.

Example

Daytime client

Connect to the daytime service on localhost:13, and echo back the current time. You must specify whether to connect over IPv4 or IPv6.

;; daytime-client.scm
(use udp6)
(define port 13)
(define family 'inet)
(define s (udp-open-socket family))
(udp-connect! s "localhost" port)  ; daytime service
(udp-send s "\n")
(receive (n data host port) (udp-recvfrom s 64)
  (print n " bytes from " host ":" port ": " data))
(udp-close-socket s)
 
;; If family is 'inet, prints:
;;  26 bytes from 127.0.0.1:13: Wed Dec 24 11:53:14 2003
;; If family is 'inet6, prints:
;;  26 bytes from ::1:13: Wed Dec 24 11:53:14 2003

If you don't have a daytime service running---and you probably don't---simulate it with netcat as in:

# this will work for one read
$ date | nc -u -l -6 1313

and, setting port to 1313 in the script, we get:

29 bytes from ::1:1313: Tue Feb 17 23:05:10 CST 2015

Alternatively, see Daytime server for an implementation using udp6.

Daytime client using socket

This example can also be written directly with the socket egg:

(use socket)
(define s (socket-connect/ai
           (address-information "localhost" 13 type: sock/dgram)))
(socket-send s "\n")
(receive (data addr) (socket-receive-from s 64)
  (print (string-length data) " bytes from "
         (sockaddr->string addr) ": " data))
(socket-close s)

;; Prints one of the following:
;; 26 bytes from 127.0.0.1:13: Sat Feb 12 03:53:46 CST 2011
;; 26 bytes from [::1]:13: Sat Feb 12 03:53:46 CST 2011

In the latter case, we do not need to specify the address family; address-information returns all IPv4 and IPv6 addresses associated with "localhost", and socket-connect/ai tries each in turn. The udp6 egg does not currently expose this shortcut.

Cat server

Listen on both IPv6 and IPv4 (on most operating systems), port 1337, and echo messages to stdout.

(use udp6)
(define s (udp-open-socket 'inet6))
(udp-bind! s "::" 1337)
(let loop ()
  (receive (len str host port) (udp-recvfrom s 1024)
      (print "received " len " bytes from [" host "]:" port " : " str))
      (loop))
(udp-close-socket s)

After running this script in a window, we can see the UDP listener:

$ netstat -n -p udp|grep 1337
udp46      0      0  *.1337                 *.*

Then we can send data to the server over both IPv4 and IPv6 using netcat:

$ nc -6 -u localhost 1337
hello
^C
$ nc -4 -u localhost 1337
hi
^C

The script should now produce output similar to:

received 6 bytes from [::1]:62028 : hello
received 3 bytes from [::ffff:127.0.0.1]:61031 : hi

Daytime server

Using daytime-client.scm from above (modified to use port 1313), you can connect to this example daytime server:

;; daytime-server.scm
(use udp6 posix)
(define s (udp-open-socket 'inet6))
(udp-bind! s "::" 1313)
(let loop ()
  (receive (len str host port) (udp-recvfrom s 1024)
      (udp-sendto s host port (seconds->string))
      (loop))
(udp-close-socket s)
$ csi -script daytime-server.scm &
$ csi -script daytime-client.scm
24 bytes from ::1:1313: Tue Feb 17 23:23:19 2015
$ csi -script daytime-client.scm
24 bytes from ::1:1313: Tue Feb 17 23:23:21 2015

Bugs and limitations

Multicast is not yet implemented.

About this egg

Source

https://github.com/ursetto/udp6-egg

Author

Jim Ursetto. Originally by Category 5, with several enhancements by Daishi Kato, but has been rewritten on top of the socket egg.

Version History

0.2
Add Chicken 5 support. Add simple daytime client/server, echo server to tests/ dir; not used during -test.
0.1
Initial release

See udp for previous history (up to 1.14).

License

Copyright (c) 2011-2019, Jim Ursetto
Copyright (c) 2003-2004, Category 5
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

  Redistributions of source code must retain the above copyright notice,
  this list of conditions and the following disclaimer. Redistributions in
  binary form must reproduce the above copyright notice, this list of
  conditions and the following disclaimer in the documentation and/or
  other materials provided with the distribution. Neither the name of the
  author nor the names of its contributors may be used to endorse or
  promote products derived from this software without specific prior
  written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Contents »