shithub: mc

ref: d0ffb958c7247028223c7e53253249d52a47a324
dir: /doc/api/libstd/networking.txt/

View raw version
{
        title: Networking
        description:    libstd: Networking
}
Networking
----------

    pkg std =
            type netaddr = union
                    `Ipv4	byte[4]
                    `Ipv6	byte[16]
            ;;


            /* network connections */
            const dial	: (dialstr : byte[:] -> result(fd, byte[:]))
            const announce	: (ds : byte[:] -> result(fd, byte[:]))
            const listen	: (sock : fd -> result(fd, byte[:]))
            const accept	: (lfd : fd -> result(fd, byte[:]))

            /* ip parsing */
            const ipparse	: (ip : byte[:]	-> option(netaddr))
            const ip4parse	: (ip : byte[:] -> option(netaddr))
            const ip6parse	: (ip : byte[:] -> option(netaddr))

            generic hosttonet	: (v : @a -> @a)
            generic nettohost	: (v : @a -> @a)
    ;;

Summary
-------

This group of functions contains the basic, portable networking functionality
provided by libstd. There are other packages shipped which provide access
to the underlying functionality used to implement this code, and which may
provide more control.

The bulk of the functionality is fairly low level. Most of the client side
networking should be done using nothing more than `dial` and `announce`

Dial describes the endpoint to connect to in the form `proto!host!service`.
`proto` can be any supported protocol.  The host specified can be an IP
address, hostname, or path to a local socket. The service ismay be either a
named service, or a protocol specific port. If the port is not a component of
the address (eg, Unix domain sockets) then it should be ommitted.

On plan 9, the full dial(2) dial string syntax is suported.

Data Types
----------

This contains the infomation that we extract by resolving a host.

    type ipaddr = union
            `Ipv4	byte[4]
            `Ipv6	byte[16]
    ;;

This contains an IP address. Either V4 or V6 is supported.

Connections
----------

    const dial	: (dialstr : byte[:] -> result(fd, byte[:]))

Dial connects to a dial string as described in the summary, returning either a
file descriptor on success, or an error description on failure. The FD
returned is a connection to the server.

    const announce	: (ds : byte[:] -> result(fd, byte[:]))

Announce sets up a file descriptor which is ready to listen for connections,
and binds it to an address. Wildcards can be specified with '*' within the
dial string.

    const listen	: (sock : fd -> result(fd, byte[:]))

Listen specifies that the socket created with `announce` is willing to accept
connections.

    const accept	: (lfd : fd -> result(fd, byte[:]))

Accept takes the returned file descriptor from listen, and returns a file
descriptor that is prepared for reading and writing.

IP Parsing
----------

    const ipparse	: (ip : byte[:]	-> option(netaddr))

Ipparse will parse an IP address. This will recognize either V4 or V6
addresses, and `\`Some \`Ipv4 bits or `\`Some \`Ipv6 bits` as appropriate, or
`\`None` if the address can't be parsed.

    const ip4parse	: (ip : byte[:] -> option(netaddr))

Parses an Ipv4 address from the string `ip`. The syntax expected is dotted
quad notation. Returns `\` Some \`Ipv4 bits` if the address parses successfully, or
`\`None` if parsing fails.

    const ip6parse	: (ip : byte[:] -> option(netaddr))

Parses an Ipv6 address from the string `ip`. Returns `\` Some \`Ipv4 bits` if
the address parses successfully, or `\`None` if parsing fails. Zones are
currently not supported. This is a bug.


Endian flipping
--------------

    generic hosttonet	: (v : @a -> @a)
    generic nettohost	: (v : @a -> @a)


Flips the bits in an integer to match the expected. These functions should be
avoided in favor of explicit packing functions.

Examples
--------

Some simple examples of how to use the Myrddin networking API

#### Echo Server

	use std

	const Dialstr = "tcp!*!1234"
	const main = {
		var lfd, afd
		var buf : byte[1024]

		match std.announce(Dialstr)
		| `std.Ok f:    lfd = f
		| `std.Fail e:  std.fatal("unable to announce on {}: {}\n", Dialstr, e)
		;;

		match std.listen(lfd)
		| `std.Ok f:    afd = f
		| `std.Fail e:  std.fatal("unable to listen on {}: {}\n", Dialstr, e)
		;;

		while true
			match std.accept(afd)
			| `std.Ok fd:
				match std.read(fd, buf[:])
				| `std.Ok n:
					std.writeall(fd, buf[:n])
				| `std.Fail e:
					std.put("lost conection while reading: {}\n", e)
				;;
				std.close(fd)
			| `std.Fail e:
				std.fatal("unable to accept connection on {}: {}\n", Dialstr, e)
			;;
		;;
	}
		

#### Echo Client

	use std

	const Dialstr = "tcp!localhost!1234"
	const main = {args : byte[:][:]
		var req, resp

		match std.dial(Dialstr)
		| `std.Ok fd:
			req = std.strjoin(args[1:], " ")
			std.writeall(fd, req)
			resp = std.try(std.fslurp(fd))
			std.put("{}\n", resp)
		| `std.Fail e:
			std.fatal("unable to dial {}: {}\n", Dialstr, e)
		;;
	}

Bugs
----
The errors returned are strings, when they should be unions with default
formatting functions.