> ## 2. TCP/IP Engine

> This chapter describes the main library file, `DCRTCP.LIB`, which comprises the configuration macros, the data structures and the functions used to initialize and drive TCP/IP. IP version 4 is supported by `DCRTCP.LIB`.

> NOTE | Starting with Dynamic C version 7.05, `DCRTCP.LIB` is a light wrapper around `DNS.LIB`, `IP.LIB`, `NET.LIB`, `TCP.LIB` and `UDP.LIB`. No changes are required to existing code.

> ### 2.1 TCP/IP Configuration

> To run the TCP/IP engine, a host (i.e., the controller board) needs to know its IP address, netmask and default gateway. If DNS (Domain Name System) lookups are needed, a host will also need to know the IP address of the local DNS server.

> #### Media Access Control (MAC) address

> Some ISPs require that the user provide them with a MAC address for their device. Run the utility program, `/Samples/tcpip/display_mac.c`, to display the MAC address of your controller board.

> #### 2.1.1 IP Addresses Set Manually

> The necessary IP addresses can be set at compile time by defining the configuration macros: `MY_IP_ADDRESS`, `MY_NETMASK`,`MY_GATEWAY` and `MY_NAMESERVER`. At runtime, the configuration functions, `tcp_config``()`, `sethostid``()` and `sethostname``()` can override the configuration macros.

> #### 2.1.2 IP Addresses Set Dynamically

> The library `BOOTP.LIB` allows a target board to be a BOOTP or DHCP client. The protocol used depends on what type of server is installed on the local network. BOOTP and DHCP servers are usually centrally located on a local network and operated by the network administrator. Note that initialization may take longer when using DHCP as opposed to static configuration, but this depends on your server.

> Both protocols allow a number of configuration parameters to be sent to the client, including:

> - client's IP address.
> - net mask.
> - list of gateways.
> - host and default domain names.
> - list of name servers.

> To use these protocols, include:

>     #define USE_DHCP
>     #use DCRTCP.LIB

> in your program.

> BOOTP assigns permanent IP addresses. DHCP can "lease" an IP address to a host, i.e., assign the IP address for a limited amount of time.

> #### 2.1.2.1 BOOTP/DHCP Control Macros

> Various macros control the use of DHCP. Apart from setting these macros before '#use dcrtcp.lib', there is typically very little additional work that needs to be done to use DHCP/BOOTP services. Most of the work is done automatically when you call `sock_init()` to initialize TCP/IP. There are more control macros available than what are listed here. Please look at the beginning of the file`/lib/tcpip/bootp.lib` for more information.

> #### USE_DHCP

> If this macro is defined, the target uses BOOTP and/or DHCP to configure the required parameters. If `USE_DHCP` is not defined, then `MY_IP_ADDRESS`, `MY_NETMASK`,`MY_GATEWAY` and (possibly) `MY_NAMESERVER` must be defined in the application program.

> #### DHCP_USE_BOOTP

> If defined, the target uses the first BOOTP response it gets. If not defined, the target waits for the first DHCP offer and only if none comes in the time specified by `_bootptimeout` does it accept a BOOTP response (if any). Use of this macro speeds up the boot process, but at the expense of ignoring DHCP offers if there is an eager BOOTP server on the local subnet.

> #### DHCP_CLASS_ID "Rabbit2000-TCPIP:Z-World:Test:1.0.0"

> This macro defines a class identifier by which the OEM can identify the type of configuration parameters expected. DHCP servers can use this information to direct the target to the appropriate configuration file. Z-World recommends the standard format: "hardware:vendor:product code:firmware" version.

> #### DHCP_USE_TFTP

> If this and `USE_DHCP` are defined, the library will use the BOOTP filename and server to obtain an arbitrary configuration file that will be accessible in a buffer at physical address `_bootpdata`, with length, `_bootpsize`. The global variables, `_bootpdone` and `_bootperror` indicate the status of the boot file download. `DHCP_USE_TFTP` should be defined to the maximum file size that may be downloaded.

> #### DHCP_CLIENT_ID clientid_char_ptr
> DHCP_CLIENT_ID_LEN clientid_length

> Define a client identifier string. Since the client ID can contain binary data, the length of this string must be specified as well. This string MUST be unique amongst all clients in an administrative domain, thus in practice the client ID must be individually set for each client e.g. via front-panel configuration. It is NOT recommended to program a hard-coded string (as for class ID). Note that RFC2132 recommends that the first byte of the string should be zero if the client ID is not actually the hardware type and address of the client (see next).

> #### DHCP_CLIENT_ID_MAC

> If defined, this overrides `DHCP_CLIENT_ID`, and automatically sets the client ID string to be the hardware type (1 for ethernet) and MAC address, as suggested by RFC2132.

> #### 2.1.2.2 BOOTP/DHCP Global Variables

> The following list of global variables may be accessed by application code to obtain information about DHCP or BOOTP. These variable are only accessible if `USE_DHCP` is defined.

> #### _bootpon

> Runtime control of whether to perform DHCP/BOOTP. This is initially set to 'true'. It can be set to false before calling `sock_init` (the function that initializes the TCP/IP engine), causing static configuration to be used. Static configuration uses the values defined for the configuration macros, `MY_IP_ADDRESS` etc. If BOOTP fails during initialization, this will be reset to 0. If reset, then you can call `dhcp_acquire()` at some later time.

> #### _survivebootp

> Set to one of the following values:

> `0`: If BOOTP/DHCP fails, then a runtime error occurs. This is the default.
> `1`: If BOOTP fails, then use the values in `MY_IP_ADDRESS` etc. If those macros are not defined, a runtime error occurs.

> #### _dhcphost

> IP address of last-used DHCP server (~0UL if none). If `_survivebootp` is true, then this variable should be checked to see if DHCP/BOOTP was actually used to obtain the lease. If `_dhcphost` is ~0UL, then the fallback parameters (`MY_IP_ADDRESS` etc.) were used since no DHCP server responded.

> #### _bootphost

> IP address of the last-used BOOTP/TFTP server (~0UL if none). Usually obtained from the `siaddr` field of the DHCP OFFER/ACK message. This is the default host used if `NULL` is given for the hostname in the call to `tftp_exec()`. This is the host that provides the boot file.

> #### _dhcplife, _dhcpt1, _dhcpt2

> These variables contain various absolute time values (referenced against `SEC_TIMER` ) at which certain aspects of the DHCP protocol get activated. `_dhcplife` is when the current lease expires. If `_dhcplife` is ~0UL (i.e. 0xFFFFFFFF) then the lease is permanent and the other variables are not used. Otherwise, `_dhcpt1` is when the current lease must be renewed by the current DHCP server. `_dhcpt2` is when the lease must be re-bound to a possibly different server, if the current server does not respond. In general, `_dhcpt1` < `_dhcpt2` < `_dhcplife`. To work out the number of seconds remaining until the current lease expires, use code similar to:

>     if (_dhcplife == ~0UL)
>        printf("Lease is permanent\r\n");
>     else if (_dhcplife > SEC_TIMER)
>        printf("Remaining lease %lu seconds\r\n",
>         _dhcplife - SEC_TIMER);
>     else
>        printf("Lease is expired\r\n");

> #### _bootptimeout

> Number of seconds to wait for a BOOTP or DHCP offer. If there is no response within this time (default 30 sec), then BOOTP is assumed to have failed, and the action specified by `_survivebootp` will be taken. You can set this variable to a different value before calling `sock_init()`.

> #### _bootpdone

> Is set to a non-zero value when TFTP download of the boot file is complete. This variable only exists if `DHCP_USE_TFTP` is defined. It is set to one of the following values:

> `0`: Download not complete, or boot file not yet known.
> `1`: Boot file download completed (check `_bootperror` for status).
> `2`: No boot file was specified by the server.

> #### _bootpsize

> Indicates how many bytes of the boot file have been downloaded. Only exists if `DHCP_USE_TFTP` is defined.

> #### _bootpdata

> Physical starting address of boot data. The length of this area will be `DHCP_USE_TFTP` bytes, however, the actual amount of data in the buffer is given by `_bootpsize`. This variable only exists if `DHCP_USE_TFTP` is defined and is only valid if `_bootpdone` is 1. You can access the data using `xmem2root()` and related functions.

> #### _bootperror

> Indicates any error which occurred in a TFTP process. This variable only exists if `DHCP_USE_TFTP` is defined and is only valid when `_bootpdone` is 1, in which case `_bootperror` is set to one of the following values (which are also documented with the `tftp_tick()` function):

> | `0`: | No error.
> | `-1`: | Error from boot file server, transfer terminated. This usually occurs because the server is not configured properly, and has denied access to the nominated file.
> | `-2`: | Error, could not contact boot file server or lost contact.
> | `-3`: | Timed out, transfer terminated.
> | `-4`: | (not used)
> | `-5`: | Transfer complete, but truncated because buffer too small to receive the complete file.

> #### 2.1.2.3 DHCP Functions

> There are two user-callable functions regarding IP address leases. To obtain a lease, call `dhcp_acquire``()`. To relinquish it, call `dhcp_release``()`.

> #### 2.1.2.4 DHCP Sample Program

> The following sample code is a basic TCP/IP program that will initialize the TCP/IP interface, and allow the device to be 'pinged' from another computer on the network. DHCP or BOOTP will be used to obtain IP addresses and other network configuration items. A more extensive sample program is in `Samples\tcpip\dhcp.c`. It demonstrates other DHCP features, such as releasing and re-acquiring IP addresses and downloading a configuration file.

> #### Program Name: samples/tcpip/dhcp.c

>     // Main define to cause BOOTP or DHCP to be used.
>     #define USE_DHCP

>     /* These values may be used as a fallback if _survivebootp is set true. Otherwise, they will be ignored. Note that in a 'real' application, setting fallbacks as hard-coded addresses would be unwise.*/

>     #define MY_IP_ADDRESS "10.10.6.179"
>     #define MY_NETMASK "255.255.255.0"
>     #define MY_GATEWAY "10.10.6.1"

>     #memmap xmem
>     #use dcrtcp.lib

>     /* Print some of the DHCP or BOOTP parameters received. */

>     void print_results(void){
>        printf("Network Parameters:\r\n");
>        printf(" My IP Address = %08lX\r\n", my_ip_addr);
>        printf(" Netmask = %08lX\r\n", sin_mask);
>        if (_dhcphost != ~0UL) {
>           if (_dhcpstate == DHCP_ST_PERMANENT) {
>              printf(" Permanent lease\r\n");
>           } else {

>              printf("Remaining lease= %ld (sec)\r\n", _dhcplife -SEC_TIMER);

>              printf("Renew lease in %ld (sec)\r\n", _dhcpt1 - SEC_TIMER);
>           }
>           printf(" DHCP server = %08lX\r\n", _dhcphost);
>           printf(" Boot server = %08lX\r\n", _bootphost);
>        }
>        if (gethostname(NULL,0))
>           printf(" Host name = %s\r\n", gethostname(NULL,0));
>        if (getdomainname(NULL,0))
>           printf(" Domain name = %s\r\n", getdomainname(NULL,0));
>     }

>     main(){
>        _survivebootp = 1;  // So we can use fallback addresses
>        _bootptimeout = 6;  // Short timeout for testing
>        sock_init();
>        if (_dhcphost != ~0UL)
>           printf("Lease obtained\r\n");
>        else {
>           printf("Lease not obtained. DHCP server may be down.\r\n");
>           printf("Using fallback parameters...\r\n");
>        }
>        print_results();
>        for (;;)
>           tcp_tick(NULL);
>     }

> #### 2.1.3 Sizes for TCP/IP I/O Buffers

> Starting with Dynamic C version 7.05, TCP and UDP I/O buffers are sized separately using:

> - `TCP_BUF_SIZE` determines the TCP buffer size and defaults to 4096 bytes.
> - `UDP_BUF_SIZE` determines the UDP buffer size and defaults to 4096 bytes.

> Compatibility is maintained with earlier versions of Dynamic C. If `SOCK_BUF_SIZE` is defined, `TCP_BUF_SIZE` and `UDP_BUF_SIZE` will be assigned the value of `SOCK_BUF_SIZE`. If `SOCK_BUF_SIZE` is not defined, but `tcp_MaxBufSize` is, then `TCP_BUF_SIZE` and `UDP_BUF_SIZE` will be assigned the value of `tcp_MaxBufSize` * 2.

> #### 2.1.3.1 User-supplied Buffers

> Starting with Dynamic C version 7.05, a user can associate their own buffer with a TCP or UDP socket. The memory for the buffer must be allocated by the user. This can be done with `xalloc()`, which returns a pointer to the buffer. This buffer will be tied to a socket by a call to an extended open function: `tcp_extlisten``()`, `tcp_extopen``()` or `udp_extopen``()`. Each function requires a long pointer to the buffer and its length be passed as parameters.

> ### 2.2 TCP Socket Interface

> Throughout this manual, the term socket refers to four numbers: the IP addresses and port numbers for both sides of a connection.

> With Dynamic C version 6.57, each socket must have an associated `tcp_Socket` structure of 145 bytes or a `udp_Socket` structure of 62 bytes. The I/O buffers are in extended memory. For Dynamic C 7.05 these sizes are 132 bytes and 48 bytes, respectively.

> For earlier versions of Dynamic C, each socket must have a `tcp_Socket` data structure that holds the socket state and I/O buffers. These structures are, by default, around 4200 bytes each. The majority of this space is used by the input and output buffers.

> #### 2.2.1 Number of Sockets

> Starting with Dynamic C version 7.05, there are two macros that define the number of sockets available:

> - `MAX_TCP_SOCKET_BUFFERS` determines the maximum number of TCP sockets with preallocated buffers. The default is 4. A buffer is tied to a socket with the first call to `tcp_open()` or `tcp_listen()`.
> - `MAX_UDP_SOCKET_BUFFERS` determines the maximum number of UDP sockets with preallocated buffers. The default is 0. A buffer is tied to a socket with the first call to `udp_open()`.

> Note that DNS does not need a UDP socket buffer since it manages its own buffer. DHCP and `TFTP.LIB`, however, each need one UDP socket buffer.

> Prior to Dynamic C version 7.05, `MAX_SOCKETS` defined the number of sockets that could be allocated, not including the socket for DNS lookups. If you use libraries such as `HTTP.LIB` or `FTP_SERVER.LIB`, you must provide enough sockets in `MAX_SOCKETS` for them also.

> In Dynamic C 7.05 (and later), if `MAX_SOCKETS` is defined in an application program, `MAX_TCP_SOCKET_BUFFERS` will be assigned the value of `MAX_SOCKETS`.

> #### 2.2.2 Passive Open

> There are two ways to open a TCP socket, passive and active. To passively open a socket, call `tcp_listen()`; then wait for someone to contact your device. This type of open is commonly used for Internet servers that listen on a well-known port, like 80 for HTTP (Hypertext Transfer Protocol) servers. You supply `tcp_listen()` with a pointer to a `tcp_Socket` data structure, the local port number others will be contacting on your device, and the IP address and port number that are valid for the device. If you want to be able to accept connections from any IP address or any port number, set one or both to zero.

> To handle multiple simultaneous connections, each new connection will require its own `tcp_Socket` and a separate call to `tcp_listen()`, but using the same local port number (`lport` value). `tcp_listen()` will immediately return, and you must poll for the incoming connection. You can manually poll the socket using `sock_established()`.

> #### 2.2.3 Active Open

> When your Web browser retrieves a page, it actively opens one or more connections to the server's passively opened sockets. To actively open a connection, you call `tcp_open()`, which uses parameters that are similar to the ones used in `tcp_listen()`. Supply exact parameters for `ina` and `port`, which are the IP address and port number you want to connect to; the `lport` parameter can be zero, causing an unused local port between 1024 and 65535 to be selected.

> If `tcp_open()` returns zero, no connection was made. This could be due to routing difficulties, such as an inability to resolve the remote computer's hardware address with ARP.

> #### 2.2.4 Delay a Connection

> To accept a connection request when the resources to actually process the request are not available, use the function `tcp_reserveport()`. It takes one parameter, the port number where you want to accept connections. When a connection to that port number is requested, the 3-way handshaking is done even if there is not yet a socket available. When replying to the connection request, the window parameter in the TCP header is set to zero, meaning, "I can take no bytes of data at this time." The other side of the connection will wait until the value in the window parameter indicates that data can be sent. Using the companion function, `tcp_clearreserve(port number)`, causes TCP/IP to treat a connection request to the port in the conventional way. The macro `USE_RESERVEDPORTS` is defined by default. It allows the use of these two functions.

> When using `tcp_reserveport`, the 2MSL (Maximum Segment Lifetime) waiting period for closing a socket is avoided.

> #### 2.2.5 TCP Socket Functions

> There are many functions that can be applied to an open TCP socket. They fall into three main categories: Control, Status, and I/O.

> #### 2.2.5.1 Control Functions for TCP Sockets

> These functions change the status of the socket or its I/O buffer.

> · sock_abort | · sock_flushnext
> · sock_close | · tcp_listen
> · sock_flush | · tcp_open

> `tcp_open()` and `tcp_listen()` have been explained in previous sections.

> Call `sock_close()` to end a connection. This call may not immediately close the connection because it may take some time to send the request to end the connection and receive the acknowledgements. If you want to be sure that the connection is completely closed before continuing, call `tcp_tick()` with the socket structure's address. When `tcp_tick()` returns zero, then the socket is completely closed. Please note that if there is data left to be read on the socket, the socket will not completely close.

> Call `sock_abort()` to cancel an open connection. This function will cause a TCP reset to be sent to the other end, and all future packets received on this connection will be ignored.

> For performance reasons, data may not be immediately sent from a socket to its destination. If your application requires the data to be sent immediately, you can call `sock_flush()`. This function will try sending any pending data immediately. If you know ahead of time that data needs to be sent immediately, call `sock_flushnext``()` on the socket. This function will cause the next set of data written to the socket to be sent immediately, and is more efficient than `sock_flush()`.

> #### 2.2.5.2 Status Functions for TCP Sockets

> These functions return useful information about the status of either a socket or its I/O buffers.

> · sock_bytesready | · sock_rbused
> · sock_dataready | · sock_tbleft
> · sock_established | · sock_tbsize
> · sock_rbleft | · sock_tbused
> · sock_rbsize | · tcp_tick

> `tcp_tick()` is the daemon that drives the TCP/IP engine, but it also returns status information. When you supply `tcp_tick()` with a pointer to a `tcp_Socket` (a structure that identifies a particular socket), it will first process packets and then check the indicated socket for an established connection. `tcp_tick()` returns zero when the socket is completely closed. You can use this return value after calling `sock_close()` to determine if the socket is completely closed.

>     sock_close(&my_socket);
>     while(tcp_tick(&my_socket)) {
>      // you can do other things here while waiting for the socket
>      // to be completely closed.
>     }

> These status functions can be used to avoid blocking when using `sock_write()` and some of the other I/O functions, as illustrated in the following code.

> This block of code checks to make sure that there is enough room in the buffer before adding data with a blocking function. .

>     if(sock_tbleft(&my_socket,size)) {
>         sock_write(&my_socket,buffer,size);
>     }

> This block of code ensures that there is a string terminated with a new line in the buffer, or that the buffer is full before calling `sock_gets()`:

>     sock_mode(&my_socket,TCP_MODE_ASCII);
>     if(sock_bytesready(&my_socket) != -1) {
>         sock_gets(buffer,MAX_BUFFER);
>     }

> #### 2.2.5.3 I/O Functions for TCP Sockets

> · sock_fastread | · sock_putc
> · sock_fastwrite | · sock_puts
> · sock_getc | · sock_read
> · sock_gets | · sock_write
> · sock_preread |

> There are two modes of reading and writing to TCP sockets: ASCII and binary. By default, a socket is opened in binary mode, but you can change the mode with a call to `sock_mode()`.

> When a socket is in ASCII mode, it is assumed that the data is an ASCII stream with record boundaries on the newline characters for some of the functions. This behavior means `sock_bytesready()` will return ≥0 only when a complete newline-terminated string is in the buffer or the buffer is full. The `sock_puts()` function will automatically place a newline character at the end of a string, and the `sock_gets()` function will strip the newline character.

> Do not use `sock_gets()`in binary mode.

> ### 2.3 UDP Socket Interface

> The UDP protocol is useful when sending messages where either a lost message does not cause a system failure or is handled by the application. Since UDP is a simple protocol and you have control over the retransmissions, you can decide if you can trade low latency for high reliability.

> #### Broadcast Packets

> UDP can send broadcast packets (i.e., to send a packet to a number of computers on the same network). This is accomplished by setting the remote IP address to -1, in either a call to `udp_open()` or a call to `udp_sendto()`. When used properly, broadcasts can reduce overall network traffic because information does not have to be duplicated when there are multiple destinations.

> #### Checksums

> There is an optional checksum field inside the UDP header. This field verifies the header and the data. This feature can be disabled on a reliable network where the application has the ability to detect transmission errors. Disabling the UDP checksum can increase the performance of UDP packets moving through TCP/IP engine. This feature can be modified by:

>     sock_mode(s, UDP_MODE_CHK);    // enable checksums
>     sock_mode(s, UDP_MODE_NOCHK);  // disable checksums

> The first parameter is a pointer to the socket's data structure, either `tcp_Socket` or `udp_Socket`.

> In Dynamic C version 7.20, some convenient macros offer a safer, faster alternative to using `sock_mode()`. They are `udp_set_chk(s)` and `udp_set_nochk(s)`.

> #### Improved Interface

> With Dynamic C version 7.05 there is a redesigned UDP API. The new interface is incompatible with the previous one. Section 2.3.1 covers the new interface and Section 2.3.2 covers the previous one.

> #### 2.3.1 Dynamic C 7.05 (and later)

> This UDP interface is a record service. It receives distinct datagrams and passes them as such to the user program. The socket I/O functions available for TCP sockets will not work for UDP sockets.

> See Section 2.3.3 for information on porting a program to the new UDP interface.

> #### 2.3.1.1 Control Functions for UDP Sockets

> These functions change the status of the socket or its I/O buffer.

> · sock_flush | · udp_close
> · sock_flushnext | · udp_open

> #### 2.3.1.2 I/O Functions for UDP Sockets

> These functions handle datagram-at-a-time I/O:

> · udp_recv | · udp_send
> · udp_recvfrom | · udp_sendto

> The write function, `udp_sendto()`, allows the remote IP address and port number to be specified. The read function, `udp_recvfrom()`, identifies the IP address and port number of the host that sent the datagram. There is no longer a UDP read function that blocks until data is ready.

> #### 2.3.1.3 Status Function for UDP Sockets

> These functions return useful information about the status of either a socket or its I/O buffers.

> · sock_bytesready | · sock_rbused
> · sock_dataready | · sock_tbleft
> · sock_established | · sock_tbsize
> · sock_rbleft | · sock_tbused
> · sock_rbsize | · tcp_tick

> For a udp socket, `sock_bytesready()` returns the number of bytes in the next datagram in the socket buffer, or -1 if no datagrams are waiting. Note that a return of 0 is valid, since a datagram can have 0 bytes of data.

> #### 2.3.2 UDP Interface Prior to Dynamic C 7.05

> This interface is basically the TCP socket interface with some additional functions for simulating a record service. Some of the TCP socket functions work differently for UDP because of its connectionless state. The descriptions for the applicable functions details these differences.

> #### 2.3.2.1 I/O Functions for UDP Sockets

> Prior to Dynamic C 7.05, the functions that handle UDP socket I/O are mostly the same functions that handle TCP socket I/O.

> · sock_fastread | · sock_read
> · sock_fastwrite | · sock_recv
> · sock_getc | · sock_recv_from
> · sock_gets | · sock_recv_init
> · sock_preread | · sock_write
> · sock_putc | · udp_close
> · sock_puts | · udp_open

> Notice that there are three additional I/O functions that are only available for use with UDP sockets: `sock_recv()`, `sock_recv_from()` and `sock_recv_init()`. The status and control functions that are available for TCP sockets also work for UDP sockets, with the exception of the open functions, `tcp_listen()` and `tcp_open()`.

> #### 2.3.2.2 Opening and Closing a UDP Socket

> `udp_open``()` takes a remote IP address and a remote port number. If they are set to a specific value, all incoming and outgoing packets are filtered on that value (i.e., you talk only to the one remote address).

> If the remote IP address is set to -1, the UDP socket receives packets from any valid remote address, and outgoing packets are broadcast. If the remote IP address is set to 0, no outgoing packets may be sent until a packet has been received. This first packet completes the socket, filling in the remote IP address and port number with the return address of the incoming packet. Multiple sockets can be opened on the same local port, with the remote address set to 0, to accept multiple incoming connections from separate remote hosts. When you are done communicating on a socket that was started with a 0 IP address, you can close it with `sock_close()` and reopen to make it ready for another source.

> #### 2.3.2.3 Writing to a UDP Socket

> Prior to Dynamic C 7.05, the normal socket functions used for writing to a TCP socket will work for a UDP socket, but since UDP is a significantly different service, the result could be different. Each atomic write--`sock_putc()`, `sock_puts()`, `sock_write()`, or `sock_fastwrite()``--`places its data into a single UDP packet. Since UDP does not guarantee delivery or ordering of packets, the data received may be different either in order or content than the data sent. Packets may also be duplicated if they cross any gateways. A duplicate packet may be received well after the original.

> #### 2.3.2.4 Reading From a UDP Socket

> There are two ways to read UDP packets prior to Dynamic C 7.05. The first method uses the same read functions that are used for TCP: `sock_getc()`, `sock_gets()`, `sock_read()`, and `sock_fastread``()`. These functions will read the data as it came into the socket, which is not necessarily the data that was written to the socket.

> The second mode of operation for reading uses the `sock_recv_init()`, `sock_recv()`, and `sock_recv_from()` functions. The `sock_recv_init()` function installs a large buffer area that gets divided into smaller buffers. Whenever a datagram arrives, it is stuffed into one of these new buffers. The `sock_recv()` and `sock_recv_from()` functions scan these buffers. After calling `sock_recv_init` on the socket, you should not use `sock_getc()`, `sock_read()`, or `sock_fastread()`.

> The `sock_recv()` function scans the buffers for any datagrams received by that socket. If there is a datagram, the length is returned and the user buffer is filled, otherwise `sock_recv()` returns zero.

> The `sock_recv_from()` function works like `sock_recv()`, but it allows you to record the IP address where the datagram originated. If you want to reply, you can open a new UDP socket with the IP address modified by `sock_recv_from()`.

> #### 2.3.3 Porting Programs from the older UDP API to the new UDP API

> To update applications written with the older-style UDP API, use the mapping information in the following table.

> UDP API prior to Dynamic C 7.05 | UDP API starting with Dynamic C 7.05
> `MAX_SOCKETS` | `MAX_UDP_SOCKET_BUFFERS``` and`` `MAX_TCP_SOCKET_BUFFERS```
> `SOCK_BUF_SIZE` | `UDP_BUF_SIZE` and `TCP_BUF_SIZE`
> `udp_open()` | `udp_open()`
> `sock_write()`, `sock_fastwrite()` | `udp_send()` or `udp_sendto()`
> `sock_read()`(blocking function) | `udp_recv()` or `udp_recvfrom()` (nonblocking functions)
> `sock_fastread()` | `udp_recv()` or `udp_recvfrom()`
> `sock_recv_init()` | `udp_extopen()` (to specify your own buffer)
> `sock_recv()` | `udp_recv()`
> `sock_recv_from()` | `udp_recvfrom()`
> `sock_close()` | `sock_close()` or `udp_close()`
> `sock_bytesready()` | `sock_bytesready()`
> `sock_dataready()` | `sock_dataready()`

> ### 2.4 DNS Lookups

> Starting with Dynamic C 7.05, non-blocking DNS lookups are supported. Prior to DC 7.05, there was only the blocking function, `resolve()`. Compatibility has been preserved for `resolve()`, `MAX_DOMAIN_LENGTH` , and `DISABLE_DNS`.

> The application program has to do two things to resolve a host name:

> 1. Call `resolve_name_start()` to start the process.
> 2. Call `resolve_name_check()` to check for a response.

> Call `resolve_cancel()`to cancel a pending lookup.

> #### 2.4.1 Configuration Macros for DNS Lookups

> #### DISABLE_DNS

> If this macro is defined, DNS lookups will not be done. The DNS subsystem will not be compiled in, saving some code space and memory.

> #### DNS_MAX_RESOLVES

> 4 by default. This is the maximum number of concurrent DNS queries. It specifies the size of an internal table that is allocated in xmem.

> #### DNS_MAX_NAME

> 64 by default. Specifies the maximum size in bytes of a host name that can be resolved. This number includes any appended default domain and the `NULL`-terminator. Backwards compatibility exists for the `MAX_DOMAIN_LENGTH` macro. Its value will be overridden with the value `DNS_MAX_NAME` if it is defined.

> For temporary storage, a variable of this size must be placed on the stack in DNS processing. Normally, this is not a problem. However, for µC/OS-II with a small stack and a large value for `DNS_MAX_NAME`, this could be an issue.

> #### DNS_MAX_DATAGRAM_SIZE

> 512 by default. Specifies the maximum length in bytes of a DNS datagram that can be sent or received. A root data buffer of this size is allocated for DNS support.

> #### DNS_RETRY_TIMEOUT

> 2000 by default. Specifies the number of milliseconds to wait before retrying a DNS request. If a request to a nameserver times out, then the next nameserver is tried. If that times out, then the next one is tried, in order, until it wraps around to the first nameserver again (or runs out of retries).

> #### DNS_NUMBER_RETRIES

> 2 by default. Specifies the number of times a request will be retried after an error or a timeout. The first attempt does not constitute a retry. A retry only occurs when a request has timed out, or when a nameserver returns an unintelligible response. That is, if a host name is looked up and the nameserver reports that it does not exist and then the DNS resolver tries the same host name with or without the default domain, that does not constitute a retry.

> #### DNS_MIN_KEEP_COMPLETED

> 10000 by default. Specifies the number of milliseconds a completed request is guaranteed to be valid for `resolve_name_check()`. After this time, the entry in the internal table corresponding to this request can be reused for a subsequent request.

> #### DNS_SOCK_BUF_SIZE

> 1024 by default. Specifies the size in bytes of an xmem buffer for the DNS socket. Note that this means that the DNS socket does not use a buffer from the socket buffer pool.

> ### 2.5 Skeleton Program

> The following program is a general outline for a Dynamic C TCP/IP program. The first couple of defines set up the default IP configuration information. The "memmap" line causes the program to compile as much code as it can in the extended code window. The "use" line causes the compiler to compile in the Dynamic C TCP/IP code using the configuration data provided above it.

> #### Program Name: /samples/tcpip/icmp/pingme.c

>     /*
>      * You must change the following values to whatever
>      * your local IP address, netmask, and gateway are.
>      * Contact your network administrator for these numbers.
>      */

>     #define MY_IP_ADDRESS "10.10.6.101"
>     #define MY_NETMASK "255.255.255.0"
>     #define MY_GATEWAY "10.10.6.19"

>     #memmap xmem
>     #use dcrtcp.lib

>     main() {
>         sock_init();
>         for (;;) {
>             tcp_tick(NULL);
>         }
>     }

> To run this program, start Dynamic C and open the `SAMPLES\TCPIP\ICMP\PINGME.C` file. Edit the `MY_IP_ADDRESS`, `MY_NETMASK`, and `MY_GATEWAY` macros to reflect the appropriate values for your device. Run the program and try to run `ping 10.10.6.101` from a command line on a computer on the same physical network, replacing `10.10.6.101` with your value for `MY_IP_ADDRESS`.

> #### 2.5.1 TCP/IP Stack Initialization

> The `main()` function first initializes the TCP/IP stack with a call to `sock_init()`. This call initializes internal data structures and enables the Ethernet chip, which will take a couple of seconds with the RealTek chip. At this point, the TCP/IP engine is ready to handle incoming packets.

> #### 2.5.2 Packet Processing

> Incoming packets are processed whenever `tcp_tick()` is called. The user-callable functions that call `tcp_tick()` are: `tcp_open`, `udp_open`, `sock_read`, `sock_write`, `sock_close`, and `sock_abort`. Some of the higher-level protocols, e.g. `HTTP.LIB`, will call `tcp_tick()` automatically.

> It is a good practice to make sure that `tcp_tick()` is called periodically in your program to insure that the TCP/IP engine has had a chance to process packets. A rule of thumb is to call `tcp_tick``()` around 10 times per second, although slower or faster call rates should also work. The Ethernet interface chip has a large buffer memory, and TCP/IP is adaptive to the data rates that both end of the connection can handle; thus the system will generally keep working over a wide variety of tick rates.

> #### 2.5.3 TCP/IP Daemon Computing Time

> The computing time consumed by each call to `tcp_tick()` varies. Rough numbers are less than a millisecond if there is nothing to do, tens of milliseconds for typical packet processing, and hundreds of milliseconds under exceptional circumstances.

> ### 2.6 State-Based Program Design

> An efficient design strategy is to create a state machine within a function and pass the socket's data structure as a function parameter. This method allows you to handle multiple sockets without the services of a multitasking kernel. This is the way the `HTTP.LIB` functions are organized. Many of the common Internet protocols fit well into this state machine model.

> The general states are:

> - Waiting to be initialized
> - Waiting for a connection
> - Connected states that perform the real work
> - Waiting for the socket to be closed

> An example of state-based programming is `SAMPLES\TCPIP\STATE.C`. This program is a basic Web server that should work with most browsers. It allows a single connection at a time, but can be extended to allow multiple connections.

> #### 2.6.1 Blocking vs. Non-Blocking

> There is a choice between blocking and non-blocking functions when doing socket I/O.

> #### 2.6.1.1 Non-Blocking Functions

> The `sock_fastread()` and `sock_preread()` functions read all available data in the buffers, and return immediately. Similarly, the `sock_fastwrite()` function fills the buffers and returns the number of characters that were written. When using these functions, you must ensure that all of the data were written completely.

>     offset=0;
>     while(offset<length) {
>       bytes_written=sock_fastwrite(&socket,buffer+offset,length-offset);
>       if(bytes_written<0) {
>             // error handling
>       }
>       offset+=bytes_written;
>     }

> #### 2.6.1.2 Blocking Functions

> The other functions (`sock_getc()`, `sock_gets()`, `sock_putc()`, `sock_puts()`, `sock_read()` and `sock_write()`) do not return until they have completed or there is an error. If it is important to avoid blocking, you can check the conditions of an operation to insure that it will not block.

>     sock_mode(socket,TCP_MODE_ASCII);
>     // ...
>     if (sock_bytesready(&my_socket) != -1){
>         sock_gets(buffer,MAX_BUFFER);
>     }

> In this case `sock_gets()` will not block because it will be called only when there is a complete new line terminated record to read.

> ### 2.7 Multitasking and TCP/IP

> Dynamic C's TCP/IP implementation is compatible with both µC/OS-II and with the language constructs that implement cooperative multitasking: costatements and cofunctions. Note that TCP/IP is not compatible with the slice statement.

> #### 2.7.1 µC/OS-II

> The TCP/IP engine may be used with the µC/OS-II real-time kernel. The line

>     #use ucos2.lib

> must appear before the line

>     #use dcrtcp.lib

> in the application program. Also be sure to call `OSInit()` before calling `sock_init()`.

> Dynamic C version 7.05 and later requires the macro `MAX_SOCKET_LOCKS` for µC/OS-II support. If it is not defined, it will default to `MAX_TCP_SOCKET_BUFFERS` + `TOTAL_UDP_SOCKET_BUFFERS` (which is `MAX_UDP_SOCKET_BUFFERS` + 1 if there are DNS lookups).

> If buffers have been `xalloc`'d for socket I/O, they should be accounted for in `MAX_SOCKET_LOCKS`.

> #### 2.7.2 Cooperative Multitasking

> The following program demonstrates the use of multiple TCP sockets with costatements.

> #### Program Name: costate_tcp.c

>     #define MY_IP_ADDRESS "10.10.6.11"
>     #define MY_NETMASK "255.255.255.0"
>     #define MY_GATEWAY "10.10.6.1"

>     #define PORT1 8888
>     #define PORT2 8889

>     #define SOCK_BUF_SIZE 2048
>     #define MAX_SOCKETS 2

>     #memmap xmem
>     #use "dcrtcp.lib"

>     tcp_Socket Socket_1;
>     tcp_Socket Socket_2;

>     #define MAX_BUFSIZE 512
>     char buf1[MAX_BUFSIZE], buf2[MAX_BUFSIZE];

>     // The function that actually does the TCP work
>     cofunc int basic_tcp[2](tcp_Socket *s, int port, char *buf){
>        auto int length, space_avaliable;

>        tcp_listen(s, port, 0, 0, NULL, 0);

>        // wait for a connection
>        while((-1 == sock_bytesready(s)) && (0 == sock_established(s)))
>           // give other tasks time to do things while we are waiting
>           yield;
>        while(sock_established(s)) {
>           space_avaliable = sock_tbleft(s);
>           // limit transfer size to MAX_BUFSIZE, leave room for '\0'
>           if(space_avaliable > (MAX_BUFSIZE-1))
>              space_avaliable = (MAX_BUFSIZE-1);
>           // get some data
>           length = sock_fastread(s, buf, space_avaliable);

>           if(length > 0) {         // did we receive any data?
>              buf[length] = '\0';   // print it to the stdio window
>              printf("%s",buf);
>              // send it back out to the user's telnet session
>              // sock_fastwrite will work-we verified the space beforehand
>              sock_fastwrite(s, buf, length);
>           }
>           yield;                  // give other tasks time to run
>        }
>        sock_close(s);
>        return 1;
>     }

> #### Program Name: costate_tcp.c (continued)

>     main() {
>        sock_init();
>        while (1) {
>           costate {
>              // Go do the TCP/IP part, on the first socket
>              wfd basic_tcp[0](&Socket_1, PORT1, buf1);
>           }
>           costate {
>              // Go do the TCP/IP part, on the second socet
>              wfd basic_tcp[1](&Socket_2, PORT2, buf2);
>           }
>           costate {
>              // drive the tcp stack
>              tcp_tick(NULL);
>           }
>           costate {
>              // Can insert application code here!
>              waitfor(DelayMs(100));
>           }
>        }
>     }

> ### 2.8 Function Reference

> This section contains descriptions for all user-callable functions in `DCRTCP.LIB`. Starting with Dynamic C 7.05, `DCRTCP.LIB` is a light wrapper around `DNS.LIB`, `IP.LIB`, `NET.LIB`, `TCP.LIB` and `UDP.LIB`. This update requires no changes to existing code.

> Descriptions for select user-callable functions in `ARP.LIB`, `ICMP.LIB`, `BSDNAME.LIB` and `XMEM.LIB` are also included here. Note that `ARP.LIB`, `ICMP.LIB` and `BSDNAME.LIB` are automatically `#use`'d from `DCRTCP.LIB`.

> ## arpcache_create

>     ATHandle arpcache_create(longword ipaddr)

> ### Description

> Create a new entry in the ARP cache table for the specified IP address. If a matching entry for that address already exists, then that entry is returned. Otherwise, a new entry is initialized and returned. If a new entry is created, then an old entry may need to be purged. If this is not possible, then `ATH_NOENTRIES` is returned.

> ### Parameter

> #### ipaddr

> IP address of entry.

> ### Return Value

> Positive value: success.
> `ATH_NOENTRIES`: no space is available in the table, and none of the entries could be purged because they were all marked as permanent or router entries.

> ### Library

> ARP.LIB

> ## arpcache_flush

>     ATHandle arpcache_flush(ATHandle ath);

> ### Description

> Mark an ARP cache table entry for flushing. This means that the given table entry will be the first entry to be re-used for a different IP address, if necessary. Any entry (including permanent and router entries) may be flushed except for the broadcast entry.

> ### Parameter

> #### ath

> ARP table handle obtained from e.g. `arpcache_search()`.

> ### Return Value

> Positive value: success.
> `ATH_UNUSED`: the table entry was unused.
> `ATH_INVALID`: the `ath` parameter was not a valid handle.
> `ATH_OBSOLETE`: the given handle was valid, but obsoleted by a more recent entry. No change made.

> ### Library

> ARP.LIB

> ## arpcache_hwa

>     ATHandle arpcache_hwa(ATHandle ath, byte * hwa);

> ### Description

> Copy the ethernet (hardware) address from the given ARP cache table entry into the specified area.

> ### Parameters

> #### ath

> ARP cache table entry.

> #### hwa

> Address of where to store the hardware address (6 bytes).

> ### Return Value

> Positive value: handle to the entry.
> `ATH_UNUSED`: the table entry was unused.
> `ATH_INVALID`: the ath parameter was not a valid handle.
> `ATH_OBSOLETE`: the given handle was valid, but obsoleted by a more recent entry. No change made.

> ### Library

> ARP.LIB

> ## arpcache_load

>     ATHandle arpcache_load(ATHandle ath, byte * hwa, byte iface, word flags, byte router_used);

> ### Description

> Load an entry in the ARP cache table. The entry must have been created using `arpcache_create()`, or be an existing valid entry located via `arpcache_search()`.

> This function is primarily intended for internal use by the ARP library, although advanced applications could also use it. Most applications should not need to call this function directly.

> ### Parameters

> #### ath

> Handle for the entry.

> #### hwa

> Hardware (ethernet) address, or `NULL`. Pass `NULL` if the current hardware address is not to be changed.

> #### iface

> Interface to use (`IF_DEFAULT` to use default, or not change current setting).

> #### flags

> Flags for entry: one or more of the following values, OR'd together:

> · `ATE_PERMANENT`: permanent entry
> · `ATE_RESOLVING`: initiate network resolve for this entry (`hwa` is ignored if this flag is set)
> · `ATE_RESOLVED`: this entry now resolved
> · `ATE_ROUTER_ENT`: this is a router entry
> · `ATE_FLUSH`: mark this entry for flush
> · `ATE_VOLATILE`: set short timeout for this entry
> · `ATE_ROUTER_HOP`: this entry uses the specified router as the first hop. `hwa` ignored.
> · `ATE_REDIRECTED`: this entry redirected by ICMP.

> Only one of `ATE_ROUTER_ENT` or `ATE_ROUTER_HOP` should be set. For either of these, the next parameter indicates the router table entry to use.

> Only one of `ATE_RESOLVING` or `ATE_RESOLVED` should be set.

> #### router_used

> Router table entry. Only used if one of `ATE_ROUTER_ENT` or `ATE_ROUTER_HOP` is set in the flags parameter.

> ### Return Value

> Positive value: success.

> `ATH_NOROUTER`: the specified router entry number is invalid. This can be because the router_used parameter is bad, or because the router entry has a mismatching ATH.

> `ATH_INVALID`: invalid table handle passed (or unused entry).

> `ATH_OBSOLETE`: the given handle was valid, but obsoleted by a more recent entry. No change made.

> ### Library

> ARP.LIB

> ## arpcache_search

>     ATHandle arpcache_search(longword ipaddr, int virt);

> ### Description

> Return handle which refers to the ARP cache table entry for the given IP address. This does not do any resolving. It only consults the existing cache entries. The returned handle is guaranteed to be valid at least until the next call to `tcp_tick()`. Usually the handle will be valid for considerably longer, however it is possible for the handle to become obsolete if the cache entry is re-used for a different address. The caller should be able to deal with this possibility. The entry returned for the broadcast address is guaranteed to be permanent.

> ### Parameters

> #### ipaddr

> IP address to locate in the cache. This may be -1L to locate the broadcast entry or our own IP address to return the "loopback" entry.

> #### virt

> 0: do not return the broadcast or loopback entries.

> 1: allow the broadcast or loopback entries.

> Return Value

> Positive value: handle to the entry.
> `ATH_NOTFOUND`: no entry exists for the given IP address.

> ### Library

> ARP.LIB

> ## _arp_resolve

>     int _arp_resolve(longword ina, eth_address *ethap, int nowait);

> ### Description

> Gets the Ethernet address for the given IP address. This function is deprecated starting in Dynamic C 7.20.

> ### Parameters

> #### ina

> The IP address to resolve to an Ethernet address.

> #### ethap

> The buffer to hold the Ethernet address.

> #### nowait

> If 0, return within 750 ms; else if !0 wait up to 5 seconds trying to resolve the address.

> ### Return value

> `1`: Success.
> `0`: Failure.

> ### Library

> ARP.LIB

> ## arpresolve_check

>     ATHandle arpresolve_check(ATHandle ath, longword ipaddr)

> ### Description

> Check up on status of resolve process initiated by `arpresolve_start()`. This function should be called regularly to ensure that an ARP table handle is pointing to the correct entry, and that the entry is still current.

> This caller must call `tcp_tick()` if spinning on this function.

> ### Parameters

> #### ath

> ARP Table Handle obtained from `arpresolve_start()`.

> #### ipaddr

> IP address specified to `arpresolve_start()`. If this is zero, no check is performed. Otherwise, the ARP table entry is checked to see that it is the correct entry for the specified IP address.

> ### Return Value

> Positive value: completed successfully. The return value will be the same as the ath parameter.
> `ATH_AGAIN`: not yet completed, try again later.
> `ATH_FAILED`: completed in error. Address cannot be resolved because of a network configuration problem.
> `ATH_TIMEDOUT`: resolve timed out. No response from addressee within the configured time limit.
> `ATH_INVALID`: the `ath` parameter was not a valid handle|.
> `ATH_OBSOLETE`: the given handle was valid, but obsoleted by a more recent entry. Restart using `arpresolve_start()`.
> `ATH_MISMATCH`: the `ipaddr` parameter was not zero, and the IP address does not match the table entry.

> ### Library

> ARP.LIB

> ## arpresolve_ipaddr

>     longword arpresolve_ipaddr(ATHandle ath)

> ### Description

> Given an ARP table handle, return the IP address of the corresponding table entry.

> ### Parameter

> #### ath

> ARP Table Handle obtained from e.g. `router_for()`.

> ### Return Value

> `0`: An error occurred, such as an invalid or obsolete handle.
> `0xFFFFFFFF`: The handle refers to either the broadcast address, or to a point-to-point entry whose IP address is not defined.
> Else: An IP address. This may be 127.0.0.1 for the loopback entry.

> ### Library

> ARP.LIB

> ## arpresolve_start

>     ATHandle arpresolve_start(longword ipaddr);

> ### Description

> Start resolve process for the given IP address. This may return immediately if the IP address is in the ARP cache table and still valid. Otherwise, if the IP address is on the local subnet then an ARP resolve request is issued through the appropriate interface. If the address is not on the local subnet, then a router table entry is used and no network activity is necessary (unless the router itself is not resolved, in which case its resolution commences).

> ### Parameter

> #### ipaddr

> IP address of host whose hardware address is to be resolved.

> ### Return Value

> Positive value: success. The value is actually the ATH of the ARP cache table entry which is (or will be) used. This value should be passed to subsequent calls to `arpresolve_check()`.

> `ATH_NOENTRIES`: no space is available in the table, and none of the entries could be purged, because they were all marked as permanent or router entries.

> `ATH_NOROUTER`: no router ("gateway") is configured for the specified address, which is not on the local subnet.

> ### Library

> ARP.LIB

> ## _chk_ping

>     longword _chk_ping( longword host_ip, longword *sequence_number);

> ### Description

> Checks for any outstanding ping replies from host. `_chk_ping` should be called frequently with a host IP address. If an appropriate packet is found from that host IP address, the sequence number is returned through `*sequence_number``.` The time difference between our request and their response is returned in milliseconds.

> ### Parameters

> #### host_ip

> IP address to receive ping reply from.

> #### sequence_number

> Sequence number of reply.

> ### Return value

> Time in milliseconds from the ping request to the host's ping reply.
> If `_chk_ping` returns `0xffffffffL`, there were no ping receipts on this current call.

> ### Library

> ICMP.LIB

> ### See Also

> _ping, _send_ping

> ## dhcp_acquire

>     int dhcp_acquire( void );

> ### Description

> This function acquires a DHCP lease that has not yet been obtained, or has expired, or was relinquished using `dhcp_release()`. Normally, DHCP leases are renewed automatically, however if the DHCP server is down for an extended period then it might not be possible to renew the lease in time, in which case the lease expires and TCP/IP should not be used. When the lease expires, `tcp_tick()` will return 0, and the global variable for the IP address will be reset to 0. At some later time, this function can be called to try to obtain an IP address.

> This function blocks until the lease is renewed, or the process times out.

> ### Return value

> `0`: OK, lease was not expired, or an IP address lease was acquired with the same
> IP address as previously obtained.

> `-1`: An error occurred, no IP address is available. TCP/IP functionality is thus not
> available. Usual causes of an error are timeouts because a DHCP or BOOTP server
> is not available within the timeout specified by the global variable
> `_bootptimeout` (default 30 seconds).

> `1`: Lease was re-acquired, however the IP address differs from the one previously
> obtained. All existing sockets must be re-opened. Normally, DHCP servers are
> careful to reassign the same IP address previously used by the client, however this
> is sometimes not possible.

> ### Library

> BOOTP.LIB

> ## dhcp_get_timezone

>      int dhcp_get_timezone( long * seconds );

> ### Description

> This function returns the time zone offset provided by the DHCP server, if any, or uses the fallback time zone defined by the `TIMEZONE` macro. Note that `TIMEZONE` is expressed in hours, whereas the return result is in seconds.

> ### Parameters

> #### seconds

> Pointer to result longword. If the return value is 0 (OK), then this will be set to the number of seconds offset from Coordinated Universal Time (UTC). The value will be negative for west; positive for east of Greenwich. If the return value is -1, then the result will be set using the hard-coded value from the macro `TIMEZONE` (converted to seconds by multiplying by 3600), or zero if this macro is not defined.

> Return Value

> `0`: Time zone obtained from DHCP.
> `-1`: Time zone not valid, or not yet obtained, or not using DHCP.

> ### Library

> BOOTP.LIB

> ## dhcp_release

>     int dhcp_release( void );

> ### Description

> This function relinquishes a lease obtained from a DHCP server. This allows the server to re-use the IP address that was allocated to this target. After calling this function, the global variable for the IP address is set to 0, and it is not possible to call any other TCP/IP function which requires a valid IP address. Normally, `dhcp_release()` would be used on networks where only a small number of IP addresses are available, but there are a large number of hosts which need sporadic network access.

> This function is non-blocking since it only sends one packet to the DHCP server and expects no response.

> ### Return value

> `0`: OK, lease was relinquished.

> `1`: Not released, because an address is currently being acquired, or because a boot file
> (from the BOOTP or DHCP server) is being downloaded, or because some other
> network resource is in use e.g. open TCP socket. Call `dhcp_release()` again
> after the resource is freed.

> `-1`: Not released, because DHCP was not used to obtain a lease, or no lease was acquired.

> ### Library

> BOOTP.LIB

> ## getdomainname

>     char * getdomainname( char *name, int length );

> ### Description

> Gets the current domain name. For example, if the controller's internet address is "test.mynetwork.com" then "mynetwork" is the domain portion of the name.

> The domain name can be changed by the `setdomainname()` function.

> ### Parameters

> #### name

> Buffer to place the name.

> #### length

> Maximum length of the name, or zero to get a pointer to the internal domain name string. Do not modify this string!

> ### Return value

> If `length` ≥1: Pointer to `name``.``` If `length` is not long enough to hold the domain name, a `NULL` string is written to `name``.`

> If `length` = 0: Pointer to internal string containing the domain name. Do not modify this string!

> ### Library

> BSDNAME.LIB

> ### See also

> setdomainname, gethostname, sethostname, getpeername, getsockname

> ### Example

>     main() {
>         sock_init();
>         printf("Using %s for a domain\n", getdomainname(NULL, 0));
>     }

> ## gethostid

>     longword gethostid( void );

> ### Description

> Return the IP address of the controller in host format.

> ### Return value

> IP address in host format, or zero if not assigned or not valid.

> ### Library

> IP.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> sethostid

> ### Example

>     main() {
>        char buffer[ 512 ];
>        sock_init();
>        printf("My IP address is %s\n", inet_ntoa( buffer, gethostid()));
>     }

> ## gethostname

>     char * gethostname( char *name, int length );

> ### Description

> Gets the host portion of our name. For example if the controller's internet address is "test.mynetwork.com" the host portion of the name would be "test."

> The host name can be changed by the `sethostname()` function.

> ### Parameters

> #### name

> Buffer to place the name.

> #### length

> Maximum length of the name, or zero for the internal host name buffer. Do not modify this buffer.

> ### Return value

> `length` ≥1: return `name`;
> `length` = 0: return internal host name buffer (do not modify!)

> ### Library

> BSDNAME.LIB

> ## getpeername

>     int getpeername( sock_type * s, void * dest, int * len );

> ### Description

> Gets the peer's IP address and port information for the specified socket.

> ### Parameters

> #### s

> Pointer to the socket.

> #### dest

> Pointer to `sockaddr` to hold the socket information for the remote end of the socket. The data structure is:

>     typedef struct sockaddr {
>       word      s_type;      /* reserved */
>       word      s_port;      /* port number, or zero if not connected */
>       longword  s_ip;        /* IP address, or zero if not connected */
>       byte      s_spares[6]; /* not used for tcp/ip connections */
>     };

> #### len

> Pointer to the length of `sockaddr`. A `NULL` pointer can be used to represent the `sizeof(struct sockaddr)`.

> ### Return value

> `0`: Success.
> `-1`: Failure.

> ### Library

> BSDNAME.LIB

> ### See also

> getsockname

> ## getsockname

>     int getsockname( sock_type * s, void * dest, int * len );

> ### Description

> Gets the controller's IP address and port information for a particular socket.

> ### Parameters

> #### s

> Pointer to the socket.

> #### dest

> Pointer to `sockaddr` to hold the socket information for the `local` end of the socket. The data structure is:

>     typedef struct sockaddr {
>       word      s_type;       /* reserved */
>       word      s_port;       /* port number, or zero if not connected */
>       longword  s_ip;         /* IP address, or zero if not connected */
>       byte      s_spares[6];  /* not used for tcp/ip connections */
>     };

> #### len

> Pointer to the length of `sockaddr`. A `NULL` pointer can be used to represent the `sizeof(struct sockaddr)`. `BSDNAME.LIB` will assume 14 bytes if a `NULL` pointer is passed.

> ### Return value

> `0`: Success.
> `-1`: Failure.

> ### Library

> BSDNAME.LIB

> ### See also

> getpeername

> ## htonl

>     longword htonl( longword value );

> ### Description

> This function converts a host-ordered double word to a network-ordered double word. This function is necessary if you are implementing standard internet protocols because the Rabbit does not use the standard for network-byte ordering. The network orders bytes with the most significant byte first and the least significant byte last. On the Rabbit, the bytes are in the opposite order.

> ### Parameters

> #### value

> Host-ordered double word.

> ### Return value

> Host word in network format, e.g. `htonl(0x44332211)` returns 0x11223344.

> ### Library

> NET.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> htons, ntohl, ntohs

> ## htons

>     word htons( word value );

> ### Description

> Converts host-ordered word to a network-ordered word. This function is necessary if you are implementing standard internet protocols because the Rabbit does not use the standard for network-byte ordering. The network orders bytes with the most significant byte first and the least significant byte last. On the Rabbit, the bytes are in the opposite order within each 16-bit section.

> ### Parameters

> #### value

> Host-ordered word.

> ### Return value

> Host-ordered word in network-ordered format, e.g. `htons(0x1122)` returns 0x2211.

> ### Library

> NET.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> htonl, ntohl, ntohs

> ## inet_addr

>     longword inet_addr( char * dotted_ip_string );

> ### Description

> Converts an IP address from dotted decimal IP format to its binary representation. No check is made as to the validity of the address.

> ### Parameters

> #### dotted_ip_string

> Dotted decimal IP string, e.g. "10.10.6.100".

> ### Return value

> `0`: Failure.
> Binary representation of `dotted_ip_string`: Success.

> ### Library

> IP.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> inet_ntoa

> ## inet_ntoa

>     char *inet_ntoa( char *s, longword ip );

> ### Description

> Converts a binary IP address to its dotted decimal format, e.g. `inet_ntoa(s,0x0a0a0664)` returns a pointer to "10.10.6.100".

> ### Parameters

> #### s

> Location to place the dotted decimal string. A sufficient buffer size would be 16 bytes.

> #### ip

> The IP address to convert.

> ### Return value

> Pointer to the dotted decimal string pointed to by `s`.

> ### Library

> IP.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> inet_addr

> ## ntohl

>     longword ntohl( longword value );

> ### Description

> Converts network-ordered long word to host-ordered long word. This function is necessary if you are implementing standard internet protocols because the Rabbit does not use the standard for network byte ordering. The network orders bytes with the most significant byte first and the least significant byte last. On the Rabbit, the bytes are in the opposite order.

> ### Parameters

> #### value

> Network-ordered long word.

> ### Return value

> Network-ordered long word in host-ordered format,
> e.g. `ntohl(0x44332211)` returns `0x11223344`

> ### Library

> NET.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> htons, ntohs, htonl

> ## ntohs

>     word ntohs( word value );

> ### Description

> Converts network-ordered word to host-ordered word. This function is necessary if you are implementing standard internet protocols because the Rabbit does not use the standard for network byte ordering. The network orders bytes with the most significant byte first and the least significant byte last. On the Rabbit, the bytes are in the opposite order.

> ### Parameters

> #### value

> Network-ordered word.

> ### Return value

> Network-ordered word in host-ordered format,
> e.g. `ntohs(0x2211)` returns 0x1122

> ### Library

> NET.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> htonl, ntohl, htons

> ## paddr

>     unsigned long paddr(void* pointer);

> ### Description

> Converts a logical pointer into its physical address. Use caution when converting address in the E000-FFFF range. This function will return the address based on the XPC on entry.

> ### Parameters

> #### pointer

> Pointer to convert.

> ### Return value

> Physical address of pointer.

> ### Library

> XMEM.LIB

> ## pd_getaddress

>     void pd_getaddress(int nic, void* buffer);

> ### Description

> This function copies the Ethernet address (e.g., MAC address) into the buffer.

> ### Parameters

> #### nic

> This parameter is reserved for future expandability and for now should be assigned a value of 0.

> #### buffer

> Place to copy address to. Must be at least 6 byes.

> ### Return value

> None.

> ### Library

> PKTDRV.LIB

> ### Example

>     main() {
>        char buf[6];
>        sock_init();
>        pd_getaddress(0,buf);

>        printf("Your Link Address is:%02x%02x:%02x%02x:%02x%02x \n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);

>     }

> ## _ping

>     int _ping( longword host_ip, longword sequence_number );

> ### Description

> Generates an ICMP request for host. NOTE: this is a macro that calls `_send_ping`.

> ### Parameters

> #### host_ip

> IP address to send ping.

> #### sequence_number

> User-defined sequence number.

> ### Return value

> `0`: Success.
> `1`: Failure: unable to resolve hardware address.
> `-1`: Failure: unable to transmit ICMP request.

> ### Library

> ICMP.LIB

> ### See also

> _chk_ping, _send_ping

> ## psocket

>     void psocket( void * s );

> ### Description

> Given an open UDP or TCP socket, the IP address of the remote host is printed out to the Stdio window in dotted IP format followed by a colon and the decimal port number on that machine. This routine can be useful for debugging your programs.

> ### Parameters

> #### s

> Pointer to a socket.

> ### Return value

> None.

> ### Library

> BSDNAME.LIB

> ## resolve

>     longword resolve( char *host_string );

> ### Description

> Converts a text string, which contains either the dotted IP address or host name, into the longword containing the IP address. In the case of dotted IP, no validity check is made for the address. NOTE: this function blocks. Names are currently limited to 64 characters. If it is necessary to lookup larger names include the following line in the application program:

>     #define DNS_MAX_NAME <len in chars>.

> If `DISABLE_DNS` has been defined, `resolve()` will not do DNS lookup.

> If you are trying to resolve a host name, you must set up at least one name server. You can set the default name server by defining the `MY_NAMESERVER` macro at the top of your program. When you call `resolve()`, it will contact the name server and request the IP address. If there is an error, `resolve()` will return 0L.

> To simply convert dotted IP to longword, see `inet_addr``()`.

> For a sample program, see the Example Using tcp_open() listed under `tcp_open()`.

> ### Parameters

> #### host_string

> Pointer to text string to convert.

> ### Return value

> `0`: Failure.
> `!0`: The IP address `*host_string` resolves to.

> ### Library

> DNS.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> _arp_resolve, inet_addr, inet_ntoa

> ## resolve_cancel

>     int resolve_cancel(int handle);

> ### Description

> Cancels the resolve request represented by the given handle. If the handle is 0, then this function cancels all outstanding resolve requests.

> ### Parameters

> #### handle

> Handle that represents a DNS lookup process, or 0 to cancel all outstanding resolve requests.

> ### Return value

> `RESOLVE_SUCCESS`: The resolve request corresponding to the given handle has been cancelled. The given handle will no longer be valid after this value is returned.

> `RESOLVE_HANDLENOTVALID`: There is no request for the given handle.

> `RESOLVE_NONAMESERVER`: No nameserver has been defined.

> ### Library

> DNS.LIB

> ### See also

> resolve_name_start, resolve_name_check, resolve

> ## resolve_name_check

>     int resolve_name_check(int handle, longword* resolved_ip);

> ### Description

> Checks if the DNS lookup represented by the given handle has completed. On success, it fills in the resolved IP address in the space pointed to by `resolved_ip`.

> ### Parameters

> #### handle

> Handle that represents a DNS lookup process.

> #### resolved_ip

> A pointer to a user-supplied `longword` where the resolved IP address will be placed.

> ### Return value

> `RESOLVE_SUCCESS`: The address was successfully resolved. The given handle will no longer be valid after this value is returned.

> `RESOLVE_AGAIN` The resolve process has not completed, call this function again.

> `RESOLVE_FAILED` The DNS server responded that the given host name does not exist. The given handle will no longer be valid if `RESOLVE_FAILED` is returned.

> `RESOLVE_TIMEDOUT` The request has been cancelled because a response from the DNS server was not received before the last timeout expired. The given handle will no longer be valid after this value is returned.

> `RESOLVE_HANDLENOTVALID` There is no DNS lookup occurring for the given handle.

> `RESOLVE_NONAMESERVER`: No nameserver has been defined.

> ### Library

> DNS.LIB

> ### See also

> resolve_name_start, resolve_cancel, resolve

> ## resolve_name_start

>     int resolve_name_start(char* hostname);

> ### Description

> Starts the process of resolving a host name into an IP address. The given host name is limited to `DNS_MAX_NAME` characters, which is 64 by default (63 characters + the `NULL` terminator). If a default domain is to be added, then the two strings together are limited to `DNS_MAX_NAME`.

> If `hostname` does not contain a '.' then the default domain (`MY_DOMAIN`) , if provided, is appended to `hostname`. If `hostname` with the appended default domain does not exist, `hostname` is tried by itself. If that also fails, the lookup fails.

> If `hostname` does contain a '.' then `hostname` is looked up by itself. If it does not exist, the default domain is appended, and that combination is tried. If that also fails, the lookup fails.

> If `hostname` ends with a '.', then the default domain is not appended. The host name is considered "fully qualified." The lookup is attempted without the ending '.' and if that fails no other combinations are attempted.

> This function returns a handle that must be used in the subsequent `resolve_name_check()` and `resolve_cancel()` functions.

> ### Parameters

> #### hostname

> Host name to convert to an IP address

> ### Return value

> >`0`: Handle for calls to `resolve_name_check()` and `resolve_cancel()`.
> `RESOLVE_NOENTRIES`: Could not start the resolve process because there were no resolve entries free.
> `RESOLVE_LONGHOSTNAME`: The given hostname was too large.
> `RESOLVE_NONAMESERVER`: No nameserver has been defined.

> ### Library

> DNS.LIB

> ### See also

> resolve_name_check, resolve_cancel, resolve

> ## rip

>     char * rip( char * string );

> ### Description

> Strips newline (\n) and/or carriage return (\r) from a string. Only the first \n and \r characters are replaced with \0s. The resulting string beyond the first \0 character is undefined.

> ### Parameters

> #### string

> Pointer to a string.

> ### Return value

> Pointer to the modified string.

> ### Library

> NET.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### Example

>     setmode( s, TCP_MODE_ASCII );
>     ...
>     sock_puts( s, rip( questionable_string ));

> NOTE | In ASCII mode `sock_puts()` adds \n; `rip` is used to make certain the string does not already have a newline character. Remember, `rip` modifies the source string, not a copy!

> ## router_add

>     ATHandle router_add(longword ipaddr, byte iface, longword subnet, longword mask, word flags);

> ### Description

> Add a router to the router table. The same router can be added multiple times, with different subnet and mask. Normally, only one entry is needed in order to access non-local subnets: this entry should be specified with a zero mask. The hardware address of the router is not immediately resolved, however this can be done explicitly by calling `arpresolve_start()` with the same IP address. Otherwise, the router will be resolved only when it first becomes necessary.

> ### Parameters

> #### ipaddr

> IP address of the router. This address should be on the local subnet, since non-local routers are not supported.

> #### iface

> Interface to use to access this router, or `IF_DEFAULT`.

> #### subnet

> Subnet accessible through this entry.

> #### mask

> Subnet mask for this entry.

> #### flags

> Flags word: set to zero (non-zero reserved for internal use).

> ### Return Value

> Positive value: completed successfully. The return value is the ARP cache table entry for this router.

> `ATH_NOENTRIES`: insufficient space in either the router or ARP cache tables.

> ### Library

> ARP.LIB

> ## router_del_all

>     void router_del_all(void);

> ### Description

> Delete all router table entries. This will make any host that is not on the local subnet inaccessible. This function is usually called in preparation for adding a new router entry.

> ### Library

> ARP.LIB

> ## router_delete

>     ATHandle router_delete(longword ipaddr);

> ### Description

> Delete a router from the router table. All instances of the router's IP address are deleted, and the ARP cache table entry is flushed.

> ### Parameter

> #### ipaddr

> IP address of the router. This address should be on the local subnet, since non-local routers are not supported.

> ### Return Value

> Positive value: completed successfully.
> `ATH_NOTFOUND`: specified entry did not exist.

> ### Library

> ARP.LIB

> ## router_for

>     ATHandle router_for(longword ipaddr, byte * router_used, byte * r_iface);

> ### Description

> Return the ARP cache table entry corresponding to the router that handles the given IP address. If there is a pre configured router for the given address, it is selected. Otherwise, routers discovered via DHCP or ICMP router discovery are searched, with the highest preference being selected. Failing this, if there is a point-to-point interface, this is selected as the default.

> An alternative mode of calling this function is invoked if `ipaddr` is zero. In this case, the default router for the specified interface (`*r_iface`) is returned. If `r_iface` is `NULL`, then the default interface is assumed:`IF_DEFAULT`, the only interface supported at present. `IF_DEFAULT` may refer to the primary ethernet NIC or a PPP connection that uses a serial port or the primary ethernet NIC.

> ### Parameters

> #### ipaddr

> IP address of the host which is not on the local subnet.

> #### router_used

> If not `NULL`, the byte at this location is set to the index of the router in the router table.

> #### r_iface

> If not `NULL`, the byte at this location is set to the interface number that can access the router.

> ### Return Value

> Positive value: completed successfully.
> `ATH_NOROUTER`: no suitable router found. Either no router is configured, or the given IP address is on the local subnet.

> ### Library

> ARP.LIB

> ## router_print

>     int router_print(byte r)

> ### Description

> Print a router table entry, indexed by '`r`.' This is for debugging only, since the results are printed to the Dynamic C stdio window. '`r`' may be obtained from the `router_for()` function, by passing `&r` as the `router_used` parameter to that function.

> If the specified router entry is not in use, nothing is printed and the return value is non-zero. Otherwise, the information is printed and zero returned.

> See `router_printall()` for a description of the output fields printed.

> ### Parameter

> #### r

> Router table index. A number from 0 through (`ARP_ROUTER_TABLE_SIZE`-1).

> ### Return Value

> `0`: Success, information printed to stdio window.
> `!0`: Entry is not in use.

> ### Library

> ARP.LIB

> ### See Also

> router_printall

> ## router_printall

>     int router_printall(void)

> ### Description

> Print all router table entries. This is for debugging only, since the results are printed to the Dynamic C stdio window. If no routers exist in the table, nothing is printed and the return value is non-zero.

> There are 6 fields for each router entry:

> Router Table Entry Field | Description of Field
> # | `The entry number.`
> Flags | A list of the following characters: `P` = this entry pre configured `T` = transient entry `D` = added by DHCP/BOOTP `R` = added by ICMP redirect `?` = router not reachable `H` = router's hardware address resolved
> Address | `Either the router's IP address or an indication that the entry is a point-to-point link.`
> i/f | `Interface number.`
> Net/preference | For pre configured entries, indicates the network(s) which are served by this entry (the Mask indicates which bits of the IP address are used to match with the network address). For non-pre configured entries, this is the "preference value" assigned.
> Mask/exp(sec) | For pre configured entries, the bitmask to apply to IP addresses when matching against the above network. Otherwise, is the expiry time from the present, in seconds, of a transient entry.

> ### Return Value

> `0`: Success, information printed to stdio window.
> `!0`: No routers in the table.

> ### Library

> ARP.LIB

> ## _send_ping

>     int _send_ping( longword host, longword countnum, byte ttl, byte tos, longword *theid );

> ### Description

> Generates an ICMP request for host.

> ### Parameters

> #### host

> IP address to send ping.

> #### countnum

> User-defined count number.

> #### ttl

> Time to live for the packets (hop count). 255 is a standard value for this field. See `sock_set_ttl()` for details.

> #### tos

> Type of service on the packets. See `sock_set_tos()` for details.

> #### theid

> The identifier that was sent out.

> ### Return value

> `0`: Success.
> `1`: Failure: unable to resolve hardware address.
> `-1`: Failure: unable to transmit ICMP request.

> ### Library

> ICMP.LIB

> ### See also

> _chk_ping, _ping, sock_set_ttl, sock_set_tos

> ## setdomainname

>     char *setdomainname( char *name );

> ### Description

> The domain name returned by `getdomainname()` and used for `resolve()` is set to the value in the string pointed to by `name`. Changing the contents of the string after a `setdomainname()` will change the value of the system domain string. It is not recommended. Instead dedicate a static location for holding the domain name.

> `setdomainname( NULL )` is an acceptable way to remove any domain name and subsequent `resolve` calls will not attempt to append a domain name.

> ### Parameters

> #### name

> Pointer to string.

> ### Return value

> Pointer to string that was passed in.

> ### Library

> BSDNAME.LIB

> ### See also

> getdomainname, sethostname, gethostname, getpeername, getsockname

> ## sethostid

>     longword sethostid( longword ip );

> ### Description

> This function changes the system's current IP address. Changing this address will disrupt existing TCP or UDP sessions. You should close all sockets before calling this function.

> Normally there is no need to call this function. The macro `MY_IP_ADDRESS` defines an initial IP address for this host, or you can define `USE_DHCP` to obtain a dynamically assigned address. In either case, it is not recommended to use this function to change the address.

> ### Parameters

> #### ip

> New IP address.

> ### Return value

> New IP address.

> ### Library

> IP.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> gethostid

> ## sethostname

>     char * sethostname( char *name);

> ### Description

> Sets the host portion of our name.

> ### Parameters

> #### name

> The new host name.

> ### Return value

> Pointer to internal hostname buffer on success, or
> `NULL` on error (if hostname is too long).

> ### Library

> BSDNAME.LIB

> ## sock_abort

>     void sock_abort( void * s );

> ### Description

> Close a connection immediately. Under TCP this is done by sending a RST (reset).

> Under UDP there is no difference between `sock_close()` and `sock_abort()`.

> ### Parameters

> #### s

> Pointer to a socket.

> ### Return value

> None.

> ### Library

> NET.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> sock_close,

> ## sock_bytesready

>     int sock_bytesready( void * s );

> ### Description

> For TCP sockets:

> If the socket is in binary mode, `sock_bytesready()` returns the number of bytes waiting to be read. If there are no bytes waiting, it returns -1.

> In ASCII mode, `sock_bytesready()` returns -1 if there are no bytes waiting to be read or the line that is waiting is incomplete (no line terminating character has been read). The number of bytes waiting to be read will be returned given one of the following conditions:

> - the buffer is full
> - the socket has been closed (no line terminating character can be sent)
> - a complete line is waiting

> In ASCII mode, a blank line will be read as a complete line with length 0, which will be the value returned. `sock_bytesready()` handles ASCII mode sockets better than `sock_dataready()`, since it can distinguish between an empty line on the socket and an empty buffer`.`

> For UDP sockets:

> Returns the number of bytes in the next datagram to be read. If it is a datagram with no data (an empty datagram), then it will return 0. If there are no datagrams waiting, then it returns -1.

> ### Parameters

> #### s

> Pointer to a socket.

> ### Return value

> `-1`: No bytes waiting to be read.
> `0`: If in ASCII mode and a blank line is waiting to be read;
> for DC 7.05 and later, a UDP datagram with 0 bytes of data is waiting to be read.
> `>0`: The number of bytes waiting to be read.

> ### Library

> NET.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> sock_established, sockstate

> ## sock_close

>     void sock_close( void * s );

> ### Description

> Attempts to close a socket; no more data may be sent or received through that socket.

> In the case of UDP, the socket is closed immediately since UDP is a connectionless protocol. TCP, however, is a connection-oriented protocol so the close must be negotiated with the remote computer. Wait for `tcp_tick()` to return zero when passed the socket to ensure that a TCP connection is closed.

> In emergency cases, it is possible to abort the TCP connection rather than close it. Although not recommended for normal transactions, this service is available and is used by all TCP/IP systems.

> ### Parameters

> #### s

> Pointer to a socket.

> ### Library

> NET.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> sock_abort, sock_tick

> ## sock_dataready

>     int sock_dataready( void *s );

> ### Description

> Returns the number of bytes waiting to be read. If the socket is in ASCII mode, this function returns zero if a newline character has not been read or the buffer is not full. For UDP sockets, the function returns the number of bytes in the next datagram.

> This function cannot tell the difference between no bytes to read and either a blank line or a UDP datagram with no data. For this reason, use `sock_bytesready()` instead.

> ### Parameters

> #### s

> Pointer to a socket.

> ### Return value

> `0`: No bytes to read;
> or newline not yet read if the socket is in ASCII mode;
> or (for DC 7.05 and later) if a UDP datagram has 0 bytes of data waiting to be read.
> `>0`: Number of bytes ready to read.

> ### Library

> NET.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See Also

> sock_bytesready

> ## sockerr

>     char *sockerr( void * s );

> ### Description

> Gets the last ASCII error message recorded for the specified socket. Use of this function will introduce a lot of string constants in root memory. For production programs, it is better to use error numbers (without translation to strings).

> ### Parameters

> #### s

> Pointer to a socket.

> ### Return value

> Pointer to the string that represents the last error message for the socket.

> `NULL` pointer if there have been no errors.

> If the symbol `SOCKERR_NO_RETURN_NULL` is defined, then if no error occurred the string "OK" will be returned instead of a `NULL` pointer.

> The error messages are read-only; do not modify them!

> ### Library

> NETERRNO.LIB

> ### See Also

> sock_error, sock_perror

> ### Example

>     char *p;
>     ...
>     if ( p = sockerr( s ))
>        printf("Socket closed with error '%s'\n\r", p );

> ## sock_error

>     int sock_error(void *s, int clear);

> ### Description

> Return the most recent error number for the specified socket, which may be a TCP or UDP socket. Up to two error codes may be queued to a socket.

> ### Parameters

> #### s

> socket

> #### clear

> 0: do not clear the returned error condition.

> 1: clear the returned error from the socket. You can call this function again to get the next older error code (if any).

> ### Return Value

> `0`: no error.
> `!0`: one of the `NETERR_*` constants defined in `NETERRNO.LIB`.

> ### Library

> NETERRNO.LIB

> ### See Also

> sockerr, sock_perror

> ## sock_established

>     int sock_established( void *s );

> ### Description

> TCP connections require a handshaked open to ensure that both sides recognize a connection. Whether the connection was initiated with `tcp_open()` or `tcp_listen()`, `sock_established()` will continue to return 0 until the connection is established, at which time it will return 1. It is not enough to spin on this after a listen because it is possible for the socket to be opened, written to and closed between two checks. `sock_bytesready()` can be called with `sock_established()` to handle this case.

> UDP is a connectionless protocol, hence `sock_established()` always returns 1 for UDP sockets.

> ### Parameters

> #### s

> Pointer to a socket.

> ### Return value

> `0`: Not established.
> `1`: Established.

> ### Library

> TCP.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> sock_bytesready, sockstate

> ## sock_fastread

>     int sock_fastread( tcp_Socket *s, byte *dp, int len );

> ### Description

> `sock_fastread()` attempts to read data from a socket. If possible, the buffer, `dp`, is filled, otherwise, only the number of bytes read is returned. A return value of -1 indicates a socket error.

> This function cannot be used on UDP sockets after `sock_recv_init()` is called.

> ### Parameters

> #### s

> Pointer to a socket.

> #### dp

> Buffer to put bytes that are read.

> #### len

> Maximum number of bytes to write to the buffer.

> ### Return value

> ≥`0`: Success, number of bytes read.
> `-1`: Error.

> ### Library

> TCP.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> sock_read, sock_fastwrite, sock_write

> ### Example

> Note that `sock_fastread()` and `sock_read()` do not necessarily return a complete or single line--they return blocks of bytes. In comparison, `sock_getc()` returns a single byte at a time and thus yields poor performance.

>     do {
>        /* this function does not block */
>        len = sock_fastread( s, buffer, sizeof(buffer)-1 );
>        if (len>0) {
>           buffer[ len ] = 0;
>           printf( "%s", buffer );
>        }
>     } while(tcp_tick(s));

> ## sock_fastwrite

>     int sock_fastwrite( tcp_Socket *s, byte *dp, int len );

> ### Description

> Writes up to `len` bytes from `dp` on socket `s`. This function writes as many bytes as possible to the socket and returns that number of bytes.

> For UDP, `sock_fastwrite()` will send one record if
> `len <= ETH_MTU - 20 - 8`

> `ETH_MTU` is the Ethernet Maximum Transmission Unit; 20 is the IP header size and 8 is the UDP header size. By default, this is 572 bytes. If `len` is greater than this number, then the function does not send the data and returns -1. Otherwise, the UDP datagram would need to be fragmented.

> For TCP, the new data is queued for sending and `sock_fastwrite()` returns the number of bytes that will be sent. The data may be transmitted immediately if enough data is in the buffer, or sufficient time has expired, or the user has explicitly used `sock_flushnext()` to indicate this data should be flushed immediately. In either case, no guarantee of acceptance at the other end is possible.

> ### Parameters

> #### s

> Pointer to a socket.

> #### dp

> Buffer to be written.

> #### len

> Maximum number of bytes to write to the socket.

> ### Return value

> Number of bytes written, or
> `-1` if there was an error.

> ### Library

> TCP.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ## sock_flush

>     void sock_flush( tcp_Socket *s );

> ### Description

> `sock_flush()` will flush the unwritten portion of the TCP buffer to the network. No guarantee is given that the data was actually delivered. In the case of a UDP socket, no action is taken.

> `sock_flushnext()` is recommended over `sock_flush()`.

> ### Parameters

> #### s

> Pointer to a socket.

> ### Return value

> None.

> ### Library

> TCP.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> sock_flushnext, sock_fastwrite, sock_write, sockerr

> ## sock_flushnext

>     void sock_flushnext( tcp_Socket *s );

> ### Description

> Writing to TCP sockets does not guarantee that the data are actually transmitted or that the remote computer will pass that data to the other client in a timely fashion. Using a flush function will guarantee that `DCRTCP.LIB` places the data onto the network. No guarantee is made that the remote client will receive that data.

> `sock_flushnext()` is the most efficient of the flush functions. It causes the next function that sends data to the socket to flush, meaning the data will be transmitted immediately.

> Several functions imply a flush and do not require an additional flush: `sock_puts()`, and sometimes `sock_putc()` (when passed a \n).

> ### Parameters

> #### s

> Pointer to a socket.

> ### Return value

> None.

> ### Library

> TCP.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> sock_write, sock_fastread, sock_read, sockerr, sock_flush, sock_flushnext

> ## sock_getc

>     int sock_getc( tcp_Socket *s );

> ### Description

> Gets the next character from the socket. NOTE: This function blocks.

> This function cannot be used on UDP sockets after `sock_recv_init()` is called.

> ### Parameters

> #### s

> Pointer to a socket.

> ### Return value

> Character read or `-1` if error.

> ### Library

> TCP.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### Example

>     do {
>        if (sock_bytesready( s ) > 0)

>           putchar( sock_getc( s ));
>     } while (tcp_tick(s));

> ## sock_gets

>     int sock_gets( tcp_Socket *s, char *text, int len );

> ### Description

> Reads a string from a socket and replaces the CR or LF with a '\0'. If the string is longer than `len`, the string is null terminated and the remaining characters in the string are discarded.

> To use `sock_gets()`, you must first set ASCII mode using the function `sock_mode()`or the macro `tcp_set_ascii()`.

> This function cannot be used on UDP sockets after `sock_recv_init()` is called.

> ### Parameters

> #### s

> Pointer to a socket

> #### text

> Buffer to put the string.

> #### len

> Max length of buffer.

> ### Return value

> `0`: Either the buffer is empty or the buffer has room and the connection
> can get more data, but no '\r' or '\n' was read.
> `>0`: The length of the string.
> `-1`: Function was called with a UDP socket ( valid for Dynamic C 7.05 and later).

> ### Library

> TCP.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> sock_puts, sock_putc, sock_getc, sock_read, sock_write

> ### Example

>     sock_mode( s, TCP_MODE_ASCII );
>     do {
>        if (sock_bytesready( s ) > 0) {
>           sock_gets( s, buffer, sizeof(buffer)-1 );
>           puts( buffer );
>        }
>     } while (tcp_tick( s );

> ## sock_init

>     int sock_init(void);

> ### Description

> This function initializes the packet driver and `DCRTCP.LIB` using the compiler defaults for configuration. This function must be called before using other `DCRTCP.LIB` functions.

> The return value indicates whether the network is available. If the return code is 1or 3, then the network is not usable. If the return code is 2, then the network is usable because suitable fallbacks were defined; particularly `MY_IP_ADDRESS`. It is only possible to get return codes 2 or 3 is `USE_DHCP` is defined. Typically, return codes 2 or 3 mean that there is no DHCP server available within approximately 30 seconds from calling `sock_init()`. The timeout can be adjusted by setting the global variable `_bootptimeout` to a suitable value before calling `sock_init()`.

> If `USE_DHCP` and `MY_IP_ADDRESS` are both defined, then by default the global variable `_survivebootp` will be set to TRUE. If `_survivebootp` is set to FALSE before calling `sock_init()`, then the fallbacks will not be used. That is, return code 2 will never be returned.

> If you use `ucos2.lib`, be sure to call `OSInit()` before calling `sock_init()`.

> ### Return Value

> `0`: OK.
> `1`: Ethernet packet driver initialization failed.
> `2`: DHCP failed, using fallback definitions.
> `3`: DHCP failed, no fallbacks defined.
> Other: reserved.

> ### Library

> NET.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ## sock_mode

>     word sock_mode( void *s, word mode );

> ### Description

> Change some of the socket options. Depending on whether `s` is a TCP or UDP socket, you may pass OR'd combinations of the following flags in the mode parameter. For a TCP socket, only the `TCP_MODE_*` flags are relevant. For a UDP socket, only the `UDP_MODE_*` flags are relevant. Do not use the wrong flags for the given socket type.

> Note: it is more convenient, faster, and safer to use the macro equivalent, if it is only desired to change one mode at a time. If you use this function, then you must specify the setting of all relevant flags (TCP or UDP).

> The macros do not do socket locking so, strictly speaking, µC/OS users should call this function.

> #### TCP Modes:

> #### TCP_MODE_ASCII | TCP_MODE_BINARY (default)

> TCP and UDP sockets are usually in binary mode which means an arbitrary stream of bytes is allowed (TCP is treated as a byte stream and UDP is treated as records filled with bytes.) The default is `TCP_MODE_BINARY`.`` By changing the mode to `TCP_MODE_ASCII`, some of the `DCRTCP.LIB` functions will see a stream of records terminated with a newline character.

> In ASCII mode, `sock_bytesready()` will return -1 until a newline-terminated string is in the buffer or the buffer is full. `sock_puts()` will append a newline to any output. `sock_gets()` (which should only be used in ASCII mode) removes the newline and null terminates the string.

> #### Macros:

>     tcp_set_binary(s)
>     tcp_set_ascii(s)

> #### TCP_MODE_NAGLE (default) | TCP_MODE_NONAGLE

> The Nagle algorithm may substantially reduce network traffic with little negative effect on a user (In some situations, the Nagle algorithm even improves application performance.) The default is `TCP_MODE_NAGLE`. This mode only affects TCP connections.

> #### Macros:

>     tcp_set_nagle(s)
>     tcp_set_nonagle(s)

> #### UDP Modes:

> #### UDP_MODE_CHK | UDP_MODE_NOCHK

> Checksums are required for TCP, but not for UDP. The default is `UDP_MODE_CHK.` If you are providing a checksum at a higher level, the low-level checksum may be redundant. The checksum for UDP can be disabled by selecting the `UDP_MODE_NOCHK` flag. Note that you do not control whether the remote computer will send checksums. If that computer does checksum its outbound data, `DCRTCP.LIB` will check the received packet's checksum.

> #### Macros:

>     udp_set_chk(s)
>     udp_set_nochk(s)

> #### UDP_MODE_NOICMP (default) | UDP_MODE_ICMP

> Marks this socket for receipt of ICMP error messages. The messages are queued like normal received datagrams, and read using `udp_recvfrom()`, which returns -3 when ICMP messages are returned instead of normal datagrams. Only ICMP messages which are relevant to the current binding of the socket are queued.

> #### Macros:

>     udp_set_noicmp(s)
>     udp_set_icmp(s)

> #### UDP_MODE_NODICMP (default) | UDP_MODE_DICMP

> Marks this socket as the default receiver of ICMP messages which cannot be assigned to a particular UDP socket. This would be used for UDP sockets that are used with many different `sendto` addresses, since the ICMP message may refer to a message sent some time ago (with different destination address than the most recent). Only one UDP socket should be set with this mode.

> #### Macros:

>     udp_set_nodicmp(s)
>     udp_set_dicmp(s)

> ### Parameters

> #### s

> Pointer to a socket.

> #### mode

> New mode for specified socket.

> ### Return Value

> Resulting mode flags

> ### See Also

> inet_addr

> ### Library

> NET.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ## sock_perror

>     void sock_perror(void *s, const char * prefix);

> ### Description

> Prints out the most recent error messages for a socket, and clear the errors. This calls `sockerr()` and `printf()`, so it should only be called for debugging a new application. The output is in the format:

>     [TCP|UDP] socket (ipaddr:port -> ipaddr:port) msg1; msg2

> where`msg1` and, possibly,`msg2` are the most recent error messages. The initial string is "TCP" or "UDP" for open sockets, or may be "Closed" if the socket is currently closed (either TCP or UDP). Up to two error codes may be queued to a socket.

> If there are no errors, nothing is printed.

> ### Parameters

> #### s

> Pointer to TCP or UDP socket.

> #### prefix

> Pointer to text to add to generated messages, or `NULL`.

> ### Library

> NETERRNO.LIB

> ### See Also

> sock_error, sockerr

> ## sock_preread

>     int sock_preread( tcp_Socket *s, byte *dp, int len );

> ### Description

> This function reads up to `len` bytes from the socket into the buffer `dp`. The bytes are not removed from the socket's buffer.

> ### Parameters

> #### s

> Pointer to a socket structure.

> #### dp

> Buffer to preread into.

> #### len

> Maximum number of bytes to preread.

> ### Return value

> `0`: No data waiting.
> `-1`: Error.
> `>0`: Number of preread bytes.

> ### Library

> TCP.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> sock_fastread, sock_fastwrite, sock_read, sock_write

> ## sock_putc

>     byte sock_putc( tcp_Socket *s, byte c );

> ### Description

> A single character is placed on the output buffer. In the case of `\n', the buffer is flushed as described under `sock_flushnext`. No other ASCII character expansion is performed.

> Note that `sock_putc` uses `sock_write`, and thus may block if the output buffer is full. See `sock_write` for more details.

> ### Parameters

> #### s

> Pointer to a socket.

> #### c

> Character to send.

> ### Return value

> The character `c`.

> ### Library

> TCP.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> sock_read, sock_write, sock_fastread, sock_fastwrite, sock_mode

> ## sock_puts

>     int sock_puts( tcp_Socket *s, byte *dp );

> ### Description

> A string is placed on the output buffer and flushed as described under `sock_flushnext``()`. If the socket is in ASCII mode, CR and LF are appended to the string. No other ASCII character expansion is performed. In binary mode, the string is sent as is.

> Note that `sock_puts()` uses `sock_write()`, and thus may block if the output buffer is full. See `sock_write``()` for more details.

> ### Parameters

> #### s

> Pointer to a socket.

> #### dp

> Buffer to read the string from.

> ### Return value

> ≥`0`: Length of string in `dp`.
> `-1`: Function was called with a UDP socket (valid for Dynamic C 7.05 and later).

> ### Library

> TCP.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> sock_gets, sock_putc, sock_getc, sock_read, sock_write

> ## sock_rbleft

>     int sock_rbleft( void *s );

> ### Description

> Determines the number of bytes available in the receive buffer.

> ### Parameters

> #### s

> Pointer to a socket.

> ### Return value

> Number of bytes available in the receive buffer.

> ### Library

> NET.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> sock_rbsize, sock_rbused, sock_tbsize, sock_tbused, sock_tbleft

> ## sock_rbsize

>     int sock_rbsize( void *s );

> ### Description

> Determines the size of the receive buffer for the specified socket.

> ### Parameters

> #### s

> Pointer to a socket.

> ### Return value

> The size of the receive buffer.

> ### Library

> NET.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> sock_rbleft, sock_rbused, sock_tbsize, sock_tbused, sock_tbleft

> ## sock_rbused

>     int sock_rbused( void *s );

> ### Description

> Returns the number of bytes in use in the receive buffer for the specified socket.

> ### Parameters

> #### s

> Pointer to a socket.

> ### Return value

> Number of bytes in use.

> ### Library

> NET.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> sock_rbleft, sock_tbsize, sock_tbused, sock_tbleft

> ## sock_read

>     int sock_read( tcp_Socket *s, byte *dp, int len );

> ### Description

> `sock_read()` will busywait until `len` bytes are read or a socket error exists. If `sock_yield()` has been called, the user-defined function that is passed to it will be called in a tight loop while `sock_read()` is busywaiting.

> This function cannot be used on UDP sockets after `sock_recv_init()` is called.

> ### Parameters

> #### s

> Pointer to a socket.

> #### dp

> Buffer to store bytes that are read.

> #### len

> Maximum number of bytes to write into the buffer.

> ### Return value

> Number of bytes read: Success.
> `-1`: Error.

> ### Library

> TCP.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> sock_fastread, sock_fastwrite, sock_write, sockerr

> ### Example

> Note that `sock_fastread()` and `sock_read()` do not necessarily return a complete or single line--they return blocks of bytes. In comparison, `sock_getc()` returns a single byte at a time and thus yields poor performance.

>     do {
>        len = sock_bytesready( s );
>        if (len > 0) {
>           if (len > sizeof( buffer) - 1)
>           {                                 // If too many bytes, read
>              len = sizeof( buffer ) - 1;    // some now, read the rest
>           }                                 // next time around.
>           sock_read( s, buffer, len );
>           buffer[ len ] = 0;
>           printf( "%s", buffer );
>        }
>     } while ( tcp_tick( s ));

> ## sock_recv

>     int sock_recv( sock_type *s, char *buffer, int len );

> ### Description

> After a UDP socket is initialized with `udp_open()` and `sock_recv_init()`, `sock_recv()``` scans the buffers for any datagram received by that socket. This function is not available starting with Dynamic C 7.05 (see Section 2.3).

> ### Parameters

> #### s

> Pointer to a UDP socket.

> #### buffer

> Buffer to put datagram.

> #### maxlength

> Length of buffer.

> ### Return value

> `>0`: Length of datagram.
> `0`: No datagram found.
> `-1`: Receive buffer not initialized with `sock_recv_init()`.

> ### Library

> DCRTCP.LIB

> ### See also

> sock_recv_from, sock_recv_init

> ### Example using sock_recv()

>     #define MY_IP_ADDRESS "10.10.6.100"
>     #define MY_NETMASK "255.255.255.0"
>     #memmap xmem

>     #use "dcrtcp.lib"

>     #define SAMPLE 401

>     udp_Socket data;
>     char bigbuf[ 8192 ];

>     main() {
>         word templen;
>         char spare[ 1500 ];

>         sock_init();
>         if ( !udp_open( &data, SAMPLE, 0xffffffff, SAMPLE, NULL) ) {
>             puts("Could not open broadcast socket");
>             exit( 3 );
>         }

>         /* set large buffer mode */
>         if ( sock_recv_init( &data, bigbuf, sizeof( bigbuf ))) {
>             puts("Could not enable large buffers");
>             exit( 3 );
>         }

>         sock_mode( &data, UDP_MODE_NOCHK );    /* turn off checksums */

>         while (1) {
>             tcp_tick( NULL );

>             if ( templen = sock_recv( &data, spare, sizeof( spare ))) {
>                     /* something received */
>                 printf("Got %u byte packet\n", templen );
>             }
>         }
>     }

> ## sock_recv_from

>     int sock_recv_from( sock_type *s, long *hisip, word *hisport, char *buffer, int len);

> ### Description

> After a UDP socket is initialized with `udp_open()` and `sock_recv_init()`, `sock_recv_from``` `()``` scans the buffers for any datagram received by that socket and identifies the remote host's address. This function is not available starting with Dynamic C 7.05 (see Section 2.3).

> ### Parameters

> #### s

> Pointer to UDP socket.

> #### hisip

> IP of remote host, according to UDP header.

> #### hisport

> Port of remote host.

> #### buffer

> Buffer to put datagram in.

> #### len

> Length of buffer.

> ### Return value

> `>0`: Length of datagram received;
> `0`: No datagram;
> `-1`: Receive buffer was not initialized with `sock_recv_init()`.

> ### Library

> DCRTCP.LIB

> ### See also

> sock_recv, sock_recv_init

> ## sock_recv_init

>     int sock_recv_init( sock_type *s, void *space, word len);

> ### Description

> This function is not available starting with Dynamic C 7.05 (see Section 2.3).

> The basic socket reading functions (`sock_read()`, `sock_fastread()`, etc.) are not adequate for all your UDP needs. The most basic limitation is their inability to treat UDP as a record service.

> A record service must receive distinct datagrams and pass them to the user program as such. You must know the length of the received datagram and the sender (if you opened in broadcast mode). You may also receive the datagrams very quickly, so you must have a mechanism to buffer them.

> Once a socket is opened with `udp_open()`, you can use `sock_recv_init()` to initialize that socket for `sock_recv()` and `sock_recv_from()`. Note that `sock_recv()` and related functions are `incompatible` with `sock_read()`, `sock_fastread()`, `sock_gets()``` and `sock_getc()`. Once you have used `sock_recv_init()`, you can no longer use the older-style calls.

> `sock_recv_init()` installs a large buffer area which gets segmented into smaller buffers. Whenever a UDP datagram arrives, `DCRTCP.LIB` stuffs that datagram into one of these new buffers. The new functions scan those buffers. You must select the size of the buffer you submit to `sock_recv_init()`; make it as large as possible, say 4K, 8K or 16K.

> For a sample program, see Example using sock_recv() listed under `sock_recv()`.

> ### Parameters

> #### s

> Pointer to a UDP socket.

> #### space

> Buffer of temporary storage space to store newly received packets.

> #### len

> Size of the buffer.

> ### Return value

> `0`

> ### Library

> DCRTCP.LIB

> ### See also

> sock_recv_from, sock_recv

> ## sock_resolved

>     int sock_resolved(void * s)

> ### Description

> Check whether the socket has a valid destination hardware address. This is typically used for UDP sockets, but may also be used for TCP sockets. If this function returns zero (FALSE), then any datagrams you send using `udp_send()` or `udp_sendto()` may not be transmitted because the destination hardware address is not known.

> If the current destination IP address of the socket is zero (i.e. the socket is passively opened), this function returns zero, since datagrams cannot be transmitted from a passively opened socket.

> If `udp_bypass_arp()` is in effect, the return value from this function is unaffected, however datagrams will still be sent to the specified hardware address (since the normal resolve process is bypassed).

> Note that a hardware address may become invalid after being valid, since the underlying ARP table may need to purge the entry. This would be rare, but if any UDP application needs to ensure that all packets are actually transmitted, which is a questionable goal since UDP is unreliable, then this function should be consulted before each send. If this function returns 0, then the UDP socket should be re-opened.

> The hardware address may also be invalidated if `udp_sendto()` is called with a different destination IP address, that has not been determined based on an incoming datagram.

> This function is not required for TCP sockets, since the TCP library handles these details internally.

> ### Parameter

> #### s

> Pointer to open TCP or UDP socket

> ### Return Value:

> `0`: Destination hardware address not valid
> `!0`: Destination hardware address resolved OK.

> ### Library

> NET.LIB

> ### See Also

> udp_extopen, arpresolve_start, arpresolve_check, udp_waitopen, udp_sendto, udp_bypass_arp

> ## sock_set_tos

>     void sock_set_tos(void* s, byte tos);

> ### Description

> Set the IP "Type Of Service" field in outgoing packets for this socket. The given TOS will be in effect until the socket is closed. When a socket is opened (or re-opened), the TOS will be set to the default (`TCP_TOS` or `UDP_TOS` as appropriate). If not overridden, the defaults are zero (`IPTOS_DEFAULT`) in both cases.

> ### Parameters

> #### s

> Pointer to open TCP or UDP socket.

> #### tos

> Type Of Service. This should be one of the following values:

> · `IPTOS_DEFAULT` - Default service
> · `IPTOS_CHEAP` - Minimize monetary cost
> · `IPTOS_RELIABLE` - Maximize reliability
> · `IPTOS_CAPACIOUS` - Maximize throughput
> · `IPTOS_FAST` - Minimize delay
> · `IPTOS_SECURE` - Maximize security.

> Other value may be used (since TOS is just a number between 0 and 255), but this should only be done for experimental purposes.

> ### Library

> NET.LIB

> ### See Also

> sock_set_ttl

> ## sock_set_ttl

>     void sock_set_ttl(void* s, byte ttl);

> ### Description

> Set the IP "Time To Live" field in outgoing packets for this socket. The given TTL will be in effect until the socket is closed. When a socket is opened (or re-opened), the TTL will be set to the default (`TCP_TTL` or `UDP_TTL` as appropriate). If not overridden, the defaults are 64 in both cases.

> ### Parameters

> #### s

> Pointer to open TCP or UDP socket.

> #### ttl

> Time To Live. This is a value between 1 and 255. A value of zero is also accepted, but will have undesirable consequences.

> ### Library

> NET.LIB

> ### See Also

> sock_set_tos

> ## sockstate

>     char *sockstate( void * s );

> ### Description

> Returns a string that gives the current state for a socket.

> ### Parameters

> #### s

> Pointer to a socket.

> ### Return value

> An ASCII message which represents the current state of the socket. These strings should not be modified.

> "`Listen`" indicates a passively opened socket that is waiting for a connection.

> "`SynSent`" and "`SynRcvd`" are connection phase intermediate states.

> "`Established`" states that the connection is complete.

> "`EstClosing`" "`FinWait1`" "`FinWait2`" "`CloseWait`" "`Closing`" "`LastAck`" "`TimeWait`" and "`CloseMSL`" are connection termination intermediate states.

> "`Closed`" indicates that the connection is completely closed.

> "`UDP Socket`" is always returned for UDP sockets because they are stateless.

> "`Not an active socket`" is a default value used when the socket is not recognized as UDP or TCP.

> "`BAD`" more than one bit set.

> ### Library

> TCP.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> sock_established, sock_dataready

> ### Example

>     char *p;
>     ...
>     #ifdef DEBUG
>     if ( p = sockstate( s ))
>         printf("Socket state is '%s'\n\r", p );
>     #endif DEBUG

> ## sock_tbleft

>     int sock_tbleft( void *s );

> ### Description

> Gets the number of bytes left in the transmit buffer. If you do not wish to block, you may first query how much space is available for writing by calling this function before generating data that must be transmitted. This removes the need for your application to also buffer data.

> ### Parameters

> #### s

> Pointer to a socket.

> ### Return value

> Number of bytes left in the transmit buffer.

> ### Library

> NET.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> sock_rbsize, sock_rbused, sock_rbleft, sock_tbsize, sock_tbused

>     if ( sock_tbleft( s ) > 10 ) {
>         /* we can send up to 10 bytes without blocking or overflowing */
>         ....
>     }

> ## sock_tbsize

>     int sock_tbsize( void *s );

> ### Description

> Determines the size of the transmit buffer for the specified socket.

> ### Parameters

> #### s

> Pointer to a socket.

> ### Return value

> The size of the transmit buffer.

> ### Library

> NET.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> sock_rbsize, sock_rbused, sock_rbleft, sock_tbleft, sock_tbused

> ## sock_tbused

>     int sock_tbused( void *s );

> ### Description

> Gets the number of bytes in use in the transmit buffer for the specified socket.

> ### Parameters

> #### s

> Pointer to a socket.

> ### Return value

> Number of bytes in use.

> ### Library

> NET.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> sock_rbsize, sock_rbused, sock_rbleft, sock_tbsize, sock_tbleft

> ## sock_tick

>     void sock_tick( void * s, int * optional_status_ptr );

> ### Description

> This macro calls `tcp_tick()` to quickly check incoming and outgoing data and to manage all the open sockets. If our particular socket, `s`, is either closed or made inoperative due to an error condition, `sock_tick()` sets the value of `*optional_status_ptr` (if the pointer is not `NULL`) to 1, then jumps to a local, user-supplied label, `sock_err`. If the socket connection is fine and the pointer is not `NULL` `*optional_status_ptr` is set to 0.

> ### Parameters

> #### s

> Pointer to a socket.

> #### optional_status_ptr

> Pointer to status word.

> ### Return value

> None.

> ### Library

> NET.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ## sock_wait_closed

>     void sock_wait_closed(void * s, int seconds, int (*fptr)(), int* status);

> ### Description

> This macro waits until a TCP connection is fully closed. Returns immediately for UDP sockets. On an error, the macro jumps to a local, user-supplied `sock_err` label. If `fptr` returns non-zero the macro returns with the status word set to the value of `fptr``s return value.

> This macro has been deprecated in Dynamic C version 7.20.

> ### Parameters

> #### s

> Pointer to a socket.

> #### seconds

> Number of seconds to wait before timing out. A value of zero indicates the macro should never time-out. A good value to use is `sock_delay`, a system variable set on configuration. Typically `sock_delay` is about 20 seconds, but can be set to something else in `main()`.

> #### fptr

> Function to call repeatedly while waiting. This is a user-supplied function.

> #### status

> Pointer to a status word.

> ### Return value

> None.

> ### Library

> NET.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ## sock_wait_established

>     void sock_wait_established(void* s, int seconds, int (*fptr)(), int* status);

> ### Description

> This macro waits until a connection is established for the specified TCP socket, or aborts if a time-out occurs. It returns immediately for UDP sockets. On an error, the macro jumps to the local, user-supplied `sock_err` label. If `fptr` returns non-zero, the macro returns.

> This macro has been deprecated in Dynamic C version 7.20.

> ### Parameters

> #### s

> Pointer to a socket.

> #### seconds

> Number of seconds to wait before timing out. A value of zero indicates the macro should never time-out. A good value to use is `sock_delay`, a system variable set on configuration. Typically `sock_delay` is about 20 seconds, but can be set to something else in `main()`.

> #### fptr

> Function to call repeatedly while waiting. This is a user-supplied function.

> #### status

> Pointer to a status word.

> ### Return value

> None.

> ### Library

> NET.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ## sock_wait_input

>     void sock_wait_input(void* s, int seconds, int (*fptr)(), int* status);

> ### Description

> Waits until input exists for functions such as `sock_read()` and `sock_gets()`. As described under `sock_mode()`, if in ASCII mode, `sock_wait_input` only returns when a complete string exists or the buffer is full. It returns immediately for UDP sockets.

> On an error, the macro jumps to a local, user-supplied `sock_err` label. If `fptr` returns non-zero, the macro returns.

> This macro has been deprecated in Dynamic C version 7.20.

> ### Parameters

> #### s

> Pointer to a socket.

> #### seconds

> Number of seconds to wait before timing out. A value of zero indicates the macro should never time-out. A good value to use is `sock_delay`, a system variable set on configuration. Typically `sock_delay` is about 20 seconds, but can be set to something else in `main()`.

> #### fptr

> Function to call repeatedly while waiting.

> #### status

> A pointer to the status word. If this parameter is `NULL`, no status number will be available, but the macro will otherwise function normally. Typically the pointer will point to a local signed integer that is used only for status. `status` may be tested to determine how the socket was ended. A value of 1 means a proper close while a -1 value indicates a reset or abort.

> ### Return value

> None.

> ### Library

> NET.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ## sock_write

>     int sock_write( tcp_Socket *s, byte *dp, int len );

> ### Description

> Writes up to `len` bytes from `dp` on socket `s`. This function busywaits until either the buffer is completely written or a socket error occurs. If `sock_yield()` has been called, the user-defined function that is passed to it will be called in a tight loop while `sock_write()` is busywaiting.

> For UDP, `sock_write()` will send one (or more) records. For TCP, the new data may be transmitted if enough data is in the buffer or sufficient time has expired or the user has explicitly used `sock_flushnext()` to indicate this data should be flushed immediately. In either case, there is no guarantee of acceptance at the other end.

> ### Parameters

> #### s

> Pointer to a socket

> #### dp

> Pointer to a buffer.

> #### len

> Maximum number of bytes to write to the buffer.

> ### Return value

> Number of bytes written or `-1` on an error.

> ### Library

> TCP.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> sock_read, sock_fastwrite, sock_fastread, sockerr, sock_flush, sock_flushnext

> ## sock_yield

>     int sock_yield( tcp_Socket *s, void (*fn)());

> ### Description

> This function, if called prior to one of the blocking functions, will cause `fn``,` the user-defined function that is passed in as the second parameter, to be called repeatedly while the blocking function is in a busywait state.

> ### Parameters

> #### s

> Pointer to a TCP socket.

> #### fn

> User-defined function.

> ### Return value

> `0`

> ### Library

> NET.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ## tcp_clearreserve

>     void tcp_clearreserve( word port );

> ### Description

> This function causes the `DCRTCP.LIB` stack to handle a socket connection to the specified port normally. This undoes the action taken by `tcp_reserveport()`.

> ### Parameters

> #### port

> Port to use.

> ### Return value

> None.

> ### Library

> TCP.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> tcp_reserveport

> ## tcp_config

>     void tcp_config(char *name, char *value);

> ### Description

> Sets TCP/IP stack parameters at runtime. It should not be called with open sockets.

> Note that there are specific (and safer) functions for modifying some of the common parameters.

> This function is deprecated. It is highly recommended that you do NOT use it, since it uses strings, hence taking up lots of root data storage.

> ### Parameters

> #### name

> Setting to be changed. The possible parameters are:

> - `MY_IP_ADDRESS`: host IP address (use `sethostid()` instead)
> - `MY_NETMASK`
> - `MY_GATEWAY`: host's default gateway
> - `MY_NAMESERVER`: host's default nameserver
> - `MY_HOSTNAME`
> - `MY_DOMAINNAME`: host's domain name (use `setdomainname()` instead)

> #### value

> The value to assign to `name`.

> ### Return value

> None.

> ### Library

> NET.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See Also

> tcp_open, sock_close, sock_abort, sethostid, setdomainname, sethostname

> ## tcp_extlisten

>     int tcp_extlisten( tcp_Socket *s, int iface, word lport, longword remip, word port, dataHandler_t datahandler, word reserved, long buffer, int buflen );

> ### Description

> This function tells the TCP/IP engine that an incoming session for a particular port will be accepted. The `buffer` and `buflen` parameters allow a user to supply a socket buffer, instead of using a socket buffer from the pool. `tcp_extlisten``()` is an extended version of `tcp_listen()`.

> ### Parameters

> #### s

> Pointer to the socket's data structure.

> #### iface

> Local interface on which to open the socket (not yet implemented, use `IF_DEFAULT` for now).

> #### lport

> Port to listen on.

> #### remip

> IP address to accept connections from or 0 for all.

> #### port

> Port to accept connections from or 0 for all.

> #### datahandler

> Function to call when data is received, `NULL` for placing data in the socket's receive buffer. Some details for implementation of this service have not been finalized, and it is recommended the user insert a value of `NULL` for the present time`.`

> #### reserved

> Set to 0 for now. This parameter is for compatibility and possible future use.

> #### buffer

> Address of user-supplied socket buffer in xmem. This is the return value of `xalloc()`. If `buffer` is 0, the socket buffer for this socket is pulled from the buffer pool defined by the macro `MAX_TCP_SOCKET_BUFFERS`.

> #### buflen

> Length of user-supplied socket buffer.

> ### Return value

> `0`: Failure.
> `1`: Success.

> ### Library

> TCP.LIB

> ### See also

> tcp_listen

> ## tcp_extopen

>     int tcp_extopen(tcp_Socket* s, int iface, word lport, longword remip, word port, dataHandler_t datahandler, long buffer, int buflen);

> ### Description

> Actively creates a session with another machine. The `buffer` and `buflen` parameters allow a user to supply a socket buffer, instead of using a socket buffer from the pool. `tcp_extopen``()` is an extended version of `tcp_open()`.

> #### s

> Pointer to socket's data structure.

> #### iface

> Local interface on which to open the socket (not yet implemented, use `IF_DEFAULT` for now).

> #### lport

> Our port, zero for the next one available in the range 1025-65536.

> #### remip

> IP address to connect to.

> #### port

> Port to connect to.

> #### datahandler

> Function to call when data is received, `NULL` for placing data in the socket's receive buffer. Some details for implementation of this service have not been finalized, and it is recommended the user insert a value of `NULL` for the present time`.`

> #### buffer

> Address of user-supplied socket buffer in xmem. This is the return value of `xalloc()`. If `buffer` is 0, the socket buffer for this socket is pulled from the buffer pool defined by the macro `MAX_TCP_SOCKET_BUFFERS`.

> #### buflen

> Length of user-supplied socket buffer.

> ### Return value

> `0` if open was not able resolve the remote computer's hardware address,
> `!0` otherwise.

> ### Library

> TCP.LIB

> ### See also

> tcp_open

> ## tcp_keepalive

>     int tcp_keepalive(tcp_Socket *s, long timeout);

> ### Description

> Enable or disable TCP keepalives on a specified socket. The socket must already be open. Keepalives will then be sent after `timeout` seconds of inactivity. It is highly recommended to keep `timeout` as long as possible, to reduce the load on the network. Ideally, it should be no shorter than 2 hours. After the timeout is sent, and `KEEPALIVE_WAITTIME` seconds pass, another keepalive will be sent, in case the first was lost. This will be retried `KEEPALIVE_NUMRETRYS` times. Both of these macros can be defined at the top of your program, overriding the defaults of 60 seconds, and 4 retries.

> Using keepalives is not a recommended procedure. Ideally, the application using the socket should send its own keepalives. `tcp_keepalive()` is provided because telnet and a few other network protocols do not have a method of sending keepalives at the application level.

> ### Parameters

> #### s

> Pointer to a socket.

> #### timeout

> Period of inactivity, in seconds, before sending a keepalive or 0 to turn off keepalives.

> ### Return value

> `0`: Success.
> `1`: Failure.

> ### Library

> TCP.LIB

> ### See also

> sock_fastread, sock_fastwrite, sock_write, sockerr

> ## tcp_listen

>     int tcp_listen( tcp_Socket *s, word lport, longword remip, word port, int (*signal_handler), word reserved );

> ### Description

> This function tells `DCRTCP.LIB` that an incoming session for a particular port will be accepted. After a call to `tcp_listen()`, the function `sock_established``()` (or the macro `sock_wait_established`) must be called to poll the connection until a session is fully established.

> It is possible for a connection to be opened, written to and closed between two calls to the function `sock_established()`. To handle this case, call `sock_bytesready()` to determine if there is data to be read from the buffer.

> Multiple calls to `tcp_listen()` to the same local port (`lport`) are acceptable and constitute the `DCRTCP.LIB` mechanism for supporting multiple incoming connections to the same local port. Each time another host attempts to open a session on that particular port, another one of the listens will be consumed until such time as all listens have become established sessions and subsequent remote host attempts will receive a reset.

> ### Parameters

> #### s

> Pointer to a socket.

> #### lport

> Port to listen on (the local port number).

> #### remip

> IP address of the remote host to accept connections from or 0 for all.

> #### port

> Port to accept connections from or 0 for all.

> #### signal_handler

> This function is called if the connection is either closed or reset. The parameter for `signal_handler` is the pointer to a function which will be called when the socket is either closed or reset. Some details for implementation of this service have not been finalized, and it is recommended the user insert a value of `NULL` for the present time`.`

> #### reserved

> Set to 0 for now. This parameter is for compatibility and possible future use.

> ### Return value

> `0`: Failure.
> `1`: Success.

> ### Library

> TCP.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> tcp_open

> ### Example using tcp_listen()

>     #define MY_IP_ADDRESS "10.10.6.100"
>     #define MY_NETMASK "255.255.255.0"
>     #memmap xmem
>     #use "dcrtcp.lib"

>     #define TELNET_PORT 23

>     static tcp_Socket *s;
>     char *userid;

>     telnets(int port) {
>         tcp_Socket telnetsock;
>         char buffer[ 512 ];
>         int status;
>         s = &telnetsock;
>         tcp_listen( s, port, 0L, 0, NULL, 0);

>         while (!sock_established(s) && sock_bytesready(s)==-1){
>            tcp_tick(NULL);
>         }
>         puts("Receiving incoming connection");
>         sock_mode( s, TCP_MODE_ASCII );
>         sock_puts( s, "Welcome to a sample telnet server.");
>         sock_puts( s, "Each line you type will be printed on this"\
>             "screen once you hit return.");
>         /* other guy closes connection except if we timeout ... */
>         do {
>            if (sock_bytesready(s) >= 0) {
>               sock_gets(s, buffer, sizeof(buffer)-1);
>               puts ( buffer);
>            }

>         } while (tcp_tick(s));
>     }
>     main() {
>         sock_init();
>         telnets( TELNET_PORT);
>         exit( 0 );
>     }

> ## tcp_open

>     int tcp_open( tcp_Socket *s, word lport, longword remip, word port, int (*signal_handler)());

> ### Description

> This function actively creates a session with another machine. After a call to `tcp_open()`, the function `sock_established``()` (or the macro `sock_wait_established`) must be called to poll the connection until a session is fully established.

> It is possible for a connection to be opened, written to and closed between two calls to the function `sock_established()`. To handle this case, call `sock_bytesready()` to determine if there is data to be read from the buffer.

> ### Parameters

> #### s

> Pointer to a socket structure.

> #### lport

> Our local port. Use zero for the next available port in the range 1025-65536. A few applications will require you to use a particular local port number, but most network applications let you use almost any port with a certain set of restrictions. For example, `FINGER` or `TELNET` clients can use any local port value, so pass the value of zero for `lport` and let `DCRTCP.LIB` pick one for you.

> #### remip

> IP address to connect to.

> #### port

> Port to connect to.

> #### signal_handler

> This function is called if the connection is either closed or reset. The parameter for `signal_handler` is the pointer to a function which will be called when the socket is either closed or reset. Some details for implementation of this service have not been finalized, and it is recommended the user insert a value of `NULL` for the present time`.`

> ### Return value

> `0`: Unable to resolve the remote computer's hardware address;
> `!0` otherwise.

> ### Library

> TCP.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> tcp_listen

> ### Example Using tcp_open()

>     #define MY_IP_ADDRESS "10.10.6.100"
>     #define MY_NETMASK "255.255.255.0"
>     #memmap xmem

>     #use "dcrtcp.lib"

>     #define ADDRESS "10.10.6.19"
>     #define PORT "200"

>     main() {
>         word status;
>         word port;
>         longword host;
>         tcp_Socket tsock;

>         sock_init();

>         if (!(host = resolve(ADDRESS))) {
>             puts("Could not resolve host");
>             exit( 3 );
>         }
>         port = atoi( PORT );
>         printf("Attempting to open '%s' on port %u\n\r", ADDRESS, port );
>         if ( !tcp_open( &tsock, 0, host, port , NULL )) {
>             puts("Unable to open TCP session");
>             exit( 3 );
>         }

>         printf("Waiting a maximum of %u seconds for connection"\
>             " to be established\n\r", sock_delay );

>         while (!sock_established(&tsock) && sock_bytesready(&tsock)==-1){
>            tcp_tick(NULL);
>         }
>         puts("Socket is established");
>         sock_close( &tsock );
>         exit( 0 );
>     }

> ## tcp_reserveport

>     void tcp_reserveport( word port );

> ### Description

> This function allows a connection to be established even if there is not yet a socket available. This is done by setting a parameter in the TCP header during the connection setup phase that indicates 0 bytes of data can be received at the present time. The requesting end of the connection will wait until the TCP header parameter indicates that data will be accepted.

> The 2MSL waiting period for closing a socket is avoided by using this function.

> The penalty of slower connection times on a controller that is processing a large number of connections is offset by allowing the program to have less sockets and consequently less RAM usage.

> ### Parameters

> #### port

> Port to use.

> ### Return value

> None.

> ### Library

> TCP.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> tcp_clearreserve

> ## tcp_tick

>     int tcp_tick( void *s );

> ### Description

> This function is a single kernel routine designed to quickly process packets and return as soon as possible. `tcp_tick()` performs processing on all sockets upon each invocation: checking for new packets, processing those packets, and performing retransmissions on lost data. On most other computer systems and other kernels, performing these required operations in the background is often done by a task switch. `DCRTCP.LIB` does not use a tasker for its basic operation, although it can adopt one for the user-level services.

> Although you may ignore the returned value of `tcp_tick()`, it is the easiest method to determine the status of the given socket.

> ### Parameters

> #### s

> Pointer to a socket. If `NULL`, the returned value is always `0`.

> ### Return value

> `0`: Connection reset or closed by other host or `NULL` was passed in.
> `!0`: Connection is fine.

> ### Library

> TCP.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> tcp_open, sock_close, sock_abort, sock_tick

> ## udp_bypass_arp

>     void udp_bypass_arp(udp_Socket *s, eth_address * eth);

> ### Description

> Override the normal Address Resolution Protocol for this UDP socket. This is sometimes necessary for special purposes such as if the ethernet address is to remain fixed, or if the ethernet address is not obtainable using ARP. The great majority of applications should not use this function.

> If ARP bypass is in effect for a UDP socket, then `udp_sendto()` will never return the -2 return code.

> ### Parameters

> #### s

> UDP socket

> #### eth

> Pointer to override address. If `NULL`, then resume normal operation i.e. use ARP to resolve ethernet addresses. Note that the specified ethernet address must be in static storage, since only the pointer is stored.

> ### Library

> UDP.LIB

> ### See Also

> udp_sendto, udp_waitsend, sock_resolved

> ## udp_close

>     void udp_close(udp_Socket *ds);

> ### Description

> This function closes a UDP connection.

> ### Parameters

> #### ds

> Pointer to socket's data structure.

> ### Library

> UDP.LIB

> ## udp_extopen

>     int udp_extopen( udp_Socket *s, int iface, word lport, longword remip, word port, dataHandler_t datahandler, long buffer, int buflen );

> ### Description

> This function is an extended version of `udp_open()`. It opens a socket on a given network interface (`iface`) on a given local port (`lport`). The `iface` parameter is not currently supported and should be `IF_DEFAULT`. The remote end of the connection is specified by `remip` and `port`. The following table explains the possible combinations and what they mean.

> REMIP | Effect of REMIP value
> 0 | The connection completes when the first datagram is received, supplying both the remote IP address and the remote port number. Only datagrams received from that IP/port address will be accepted.
> -1 | All remote hosts can send datagrams to the socket. All outgoing datagrams will be sent to the broadcast address on the specified port.
> >0 | If the remote IP address is a valid IP address and the remote port is 0, the connection will complete when the first datagram is received, supplying the remote port number. If the remote IP address and the remote port are both specified when the function is called, the connection is complete at that point.

> The `buffer` and `buflen` parameters allow a user to supply a socket buffer, instead of using a socket buffer from the pool.

> If `remip` is non-zero, then the process of resolving the correct destination hardware address is started. Datagrams cannot be sent until `sock_resolved()` returns TRUE. If you attempt to send datagrams before this, then the datagrams may not get sent. The exception to this is if `remip` is -1 (broadcast) in which case datagrams may be sent immediately after calling this function.

> ### Parameters

> #### s

> Pointer to socket's data structure.

> #### iface

> Local interface on which to open the socket (not yet implemented--use `IF_DEFAULT` for now).

> #### lport

> Local port.

> #### remip

> Acceptable remote IP, or 0 for all.

> #### port

> Acceptable remote port, or 0 for all.

> #### datahandler

> Function to call when data is received, `NULL` for placing data in the socket's receive buffer.

> #### buffer

> Address of user-supplied socket buffer in xmem. If `buffer` is 0, the socket buffer for this socket is pulled from the buffer pool defined by the macro `MAX_UDP_SOCKET_BUFFERS`.

> #### buflen

> Length of user-supplied socket buffer.

> ### Return value:

> `!0`: Success.
> `0`: Failure; error opening socket, e.g., a buffer could not be allocated.

> ### Library

> UDP.LIB

> ### See Also

> udp_open, sock_resolved

> ## udp_open

>     int udp_open( udp_Socket *s, word lport, longword remip, word port, dataHandler_t datahandler);

> ### Description

> This function opens a UDP socket on the given local port (`lport`). The remote end of the connection is specified by `remip` and `port`. The following table explains the possible combinations and what they mean.

> Table 1.
> REMIP | Effect of REMIP value
> 0 | The connection completes when the first datagram is received, supplying both the remote IP address and the remote port number. Only datagrams received from that IP/port address will be accepted.
> -1 | All remote hosts can send datagrams to the socket. All outgoing datagrams will be sent to the broadcast address on the specified port.
> >0 | If the remote IP address is a valid IP address and the remote port is 0, the connection will complete when the first datagram is received, supplying the remote port number. If the remote IP address and the remote port are both specified when the function is called, the connection is complete at that point.

> If the remote host is set to a particular address, either host may initiate traffic. Multiple calls to `udp_open()` with `remip` set to zero is a useful way of accepting multiple incoming sessions.

> Although multiple calls to `udp_open()` may normally be made with the same `lport` number, only one `udp_open()` should be made on a particular `lport` if the `remip` is set to -1. Essentially, the broadcast and nonbroadcast protocols cannot co-exist.

> Be sure that you have allocated enough UDP socket buffers with `MAX_UDP_SOCKET_BUFFERS`. Note that this macro defaults to 0, so any usage of `udp_open()` requires a definition of `MAX_UDP_SOCKET_BUFFERS` in your program.

> ### Parameters

> #### s

> Pointer to a UDP socket.

> #### lport

> Local port

> #### remip

> Acceptable remote IP, 0 to connect on first datagram, or -1 for broadcast.

> #### port

> Acceptable remote port, or 0 to connect on first datagram.

> #### datahandler

> Function to call when data is received. `NULL` for placing data in the socket's receive buffer.

> ### Return value

> `0`: Failure (e.g., a buffer could not be allocated).
> `!0`: Success.

> ### Library

> UDP.LIB (Prior to DC 7.05, this was DCRTCP.LIB)

> ### See also

> udp_extopen

> ## udp_peek

>     int udp_peek(udp_Socket* s, _udp_datagram_info * udi);

> ### Description

> Look into the UDP socket receive buffer to see if there is a datagram ready to be read using `udp_recvfrom()`. This function does not remove the datagram from the buffer, but it allows the application to determine the full details about the next datagram, including whether the datagram was broadcast.

> The returned data is put in `*udi`. `udi` must point to a valid data structure, or be `NULL`. The data structure is:

>     typedef struct {
>        longword remip;    // Remote host IP address
>        word     remport;  // Remote host port number
>        int      len;      // Length of datagram
>        byte     flags;    // Flags
>        byte     iface;    // Interface number
>     } _udp_datagram_info;

> The `flags` field may have one of the following values:

>     UDI_ICMP_ERROR     This is an ICMP error entry.
>     UDI_TOS_MASK       Type-of-service bit mask.
>     UDI_BROADCAST_LL   Received on broadcast link-layer address.
>     UDI_BROADCAST_IP   Received on broadcast network (IP) address.

> ### Parameters

> #### s

> UDP socket to check

> #### udi

> Where to store the returned information.

> ### Return Value

> `1`: A normal datagram is in the receive buffer.
> `0`: No datagram waiting.

> `-3`: An ICMP error message is in the receive buffer - this will only be returned if `udi` parameter is not `NULL`.

> ### Library

> UDP.LIB

> ### See Also

> udp_recvfrom

> ## udp_recv

>     int udp_recv(udp_Socket* s, char* buffer, int len)

> ### Description

> Receives a single UDP datagram on a UDP socket. If the buffer is not large enough for the datagram, the datagram is truncated, and the remainder discarded.

> ### Parameters

> #### s

> Pointer to socket's data structure.

> #### buffer

> Buffer where the UDP datagram will be stored.

> #### len

> Maximum length of the buffer.

> ### Return value

> `` ≥`0`: Number of bytes received.
> `-1`: No datagram waiting.
> `<-1`: Error.

> ### Library

> UDP.LIB

> ### See also

> udp_recvfrom, udp_send, udp_sendto, udp_open

> ## udp_recvfrom

>     int udp_recvfrom(udp_Socket* s, char* buffer, int len, longword* remip, word* remport);

> ### Description

> Receive a single UDP datagram on a UDP socket. remip and remport should be pointers to the locations where the remote IP address and remote port from which the datagram originated are placed. If the buffer is not large enough for the datagram, then the datagram will be truncated, with the remainder being discarded.

> If and only if the `UDP_MODE_ICMP` or `UDP_MODE_DICMP` modes are set for this socket, then a return code of -3 indicates that an ICMP error message is being returned in the buffer instead of a normal datagram. In this case, `buffer` will contain fixed data in the form of a structure of type `_udp_icmp_message`. The definition of this structure is:

>     typedef struct {
>     word myport;         // Originating port on this host
>     byte icmp_type;      // One of the ICMPTYPE_* values
>     byte icmp_code;      // The corresponding ICMP code
>     } _udp_icmp_message;

> Please see `sock_mode` for more information about the modes `UDP_MODE_ICMP` and `UDP_MODE_DICMP`.

> ### Parameters

> #### s

> Pointer to socket's data structure.

> #### buffer

> Buffer where the UDP datagram will be stored.

> #### len

> Maximum length of the buffer.

> #### remip

> IP address of the remote host of the received datagram.

> #### remport

> Port number of the remote host of the received datagram.

> ### Return value

> ≥`0`: Number of bytes received.
> `-1`: No datagram waiting.
> `-2`: Error - not a UDP socket.
> `-3`: The returned buffer contains an ICMP error which was queued previously.

> ### Library

> UDP.LIB

> ### See also

> udp_recv, udp_send, udp_sendto, udp_open, udp_peek

> ## udp_send

>     int udp_send(udp_Socket* s, char* buffer, int len);

> ### Description

> Sends a single UDP datagram on a UDP socket. It will not work for a socket for which the `remip` parameter to `udp_open()` was 0, unless a datagram has first been received on the socket. If the `remip` parameter to `udp_open()` was -1, the datagram will be send to the broadcast address.

> ### Parameters

> #### s

> Pointer to socket's data structure.

> #### buffer

> Buffer that contains the UDP datagram

> #### len

> Length of the UDP datagram.

> ### Return value

> ≥`0`: Number of bytes sent.
> `-1`: Failure.

> ### Library

> UDP.LIB

> ### See also

> udp_sendto, udp_recv, udp_recvfrom, udp_open

> ## udp_sendto

>     int udp_sendto(udp_Socket* s, char* buffer, int len, longword remip, word remport);

> ### Description

> Sends a single UDP datagram on a UDP socket. It will send the datagram to the IP address and port specified by `remip` and `remport`. Note that this function can be used on a socket that has been "connected" to a different remote host and port.

> ### Parameters

> #### s

> Pointer to socket's data structure.

> #### buffer

> Buffer that contains the UDP datagram.

> #### len

> Length of the UDP datagram.

> #### remip

> IP address of the remote host.

> #### remport

> Port number of the remote host.

> ### Return value

> ≥`0`: Success, number of bytes sent.
> `-1`: Failure.
> `-2`: Failed because hardware address not resolved.

> ### Library

> UDP.LIB

> ### See also

> udp_send, udp_recv, udp_recvfrom, udp_open

> ## udp_waitopen

>     int udp_waitopen( udp_Socket *s, int iface, word lport, longword remip, word port, dataHandler_t datahandler, long buffer, int buflen, longword millisecs );

> ### Description

> This function is identical to `udp_extopen()`, except that it waits a specified amount of time for the hardware address of the destination to be resolved.

> While waiting, this function calls `tcp_tick()`.

> ### Parameters

> #### s

> Pointer to socket.

> #### iface

> Local interface on which to open the socket (not yet implemented so use `IF_DEFAULT` for now).

> #### lport

> Local port.

> #### remip

> Acceptable remote ip, or 0 for all.

> #### port

> Acceptable remote port, or 0 for all.

> #### datahandler

> Function to call when data is received, `NULL` for placing data in the sockets receive buffer.

> #### buffer

> Address of user-supplied socket buffer in xmem, 0 to use a buffer from the socket buffer pool.

> #### buflen

> Length of user-supplied socket buffer.

> #### millisecs

> Maximum milliseconds to wait for the hardware address to be resolved.

> ### Return Value

> `>0`: Successfully opened socket.
> `0`: Timed out without resolving address.
> `-1`: Error opening socket (e.g., buffer could not be allocated).

> ### Library

> UDP.LIB

> ### See Also

> udp_extopen, sock_resolved

> ## udp_waitsend

>     int udp_waitsend(udp_Socket* s, char* buffer, int len, longword remip, word remport, word millisecs);

> ### Description

> This is identical to `udp_sendto()`, except that it will block for up to the specified amount of time waiting for the hardware address to be resolved. Normally, you should not have to specify more than 100ms for the time out. If it takes longer than this, the destination is probably unavailable.

> ### Parameters

> #### s

> UDP socket on which to send the datagram.

> #### buffer

> Buffer that contains the UDP datagram.

> #### len

> Length of the UDP datagram.

> #### remip

> IP address of the remote host.

> #### remport

> Port number of the remote host.

> #### millisecs

> Number of milliseconds to wait for hardware address resolution. Reasonable values are between 50 and 750 milliseconds.

> ### Return Value

> ≥`0`: Number of bytes sent.
> `-1`: Failure (invalid UDP socket etc.).
> `-2`: Failure (timed out, no datagram sent).

> ### Library

> UDP.LIB

> ### See Also

> udp_sendto, udp_recvfrom, udp_bypass_arp

> ### 2.9 Macros

> #### DISABLE_DNS

> This macro disables DNS lookup. This prevents a UDP socket for DNS from being allocated, thus saving memory. Users may still call `resolve()` with an IP address.

> #### MAX_SOCKETS

> This macro defines the number of sockets that will be allocated, not including the socket for DNS lookups. It defaults to 4. If libraries such as `HTTP.LIB` or `FTP_SERVER.LIB` are used, you must provide enough sockets in `MAX_SOCKETS` for them also. This macro has been replaced by `MAX_TCP_SOCKET_BUFFERS` and `MAX_UDP_SOCKET_BUFFERS`.

> #### MAX_SOCKET_LOCKS

> For µC/OS-II support. This macro defines the number of socket locks to allocate. It defaults to `MAX_TCP_SOCKET_BUFFERS` + `MAX_UDP_SOCKET_BUFFERS`.

> This macro is necessary because we can no longer calculate the number of socket locks needed based on the number of socket buffers, now that the user can manage their own socket buffers.

> #### MAX_TCP_SOCKET_BUFFERS

> Starting with Dynamic C version 7.05, this macro determines the maximum number of TCP sockets with preallocated buffers. If `MAX_SOCKETS` is defined, then `MAX_TCP_SOCKET_BUFFERS` will be assigned the value of `MAX_SOCKETS` for backwards compatibility. If neither macro is defined, `MAX_TCP_SOCKET_BUFFERS` defaults to 4.

> #### MAX_UDP_SOCKET_BUFFERS

> Starting with Dynamic C version 7.05, this macro determines the maximum number of UDP sockets with preallocated buffers. It defaults to 0.

> #### MY_DOMAIN

> This macro is the initial value for the domain portion of the controller's address. At runtime, it can be overwritten by `tcp_config()` and `setdomainname()`.

> #### MY_GATEWAY

> This macro gives the default value for the controllers default gateway. At runtime, it can be overwritten by `tcp_config()`.

> #### MY_IP_ADDRESS

> This macro is the default IP address for the controller. At runtime, it can be overwritten by `tcp_config()` and `sethostid()`.

> #### MY_NAMESERVER

> This macro is the default value for the primary name server. At runtime, it can be overwritten by `tcp_config()`.

> #### MY_NETMASK

> This macro is the default netmask for the controller. At runtime, it can be overwritten by `tcp_config()`.

> #### SOCK_BUF_SIZE

> This macro determines the size of the socket buffers. A TCP socket will have two buffers of size `SOCK_BUF_SIZE`/2 for send and receive. A UDP socket will have a single socket of size `SOCK_BUF_SIZE`. Both types of sockets take the same total amount of buffer space. This macro has been replaced by `TCP_BUF_SIZE` and `UDP_BUF_SIZE`.

> #### TCP_BUF_SIZE

> Starting with Dynamic C 7.05, TCP and UDP socket buffers are sized separately. `TCP_BUF_SIZE` defines the buffer sizes for TCP sockets. It defaults to 4096 bytes. Backwards compatibility exists with earlier version of Dynamic C: if `SOCK_BUF_SIZE` is defined, `TCP_BUF_SIZE` is assigned the value of `SOCK_BUF_SIZE`. If `SOCK_BUF_SIZE` is not defined, but `tcp_MaxBufSize` is, then `TCP_BUF_SIZE` will be assigned the value of `tcp_MaxBufSize`*2.

> #### tcp_MaxBufSize

> This use of this macro is deprecated in Dynamic C version 6.57 and higher; it has been replaced by `SOCK_BUF_SIZE`.

> In Dynamic C versions 6.56 and earlier, `tcp_MaxBufSize` determines the size of the input and output buffers for TCP and UDP sockets. The `sizeof(tcp_Socket)` will be about 200 bytes more than double `tcp_MaxBufSize`. The optimum value for local Ethernet connections is greater than the Maximum Segment Size (MSS). The MSS is 1460 bytes. You may want to lower `tcp_MaxBufSize`, which defaults to 2048 bytes, to reduce RAM usage. It can be reduced to as little as 600 bytes.

> `tcp_MaxBufSize` will work slightly differently in Dynamic C versions 6.57 and higher. In these later versions the buffer for the UDP socket will be `tcp_MaxBufSize*2`, which is twice as large as before.

> #### UDP_BUF_SIZE

> Starting with Dynamic C 7.05, TCP and UDP socket buffers are sized separately. `UDP_BUF_SIZE` defines the buffer sizes for UDP sockets. It defaults to 4096 bytes. Backwards compatibility exists with earlier version of Dynamic C: if `SOCK_BUF_SIZE` is defined, `UDP_BUF_SIZE` is assigned the value of `SOCK_BUF_SIZE`. If `SOCK_BUF_SIZE` is not defined, but `tcp_MaxBufSize` is, then `UDP_BUF_SIZE` will be assigned the value of `tcp_MaxBufSize`*2.

Z-World http://www.zworld.com Voice: 530.757.3737 Fax: 530.757.3792 or 530.753.5141 sales@zworld.com