Socket.Address
Many socket functions in this package take an IP address or the endpoint of a socket as a value of this module rather than as text, and this module defines those values: IPv4 and IPv6 addresses, and the endpoints of sockets.
An Address is valid by construction. It is made only here: by parsing text with
fromString, from bytes with fromOctets, as one of the
well-known addresses, or with unmapIPv4. toString prints every
address in one canonical form, which fromString reads back as the same address. Parsing and
printing are pure Elm and never touch the network, so they behave the same on every platform
and backend.
Host names are not addresses: fromString "localhost" is Nothing. Resolve a name with
Socket.lookup, or connect to one directly with
Socket.Tcp.connectToHost.
Four terms are used throughout.
An IPv6 address may carry a scope (also called a zone): the text after a %, such as the eth0
of fe80::1%eth0, which names the network interface a link-local address belongs to. The scope
is part of the address, so fe80::1%eth0 and fe80::1 are not equal.
The unspecified address, 0.0.0.0 or ::, names no particular host. any returns it.
An IPv4-mapped address is an IPv6 address that carries an IPv4 address in its last 32 bits,
written ::ffff:a.b.c.d. It is an IPv6 address and is not equal to the IPv4 address it carries;
unmapIPv4 returns that IPv4 address. A TCP listener or UDP socket on the
unspecified IPv6 address with ipv6Only = False sees its IPv4 peers this way.
An endpoint is where a socket is: an address and a port, or the path of a Unix domain socket.
Socket.Address.fromString "::FFFF:127.0.0.1"
|> Maybe.map Socket.Address.toString
--> Just "::ffff:127.0.0.1"Addresses
type Addresstype Family
= IPv4
| IPv6Which of the two kinds of address a value is: IPv4, 32 bits, or IPv6, 128 bits. An
IPv4-mapped address is IPv6.
fromString : String -> Maybe AddressParses the text of an IPv4 or IPv6 address, giving Nothing for anything that is not one.
- IPv4: four decimal fields from 0 to 255, separated by dots, each of 1 to 3 ASCII digits.
A leading zero is not allowed (
"01.2.3.4"is rejected). - IPv6: the text form of RFC 4291: groups of 1 to 4 hexadecimal digits (in either case)
separated by colons, at most one
::standing for one or more zero groups, and optionally a dotted IPv4 address, written as above, in place of the last two groups ("::ffff:192.0.2.1"). Without::there must be exactly 8 groups; with it, at most 7. A dotted ending counts as two groups. - An IPv6 address may end in a scope:
%followed by 1 to 15 characters fromA-Z,a-z,0-9,_,.and-, such as the interface name"eth0"or the interface number"2". An IPv4 address cannot have a scope.
Anything else, including surrounding whitespace, gives Nothing.
fromString "localhost"
--> NothingtoString : Address -> StringPrints an address in its canonical form, which fromString reads back as the
same address.
- IPv4: dotted decimal,
"127.0.0.1". - IPv6 (RFC 5952): lower-case hexadecimal without leading zeros; the longest run of two or more
zero groups (the leftmost one if there is a tie) is written
::, and a single zero group is written0. IPv4-mapped addresses are written"::ffff:a.b.c.d". The scope, if any, follows after a%.
fromString "2001:DB8:0:0:1:0:0:1" |> Maybe.map toString
--> Just "2001:db8::1:0:0:1"fromOctets : List Int -> Maybe AddressBuilds an address from its bytes in network order: 4 values give an IPv4 address and 16 values
an IPv6 address (without a scope). Any other length, or a value outside 0–255, gives Nothing.
fromOctets [ 127, 0, 0, 1 ] |> Maybe.map toString
--> Just "127.0.0.1"toOctets : Address -> List IntReturns the bytes of an address in network order: 4 for IPv4, 16 for IPv6. The scope is not included.
family : Address -> FamilyReturns the family of an address. An IPv4-mapped address such as "::ffff:127.0.0.1" is an IPv6
address; unmapIPv4 turns it into an IPv4 one.
Well-known addresses
loopback : Family -> AddressReturns the loopback address of a family, 127.0.0.1 or ::1, the address by which a host
reaches itself. isLoopback accepts more addresses than these two.
any : Family -> AddressReturns the unspecified address of a family, 0.0.0.0 or ::.
As the address to listen or bind on, it stands for every local interface rather than one.
Whether the IPv6 one also takes IPv4 traffic is set by ipv6Only in
Socket.Tcp.ListenOptions and
Socket.Udp.BindOptions. Http.Server has no
ipv6Only and listens as if it were False.
Classification
isLoopback : Address -> BoolReturns True for loopback addresses: 127.0.0.0/8, ::1, and the IPv4-mapped forms of
127.0.0.0/8 (such as ::ffff:127.0.0.1). The scope is ignored.
isUnspecified : Address -> BoolReturns True for the unspecified addresses 0.0.0.0 and ::. The scope is ignored. Unlike
isLoopback, this does not look inside an IPv4-mapped address: ::ffff:0.0.0.0
is not unspecified.
isIPv4Mapped : Address -> BoolReturns True for IPv4-mapped IPv6 addresses (::ffff:0:0/96), such as ::ffff:127.0.0.1,
whatever their scope.
unmapIPv4 : Address -> AddressTurns an IPv4-mapped IPv6 address into the IPv4 address it carries (::ffff:127.0.0.1 becomes
127.0.0.1), dropping any scope. Every other address is returned unchanged.
Endpoints
type Endpoint
= Inet InetEndpoint
| Unix PathWhere a stream socket is: one end of a connection, or the place a listener listens.
Inet carries an IP address and a port.
Unix carries the path of a Unix domain socket. The empty path stands for an
unnamed socket: a connection made with Socket.Unix has it as its local endpoint, and a
connection accepted by a Unix listener has it as its remote endpoint.
type alias InetEndpoint =
{ address : Address, port_ : Int }An IP address and a port number.
port_ has its underscore because port is a reserved word in Elm. It is a plain Int, and
the type does not restrict it to the port range 0–65535.
An IPv4 or IPv6 address, valid by construction; an IPv6 address may also carry a scope.
A value is obtained from
fromString,fromOctets,loopback,anyorunmapIPv4, so everyAddressis valid:toStringprints it as text thatfromStringreads back as the same address.Two addresses are equal (
==) when they have the same family, the same bits and the same scope text, compared exactly. An IPv4-mapped address is therefore never equal to the IPv4 address it carries, andfe80::1%eth0is not equal tofe80::1%ETH0.