---
name: "gen_udp"
section: "3erl"
platform: "linux"
package: "erlang-manpages"
version: "1:25.2.3+dfsg-1+deb12u4"
release: "Debian 12 (Bookworm)"
platforms: ["linux"]
url: "https://new.carta.tech/gen_udp"
---

# gen\_udp(3erl)

Interface to UDP sockets.

## NAME

gen\_udp - Interface to UDP sockets.

## DESCRIPTION

This module provides functions for communicating with sockets using the UDP protocol.

**Note:**

Functions that create sockets can take an optional option; *{inet\_backend, Backend}* that, if specified, has to be the first option. This selects the implementation backend towards the platform's socket API.

This is a *temporary* option that will be ignored in a future release.

The default is *Backend = inet* that selects the traditional *inet\_drv.c* driver. The other choice is *Backend = socket* that selects the new *socket* module and its NIF implementation.

The system default can be changed when the node is started with the application *kernel*'s configuration variable *inet\_backend*.

For *gen\_udp* with *inet\_backend = socket* we have tried to be as "compatible" as possible which has sometimes been impossible. Here is a list of cases when the behaviour of inet-backend *inet* (default) and *socket* are different:

- \*

  The option read\_packets is currently *ignored*.

## DATA TYPES

```
option() =
    {active, true | false | once | -32768..32767} |
    {add_membership, membership()} |
    {broadcast, boolean()} |
    {buffer, integer() >= 0} |
    {debug, boolean()} |
    {deliver, port | term} |
    {dontroute, boolean()} |
    {drop_membership, membership()} |
    {header, integer() >= 0} |
    {high_msgq_watermark, integer() >= 1} |
    {low_msgq_watermark, integer() >= 1} |
    {mode, list | binary} |
    list | binary |
    {multicast_if, multicast_if()} |
    {multicast_loop, boolean()} |
    {multicast_ttl, integer() >= 0} |
    {priority, integer() >= 0} |
    {raw,
     Protocol :: integer() >= 0,
     OptionNum :: integer() >= 0,
     ValueBin :: binary()} |
    {read_packets, integer() >= 0} |
    {recbuf, integer() >= 0} |
    {reuseaddr, boolean()} |
    {sndbuf, integer() >= 0} |
    {tos, integer() >= 0} |
    {tclass, integer() >= 0} |
    {ttl, integer() >= 0} |
    {recvtos, boolean()} |
    {recvtclass, boolean()} |
    {recvttl, boolean()} |
    {ipv6_v6only, boolean()}
```

```
option_name() =
    active | broadcast | buffer | debug | deliver | dontroute |
    header | high_msgq_watermark | low_msgq_watermark | mode |
    multicast_if | multicast_loop | multicast_ttl | priority |
    {raw,
     Protocol :: integer() >= 0,
     OptionNum :: integer() >= 0,
     ValueSpec ::
         (ValueSize :: integer() >= 0) | (ValueBin :: binary())} |
    read_packets | recbuf | reuseaddr | sndbuf | tos | tclass |
    ttl | recvtos | recvtclass | recvttl | pktoptions |
    ipv6_v6only
```

```
open_option() =
    {ip, inet:socket_address()} |
    {fd, integer() >= 0} |
    {ifaddr, inet:socket_address()} |
    inet:address_family() |
    {port, inet:port_number()} |
    {netns, file:filename_all()} |
    {bind_to_device, binary()} |
    option()
```

```
socket()
```

As returned by *open/1,2*.

```
multicast_if() = ip_multicast_if() | ip6_multicast_if()
```

```
ip_multicast_if() = inet:ip4_address()
```

```
ip6_multicast_if() = integer()
```

For IPv6 this is an interface index (an integer).

```
membership() = ip_membership() | ip6_membership()
```

```
ip_membership() =
    {MultiAddress :: inet:ip4_address(),
     Interface :: inet:ip4_address()} |
    {MultiAddress :: inet:ip4_address(),
     Address :: inet:ip4_address(),
     IfIndex :: integer()}
```

The tuple with size 3 is \*not\* supported on all platforms. 'ifindex' defaults to zero (0) on platforms that supports the 3-tuple variant.

```
ip6_membership() =
    {MultiAddress :: inet:ip6_address(), IfIndex :: integer()}
```

## EXPORTS

```
close(Socket) -> ok
```

Types:

Socket = socket()\

Closes a UDP socket.

```
controlling_process(Socket, Pid) -> ok | {error, Reason}
```

Types:

Socket = socket()\
 Pid = pid()\
 Reason = closed \| not\_owner \| badarg \| inet:posix()\

Assigns a new controlling process *Pid* to *Socket*. The controlling process is the process that receives messages from the socket. If called by any other process than the current controlling process, *{error, not\_owner}* is returned. If the process identified by *Pid* is not an existing local pid, *{error, badarg}* is returned. *{error, badarg}* may also be returned in some cases when *Socket* is closed during the execution of this function.

```
connect(Socket, SockAddr) -> ok | {error, Reason}
```

Types:

Socket = socket()\
 SockAddr = socket:sockaddr\_in() \| socket:sockaddr\_in6()\
 Reason = inet:posix()\

Connecting a UDP socket only means storing the specified (destination) socket address, as specified by *SockAddr*, so that the system knows where to send data.

This means that it is not necessary to specify the destination address when sending a datagram. That is, we can use *send/2*.

It also means that the socket will only received data from this address.

```
connect(Socket, Address, Port) -> ok | {error, Reason}
```

Types:

Socket = socket()\
 Address = inet:socket\_address() \| inet:hostname()\
 Port = inet:port\_number()\
 Reason = inet:posix()\

Connecting a UDP socket only means storing the specified (destination) socket address, as specified by *Address* and *Port*, so that the system knows where to send data.

This means that it is not necessary to specify the destination address when sending a datagram. That is, we can use *send/2*.

It also means that the socket will only received data from this address.

```
open(Port) -> {ok, Socket} | {error, Reason}
```

```
open(Port, Opts) -> {ok, Socket} | {error, Reason}
```

Types:

Port = inet:port\_number()\
 Opts = \[inet:inet\_backend() \| open\_option()\]\
 Socket = socket()\
 Reason = system\_limit \| inet:posix()\

Associates a UDP port number (*Port*) with the calling process.

The following options are available:

- ***list*:**

  Received *Packet* is delivered as a list.

- ***binary*:**

  Received *Packet* is delivered as a binary.

- ***{ip, Address}*:**

  If the host has many network interfaces, this option specifies which one to use.

- ***{ifaddr, Address}*:**

  Same as *{ip, Address}*. If the host has many network interfaces, this option specifies which one to use.

  However, if this instead is an *socket:sockaddr\_in()* or *socket:sockaddr\_in6()* this takes precedence over any value previously set with the *ip* options. If the *ip* option comes *after* the *ifaddr* option, it may be used to *update* its corresponding field of the *ifaddr* option (the *addr* field).

- ***{fd, integer() \>= 0}*:**

  If a socket has somehow been opened without using *gen\_udp*, use this option to pass the file descriptor for it. If *Port* is not set to *0* and/or *{ip, ip\_address()}* is combined with this option, the *fd* is bound to the specified interface and port after it is being opened. If these options are not specified, it is assumed that the *fd* is already bound appropriately.

- ***inet6*:**

  Sets up the socket for IPv6.

- ***inet*:**

  Sets up the socket for IPv4.

- ***local*:**

  Sets up a Unix Domain Socket. See *inet:local\_address()*

- ***{udp\_module, module()}*:**

  Overrides which callback module is used. Defaults to *inet\_udp* for IPv4 and *inet6\_udp* for IPv6.

- ***{multicast\_if, Address}*:**

  Sets the local device for a multicast socket.

- ***{multicast\_loop, true \| false}*:**

  When *true*, sent multicast packets are looped back to the local sockets.

- ***{multicast\_ttl, Integer}*:**

  Option *multicast\_ttl* changes the time-to-live (TTL) for outgoing multicast datagrams to control the scope of the multicasts.

  Datagrams with a TTL of 1 are not forwarded beyond the local network. Defaults to *1*.

- ***{add\_membership, {MultiAddress, InterfaceAddress}}*:**

  Joins a multicast group.

- ***{drop\_membership, {MultiAddress, InterfaceAddress}}*:**

  Leaves a multicast group.

- ***Opt*:**

  See *inet:setopts/2*.

The returned socket *Socket* is used to send packets from this port with *send/4*. When UDP packets arrive at the opened port, if the socket is in an active mode, the packets are delivered as messages to the controlling process:

```
{udp, Socket, IP, InPortNo, Packet} % Without ancillary data
{udp, Socket, IP, InPortNo, AncData, Packet} % With ancillary data
```

The message contains an *AncData* field if any of the socket options *recvtos*, *recvtclass* or *recvttl* are active, otherwise it does not.

If the socket is not in an active mode, data can be retrieved through the *recv/2,3* calls. Notice that arriving UDP packets that are longer than the receive buffer option specifies can be truncated without warning.

When a socket in *{active, N}* mode (see *inet:setopts/2* for details), transitions to passive (*{active, false}*) mode, the controlling process is notified by a message of the following form:

```
{udp_passive, Socket}
```

*IP* and *InPortNo* define the address from which *Packet* comes. *Packet* is a list of bytes if option *list* is specified. *Packet* is a binary if option *binary* is specified.

Default value for the receive buffer option is *{recbuf, 8192}*.

If *Port == 0*, the underlying OS assigns a free UDP port, use *inet:port/1* to retrieve it.

```
recv(Socket, Length) -> {ok, RecvData} | {error, Reason}
```

```
recv(Socket, Length, Timeout) -> {ok, RecvData} | {error, Reason}
```

Types:

Socket = socket()\
 Length = integer() \>= 0\
 Timeout = timeout()\
 RecvData = \
\
     {Address, Port, Packet} \| {Address, Port, AncData, Packet}\
 Address = inet:ip\_address() \| inet:returned\_non\_ip\_address()\
 Port = inet:port\_number()\
 AncData = inet:ancillary\_data()\
 Packet = string() \| binary()\
 Reason = not\_owner \| timeout \| inet:posix()\

Receives a packet from a socket in passive mode. Optional parameter *Timeout* specifies a time-out in milliseconds. Defaults to *infinity*.

If any of the socket options *recvtos*, *recvtclass* or *recvttl* are active, the *RecvData* tuple contains an *AncData* field, otherwise it does not.

```
send(Socket, Packet) -> ok | {error, Reason}
```

Types:

Socket = socket()\
 Packet = iodata()\
 Reason = not\_owner \| inet:posix()\

Sends a packet on a connected socket (see *connect/2* and *connect/3*).

```
send(Socket, Destination, Packet) -> ok | {error, Reason}
```

Types:

Socket = socket()\
 Destination = \
\
     {inet:ip\_address(), inet:port\_number()} \|\
\
     inet:family\_address() \|\
\
     socket:sockaddr\_in() \|\
\
     socket:sockaddr\_in6()\
 Packet = iodata()\
 Reason = not\_owner \| inet:posix()\

Sends a packet to the specified *Destination*.

This function is equivalent to *send(Socket, Destination, \[\], Packet)*.

```
send(Socket, Host, Port, Packet) -> ok | {error, Reason}
```

Types:

Socket = socket()\
 Host = inet:hostname() \| inet:ip\_address()\
 Port = inet:port\_number() \| atom()\
 Packet = iodata()\
 Reason = not\_owner \| inet:posix()\

Sends a packet to the specified *Host* and *Port*.

This clause is equivalent to *send(Socket, Host, Port, \[\], Packet)*.

```
send(Socket, Destination, AncData, Packet) -> ok | {error, Reason}
```

Types:

Socket = socket()\
 Destination = \
\
     {inet:ip\_address(), inet:port\_number()} \|\
\
     inet:family\_address() \|\
\
     socket:sockaddr\_in() \|\
\
     socket:sockaddr\_in6()\
 AncData = inet:ancillary\_data()\
 Packet = iodata()\
 Reason = not\_owner \| inet:posix()\

Sends a packet to the specified *Destination* with ancillary data *AncData*.

**Note:**

The ancillary data *AncData* contains options that for this single message override the default options for the socket, an operation that may not be supported on all platforms, and if so return *{error, einval}*. Using more than one of an ancillary data item type may also not be supported. *AncData =:= \[\]* is always supported.

```
send(Socket, Destination, PortZero, Packet) ->
        ok | {error, Reason}
```

Types:

Socket = socket()\
 Destination = \
\
     {inet:ip\_address(), inet:port\_number()} \|\
\
     inet:family\_address()\
 PortZero = inet:port\_number()\
 Packet = iodata()\
 Reason = not\_owner \| inet:posix()\

Sends a packet to the specified *Destination*. Since *Destination* is complete, *PortZero* is redundant and has to be *0*.

This is a legacy clause mostly for *Destination = {local, Binary}* where *PortZero* is superfluous. It is equivalent to *send(Socket, Destination, \[\], Packet)*, the clause right above here.

```
send(Socket, Host, Port, AncData, Packet) -> ok | {error, Reason}
```

Types:

Socket = socket()\
 Host = \
\
     inet:hostname() \| inet:ip\_address() \| inet:local\_address()\
 Port = inet:port\_number() \| atom()\
 AncData = inet:ancillary\_data()\
 Packet = iodata()\
 Reason = not\_owner \| inet:posix()\

Sends a packet to the specified *Host* and *Port*, with ancillary data *AncData*.

Argument *Host* can be a hostname or a socket address, and *Port* can be a port number or a service name atom. These are resolved into a *Destination* and after that this function is equivalent to *send(Socket, Destination, AncData, Packet)*, read there about ancillary data.
