Overview

group index

Secure Sockets Library provides APIs to create software that can send and/or receive data over the network using sockets. This library supports both secure and non-secure sockets, and abstracts the complexity involved in directly using network stack and security stack APIs. This library supports both IPv4 and IPv6 addressing modes for UDP and TCP sockets.

Features and Functionality

Features supported:

  • Supports non-secure TCP and UDP sockets

  • Secure TCP (TLS) socket communication using mbed TLS library

  • Supports both IPv4 and IPv6 addressing. Only link-local IPv6 addressing is supported

  • Supports UDP multicast and broadcast for both IPv4 and IPv6.

  • Thread-safe APIs

  • Provides APIs for both Client and Server mode operations

  • Supports both Synchronous and Asynchronous APIs for receiving data on socket

  • Asynchronous Server APIs for accepting client connections

  • Provides a socket-option API to configure send/receive timeout, callback for asynchronous mode, TCP keepalive parameters, certificate/key, and TLS extensions

Supported Platforms

This library and its features are supported on the following PSoC 6 MCU platforms:

Integration Notes

  • The Secure Sockets Library configures the default send and receive timeout values to 10 seconds for a newly created socket. The default timeout values can be changed by modifying the DEFAULT_SEND_TIMEOUT_IN_MSEC and DEFAULT_RECV_TIMEOUT_IN_MSEC macros in the cy_secure_sockets.h file. To configure the timeout values specific to a socket, use the cy_socket_setsockopt API function. To change the send timeout, use the CY_SOCKET_SO_SNDTIMEO socket option; similarly, for receive timeout, use the CY_SOCKET_SO_RCVTIMEO socket option. Adjust the default timeout values based on the network speed or use case.

  • The Secure Sockets Library has been designed to support different flavors of the TCP/IP stack or security stack. Currently, lwIP and mbed TLS are the default network and security stacks respectively. Therefore, any application that uses the Secure Sockets Library must ensure that the following COMPONENTS are defined in the code example project’s makefile - LWIP and MBEDTLS.

  • Applications using the Secure Sockets Library must include only the cy_secure_sockets.h file for non-secure connections. For secure connections, the application must include both cy_secure_sockets.h and cy_tls.h header files.

  • The default stack size of the Secure Sockets Library is 6 KB(6*1024). To customize the stack size, the application must perform the following:

    1. Add SECURE_SOCKETS_THREAD_STACKSIZE macro to the DEFINES in the code example’s Makefile with the required stack size. The Makefile entry would look like as follows:

      DEFINES+=SECURE_SOCKETS_THREAD_STACKSIZE=8*1024
      

  • The Secure Sockets Library disables all the debug log messages by default. To enable log messages, the application must perform the following:

    1. Add ENABLE_SECURE_SOCKETS_LOGS macro to the DEFINES in the code example’s Makefile. The Makefile entry would look like as follows:

      DEFINES+=ENABLE_SECURE_SOCKETS_LOGS
      

    2. Call the cy_log_init() function provided by the cy-log module. cy-log is part of the connectivity-utilities library. See connectivity-utilities library API documentation for cy-log details.

  • To ease the integration of Wi-Fi connectivity components to code examples, this Secure Socket Library has been bundled into the Wi-Fi Middleware Core Library v2.0.0.

  • The default mbed TLS configuration provided by the Wi-Fi Middleware Core Library disables the validity period verification of the certificates. To perform this verification, enable MBEDTLS_HAVE_TIME_DATE in the mbedtls_user_config.h file. Ensure that the system time is set prior to the cy_socket_connect() function call. To set the system time, get the time from the NTP server and set the system’s RTC time using cyhal_rtc_init(), cyhal_rtc_write() and cy_set_rtc_instance() functions. See the Time Support Details for reference. See the Code Snippet 12: Get the current time from the NTP server - Send an NTP request packet to the NTP server, and receive an NTP reply packet. to get the time from NTP server.

Code Snippets

Code Snippet 1: Create TCP Socket

This code snippet demonstrates how to initialize and create a TCP socket using an IPv4 address domain.

void snippet_create_socket()
{
    cy_rslt_t result;
    (void)(result);

    /* TCP socket handle. */
    cy_socket_t socket_handle;

    /* Initialize the Secure Sockets Library. */
    result = cy_socket_init();

    /* Create a TCP socket. */
    result = cy_socket_create(CY_SOCKET_DOMAIN_AF_INET, CY_SOCKET_TYPE_STREAM, CY_SOCKET_IPPROTO_TCP, &socket_handle);
}

Code Snippet 2: Create Secure TCP Socket

This code snippet demonstrates how to initialize and create a TCP socket using an IPv4 address domain, and set the TLS credentials to be used for securing the socket communication.

void snippet_create_secure_socket()
{
    cy_rslt_t result;
    (void)(result);

    /* TCP socket handle */
    cy_socket_t socket_handle;

    /* Variable to store the TLS identity (certificate and private key).*/
    void *tls_identity;

    /* TLS authentication mode. Setting the CY_SOCKET_TLS_VERIFY_REQUIRED authentication mode
    requires a successful TLS handshake in order to establish a secure socket communication.*/
    cy_socket_tls_auth_mode_t tls_auth_mode = CY_SOCKET_TLS_VERIFY_REQUIRED;

    /* Initialize with your TLS certificate. Must include the PEM header and footer.*/
    static const char tls_cert[] = "-----REPLACE WITH TLS CERTIFICATE FILE-----\n";

    /* Initialize with private key corresponding to the TLS certificate used.
     * Must include the PEM header and footer. */
    static const char private_key[] = "-----REPLACE WITH PRIVATE KEY-----\n";

    /* TLS certificate length and private key length. */
    const uint32_t cert_len = strlen( tls_cert );
    const uint32_t pkey_len = strlen( private_key );

    /* Initialize the Secure Sockets Library. */
    result = cy_socket_init();

    /* Create a new secure TCP socket. */
    result = cy_socket_create(CY_SOCKET_DOMAIN_AF_INET, CY_SOCKET_TYPE_STREAM, CY_SOCKET_IPPROTO_TLS, &socket_handle);

    /* Create a TCP client identity using the SSL certificate and private key. */
    result = cy_tls_create_identity(tls_cert, cert_len, private_key, pkey_len, &tls_identity);

    /* Set the TCP socket to use the TLS identity. */
    result = cy_socket_setsockopt(socket_handle, CY_SOCKET_SOL_TLS, CY_SOCKET_SO_TLS_IDENTITY, tls_identity, sizeof(tls_identity));

    /* Set the TLS authentication mode. */
    result = cy_socket_setsockopt(socket_handle, CY_SOCKET_SOL_TLS, CY_SOCKET_SO_TLS_AUTH_MODE, &tls_auth_mode, sizeof(cy_socket_tls_auth_mode_t));
}

Code Snippet 3: TCP Client Connect

This code snippet demonstrates how to create a TCP client using an IPv4 address domain, and connect to a TCP server. After connection is established with the TCP server, the client sends a message to the TCP server and waits for a message from the server.

 
#define MAKE_IPV4_ADDRESS(a, b, c, d)     ((((uint32_t) d) << 24) | \
                                          (((uint32_t)  c) << 16) | \
                                          (((uint32_t)  b) << 8) |\
                                          ((uint32_t)   a))

/* Change the server IP address and port number to match the TCP server address to which the 
 * client wants to connect to.
 */
#define TCP_SERVER_IP_ADDRESS                     MAKE_IPV4_ADDRESS(192, 168, 18, 9)
#define TCP_SERVER_PORT                           (50007)

/* Buffer size to store the incoming messages from the server. */
#define MAX_TCP_RECV_BUFFER_SIZE                  (20)

#define RTOS_TASK_TICKS_TO_WAIT                   (1000)

/* Socket disconnect timeout. */
#define SOCKET_DISCONNECT_TIMEOUT                 (0)

/* TCP socket handle. */
cy_socket_t client_handle;

/* Flag to indicate that the message is received from the TCP server. */
bool received_msg_from_server;

/* Function to handle the incoming message from the TCP server. */
cy_rslt_t tcp_client_recv_handler(cy_socket_t client_handle, void *arg)
{
    cy_rslt_t result ;

    /* Variable to store the number of bytes received. */
    uint32_t bytes_received = 0;

    /* Buffer to hold the received data from the TCP server. */
    char rx_buffer[MAX_TCP_RECV_BUFFER_SIZE];

    /* Receive incoming message from the TCP server. */
    result = cy_socket_recv(client_handle, rx_buffer, MAX_TCP_RECV_BUFFER_SIZE,
                            CY_SOCKET_FLAGS_NONE, &bytes_received);

    /* Set the flag to indicate that a message is received from the TCP server. */
    received_msg_from_server = true;

    return result;
}

void snippet_tcp_client()
{
    cy_rslt_t result;
    (void)(result);

    /* Variable to store the number of bytes sent to the TCP server. */
    uint32_t bytes_sent = 0;

    /* IP address and TCP port number of the TCP server. */
    cy_socket_sockaddr_t tcp_server_addr = {
        .ip_address.ip.v4 = TCP_SERVER_IP_ADDRESS,
        .ip_address.version = CY_SOCKET_IP_VER_V4,
        .port = TCP_SERVER_PORT
    };

    /* Buffer to hold the data to be sent to the client. */
    char tx_buffer[] = "Message to TCP server";

    /* Initialize the Secure Sockets Library. */
    result = cy_socket_init();

    /* Create a TCP socket. If you need a secure connection, create a secure socket
     * as demonstrated by the snippet_create_secure_socket function. 
     */
    result = cy_socket_create(CY_SOCKET_DOMAIN_AF_INET, CY_SOCKET_TYPE_STREAM, CY_SOCKET_IPPROTO_TCP, &client_handle);

    /* Variable used to set the socket options. */
    cy_socket_opt_callback_t tcp_recv_option = {
        .callback = tcp_client_recv_handler,
        .arg = NULL
    };

    /* Register the callback function to handle the messages received from the TCP server. */
    result = cy_socket_setsockopt(client_handle, CY_SOCKET_SOL_SOCKET,
                                  CY_SOCKET_SO_RECEIVE_CALLBACK,
                                  &tcp_recv_option, sizeof(cy_socket_opt_callback_t));

    /* Connect the created socket to the TCP server. */
    result = cy_socket_connect(client_handle, &tcp_server_addr, sizeof(cy_socket_sockaddr_t));

    /* Send a message to the TCP server. */
    result = cy_socket_send(client_handle, tx_buffer, strlen(tx_buffer), CY_SOCKET_FLAGS_NONE, &bytes_sent);

    /* Wait for a response message from the TCP server.*/
    for(;;)
    {
        if(received_msg_from_server)
        {
            break;
        }

        vTaskDelay(RTOS_TASK_TICKS_TO_WAIT);
    }
}

Code Snippet 4: TCP Server - Listening for client connection

This code snippet demonstrates how to create a TCP server using an IPv4 address domain and accept a TCP client connection. The server implementation in this snippet waits for a client connection and a message from the connected client. Upon receiving a message from the client, it sends a response message back to the client.

#define MAKE_IPV4_ADDRESS(a, b, c, d)     ((((uint32_t) d) << 24) | \
                                          (((uint32_t)  c) << 16) | \
                                          (((uint32_t)  b) << 8) |\
                                          ((uint32_t)   a))

/* Change the server IP address and port to match the TCP server address. 
 */
#define TCP_SERVER_IP_ADDRESS                     MAKE_IPV4_ADDRESS(192, 168, 18, 9)
#define TCP_SERVER_PORT                           (50007)

/* Maximum number of incoming connections. */
#define TCP_SERVER_MAX_PENDING_CONNECTIONS        (3)

/* Buffer size to store the incoming messages from the client. */
#define MAX_TCP_RECV_BUFFER_SIZE                  (20)

#define RTOS_TASK_TICKS_TO_WAIT                   (1000)

/* Socket disconnect timeout. */
#define SOCKET_DISCONNECT_TIMEOUT                 (0)

/* TCP socket handles. */
cy_socket_t server_handle, client_handle;

/* Flag to indicate when to send the data to the TCP client. */
bool send_msg_to_client;

/* Incoming TCP client connection handler. */
cy_rslt_t tcp_connection_handler(cy_socket_t socket_handle, void *arg)
{
    cy_rslt_t result;

    /* Client socket address. */
    cy_socket_sockaddr_t client_addr;

    /* Size of the client socket address. */
    uint32_t client_addr_len;

    /* Accept a new incoming connection from a TCP client.*/
    result = cy_socket_accept(socket_handle, &client_addr, &client_addr_len,
                              &client_handle);

    return result;
}

/* Function to handle the incoming  message from the TCP client. */
cy_rslt_t tcp_server_recv_handler(cy_socket_t socket_handle, void *arg)
{
    cy_rslt_t result ;

    /* Variable to store the number of bytes received. */
    uint32_t bytes_received = 0;

    /* Buffer to hold the received data from the TCP client. */
    char rx_buffer[MAX_TCP_RECV_BUFFER_SIZE];

    /* Receive the incoming message from the TCP server. */
    result = cy_socket_recv(socket_handle, rx_buffer, MAX_TCP_RECV_BUFFER_SIZE,
                            CY_SOCKET_FLAGS_NONE, &bytes_received);

    /* Set the flag to send message to the TCP client.*/
    send_msg_to_client = true;

    return result;
}

void snippet_tcp_server()
{
    cy_rslt_t result;
    (void)(result);

    /* Variable to store the number of bytes sent to the TCP client. */
    uint32_t bytes_sent = 0;

    /* IP address and TCP port number of the TCP server. */
    cy_socket_sockaddr_t tcp_server_addr = {
        .ip_address.ip.v4 = TCP_SERVER_IP_ADDRESS,
        .ip_address.version = CY_SOCKET_IP_VER_V4,
        .port = TCP_SERVER_PORT
    };

    /* Buffer to hold the data to be sent to the client. */
    char tx_buffer[] = "Message to TCP client";

    /* Initialize the Secure Sockets Library. */
    result = cy_socket_init();

    /* Create a TCP socket. If you need a secure connection, create a secure socket
     * as demonstrated by the snippet_create_secure_socket function.
     */
    result = cy_socket_create(CY_SOCKET_DOMAIN_AF_INET, CY_SOCKET_TYPE_STREAM, CY_SOCKET_IPPROTO_TCP, &server_handle);

    /* Variable used to set the socket options. */
    cy_socket_opt_callback_t tcp_connection_option = {
        .callback = tcp_connection_handler,
        .arg = NULL
    };

    /* Register the callback function to handle the connection request from a TCP client. */
    result = cy_socket_setsockopt(server_handle, CY_SOCKET_SOL_SOCKET,
                                CY_SOCKET_SO_CONNECT_REQUEST_CALLBACK,
                                &tcp_connection_option, sizeof(cy_socket_opt_callback_t));

    /* Variable used to set the socket options. */
    cy_socket_opt_callback_t tcp_recv_option = {
        .callback = tcp_server_recv_handler,
        .arg = NULL
    };

    /* Register the callback function to handle the messages received from the TCP client. */
    result = cy_socket_setsockopt(server_handle, CY_SOCKET_SOL_SOCKET,
                                  CY_SOCKET_SO_RECEIVE_CALLBACK,
                                  &tcp_recv_option, sizeof(cy_socket_opt_callback_t));

    /* Bind the TCP socket created to the server IP address and to the TCP port. */
    result = cy_socket_bind(server_handle, &tcp_server_addr, sizeof(tcp_server_addr));

    /* Start listening on the TCP server socket. */
    result = cy_socket_listen(server_handle, TCP_SERVER_MAX_PENDING_CONNECTIONS);

    for (;;)
    {
        if(send_msg_to_client)
        {
            /* Send a message to the TCP client. */
            result = cy_socket_send(client_handle, tx_buffer, strlen(tx_buffer),
                                    CY_SOCKET_FLAGS_NONE, &bytes_sent);

            send_msg_to_client = false;
        }

        vTaskDelay(RTOS_TASK_TICKS_TO_WAIT);
    }
}

Code Snippet 5: TCP IPv6 Client Connect

This code snippet demonstrates how to create a TCP client using an IPv6 address domain and connect to a TCP server. After connection is established with the TCP server, the client sends a message to the TCP server and waits for a message from the server.


/* Converts a 16-bit value from host byte order (little-endian) to network byte order (big-endian) */
#define HTONS(x) ( ( ( (x) & 0x0000FF00) >> 8 ) | ((x) & 0x000000FF) << 8 )

/* Arguments passed are uint16_t and in little-endian format. */
#define MAKE_IPV6_ADDRESS(a, b, c, d, e, f, g, h) { \
                                                    ( (uint32_t) (HTONS(a)) | ( (uint32_t) (HTONS(b)) << 16 ) ), \
                                                    ( (uint32_t) (HTONS(c)) | ( (uint32_t) (HTONS(d)) << 16 ) ), \
                                                    ( (uint32_t) (HTONS(e)) | ( (uint32_t) (HTONS(f)) << 16 ) ), \
                                                    ( (uint32_t) (HTONS(g)) | ( (uint32_t) (HTONS(h)) << 16 ) ), \
                                                  }

/* Change the server IPv6 address and port number to match the TCP server address to which the client wants to connect to. */
#define TCP_SERVER_IPV6_ADDRESS                   MAKE_IPV6_ADDRESS( 0xFE80, 0, 0, 0, 0x29D, 0x6BFF, 0xFE9D, 0xE2B4)
#define TCP_SERVER_PORT                           (50007)

/* Buffer size to store the incoming messages from the server. */
#define MAX_TCP_RECV_BUFFER_SIZE                  (20)

#define RTOS_TASK_TICKS_TO_WAIT                   (1000)

/* Socket disconnect timeout. */
#define SOCKET_DISCONNECT_TIMEOUT                 (0)

/* TCP socket handle. */
cy_socket_t ipv6_client_handle;

/* Flag to indicate that message is received from the TCP server. */
bool received_msg_from_server;

/* Function to handle the incoming message from the TCP server. */
cy_rslt_t tcp_ipv6_client_recv_handler(cy_socket_t client_handle, void *arg)
{
    cy_rslt_t result ;

    /* Variable to store the number of bytes received. */
    uint32_t bytes_received = 0;

    /* Buffer to store the incoming data from the TCP server. */
    char rx_buffer[MAX_TCP_RECV_BUFFER_SIZE];

    /* Receive the incoming message from the TCP server. */
    result = cy_socket_recv(client_handle, rx_buffer, MAX_TCP_RECV_BUFFER_SIZE,
                            CY_SOCKET_FLAGS_NONE, &bytes_received);

    /* Set the flag to indicate that a message is received from the TCP server. */
    received_msg_from_server = true;

    return result;
}

void snippet_tcp_ipv6_client()
{
    cy_rslt_t result;
    (void)(result);

    /* Variable to store the number of bytes sent to the TCP server. */
    uint32_t bytes_sent = 0;

    /* IP address and TCP port number of the TCP server. */
    cy_socket_sockaddr_t tcp_server_addr = {
        .ip_address.ip.v6 = TCP_SERVER_IPV6_ADDRESS,
        .ip_address.version = CY_SOCKET_IP_VER_V6,
        .port = TCP_SERVER_PORT
    };

    /* Buffer to hold the data to be sent to the client. */
    char tx_buffer[] = "Message to TCP server";

    /* Initialize the Secure Sockets Library. */
    result = cy_socket_init();

    /* Create a TCP socket. */
    result = cy_socket_create(CY_SOCKET_DOMAIN_AF_INET6, CY_SOCKET_TYPE_STREAM, CY_SOCKET_IPPROTO_TCP, &client_handle);

    /* Variable used to set the socket options. */
    cy_socket_opt_callback_t tcp_recv_option = {
        .callback = tcp_ipv6_client_recv_handler,
        .arg = NULL
    };

    /* Register the callback function to handle the messages received from the TCP server. */
    result = cy_socket_setsockopt(client_handle, CY_SOCKET_SOL_SOCKET,
                                  CY_SOCKET_SO_RECEIVE_CALLBACK,
                                  &tcp_recv_option, sizeof(cy_socket_opt_callback_t));

    result = cy_socket_connect(client_handle, &tcp_server_addr, sizeof(cy_socket_sockaddr_t));

    /* Send a message to the TCP server. */
    result = cy_socket_send(client_handle, tx_buffer, strlen(tx_buffer), CY_SOCKET_FLAGS_NONE, &bytes_sent);

    for(;;)
    {
        if(received_msg_from_server)
        {
            break;
        }

        vTaskDelay(RTOS_TASK_TICKS_TO_WAIT);
    }
}

Code Snippet 6: Create UDP Socket

This code snippet demonstrates how to initialize and create a UDP socket using an IPv4 address domain.

void snippet_create_udp_socket()
{
    cy_rslt_t result;
    (void)(result);

    /* UDP socket handle. */
    cy_socket_t socket_handle;

    /* Initialize the Secure Sockets Library. */
    result = cy_socket_init();

    /* Create a UDP socket. */
    result = cy_socket_create(CY_SOCKET_DOMAIN_AF_INET, CY_SOCKET_TYPE_DGRAM, CY_SOCKET_IPPROTO_UDP, &socket_handle);
}

Code Snippet 7: UDP Client - Send data to a UDP server using an IPv4 address

This code snippet demonstrates how to create a UDP client using an IPv4 address domain and send data to a UDP server. After sending data to the UDP server, this UDP client waits for a response message from the server.


#define MAKE_IPV4_ADDRESS(a, b, c, d)     ((((uint32_t) d) << 24) | \
                                          (((uint32_t)  c) << 16) | \
                                          (((uint32_t)  b) << 8) |\
                                          ((uint32_t)   a))

/* Change the server IP address and port number to match the UDP server address to which
 * client wants to connect to.
 */
#define UDP_SERVER_IP_ADDRESS                     MAKE_IPV4_ADDRESS(192, 168, 18, 9)
#define UDP_SERVER_PORT                           (50007)

/* Buffer size to store the incoming messages from the server. */
#define MAX_UDP_RECV_BUFFER_SIZE                  (20)

#define RTOS_TASK_TICKS_TO_WAIT                   (1000)

/* UDP socket handle. */
cy_socket_t client_handle;

bool received_msg_from_udp_server;

/* Function to handle the incoming  message from the UDP server. */
cy_rslt_t udp_client_recv_handler(cy_socket_t socket_handle, void *arg)
{
    cy_rslt_t result ;

    /* Variable to store the number of bytes received. */
    uint32_t bytes_received = 0;

    /* Buffer to store the incoming data from the UDP server. */
    char rx_buffer[MAX_UDP_RECV_BUFFER_SIZE];

    /* Receive the incoming message from the UDP server. */
    result = cy_socket_recvfrom(socket_handle, rx_buffer, MAX_UDP_RECV_BUFFER_SIZE, CY_SOCKET_FLAGS_NONE, NULL, NULL, &bytes_received);

    received_msg_from_udp_server = true;
    return result;
}

void snippet_udp_client()
{
    cy_rslt_t result;
    (void)(result);

    /* Variable to store the number of bytes sent to the UDP server. */
    uint32_t bytes_sent = 0;

    /* IP address and UDP port number of the UDP server. */
    cy_socket_sockaddr_t udp_server_addr = {
        .ip_address.ip.v4 = UDP_SERVER_IP_ADDRESS,
        .ip_address.version = CY_SOCKET_IP_VER_V4,
        .port = UDP_SERVER_PORT
    };

    /* Buffer to hold the data to be sent to client. */
    char tx_buffer[] = "Message to UDP server";

    /* Initialize the Secure Sockets Library. */
    result = cy_socket_init();

    /* Create a UDP socket. */
    result = cy_socket_create(CY_SOCKET_DOMAIN_AF_INET, CY_SOCKET_TYPE_DGRAM, CY_SOCKET_IPPROTO_UDP, &client_handle);

    /* Variable used to set the socket options. */
    cy_socket_opt_callback_t udp_recv_option = {
        .callback = udp_client_recv_handler,
        .arg = NULL
    };

    /* Register the callback function to handle the messages received from the UDP client. */
    result = cy_socket_setsockopt(client_handle, CY_SOCKET_SOL_SOCKET,
                                  CY_SOCKET_SO_RECEIVE_CALLBACK,
                                  &udp_recv_option, sizeof(cy_socket_opt_callback_t));

    /* Send a message to the UDP server. */
    result = cy_socket_sendto(client_handle, tx_buffer, strlen(tx_buffer), CY_SOCKET_FLAGS_NONE, &udp_server_addr, sizeof(cy_socket_sockaddr_t), &bytes_sent);

    for(;;)
    {
        if(received_msg_from_udp_server)
        {
            break;
        }

        vTaskDelay(RTOS_TASK_TICKS_TO_WAIT);
    }
}

Code Snippet 8: UDP Server - Receive data from a UDP client using an IPv4 address

This code snippet demonstrates how to create a UDP server using an IPv4 address domain and receive data from a UDP client.


#define MAKE_IPV4_ADDRESS(a, b, c, d)     ((((uint32_t) d) << 24) | \
                                          (((uint32_t)  c) << 16) | \
                                          (((uint32_t)  b) << 8) |\
                                          ((uint32_t)   a))

/* Change the server IP address and port number to match the UDP server address to which
 * client wants to connect to.
 */
#define UDP_SERVER_IP_ADDRESS                     MAKE_IPV4_ADDRESS(192, 168, 18, 9)
#define UDP_SERVER_PORT                           (50007)

/* Buffer size to store the incoming messages from the client. */
#define MAX_UDP_RECV_BUFFER_SIZE                  (20)

/* UDP socket handle. */
cy_socket_t server_handle;

bool received_msg_from_udp_client;

/* Function to handle the incoming  message from the UDP client. */
cy_rslt_t udp_server_recv_handler(cy_socket_t socket_handle, void *arg)
{
    cy_rslt_t result ;

    /* Variable to store the number of bytes received. */
    uint32_t bytes_received = 0;

    char rx_buffer[MAX_UDP_RECV_BUFFER_SIZE];

    /* Receive the incoming message from the UDP server. */
    result = cy_socket_recvfrom(server_handle, rx_buffer, MAX_UDP_RECV_BUFFER_SIZE, CY_SOCKET_FLAGS_NONE, NULL, NULL, &bytes_received);

    received_msg_from_udp_client = true;

    return result;
}

void snippet_udp_server()
{
    cy_rslt_t result;
    (void)(result);

    /* IP address and UDP port number of the UDP server. */
    cy_socket_sockaddr_t udp_server_addr = {
        .ip_address.ip.v4 = UDP_SERVER_IP_ADDRESS,
        .ip_address.version = CY_SOCKET_IP_VER_V4,
        .port = UDP_SERVER_PORT
    };

    /* Initialize the Secure Sockets Library. */
    result = cy_socket_init();

    /* Create a UDP socket. */
    result = cy_socket_create(CY_SOCKET_DOMAIN_AF_INET, CY_SOCKET_TYPE_DGRAM, CY_SOCKET_IPPROTO_UDP, &server_handle);

    /* Variable used to set the socket options. */
    cy_socket_opt_callback_t udp_recv_option = {
        .callback = udp_server_recv_handler,
        .arg = NULL
    };

    /* Register the callback function to handle the messages received from the UDP client. */
    result = cy_socket_setsockopt(server_handle, CY_SOCKET_SOL_SOCKET,
                                  CY_SOCKET_SO_RECEIVE_CALLBACK,
                                  &udp_recv_option, sizeof(cy_socket_opt_callback_t));

    /* Bind the UDP socket created to the server IP address and port. */
    result = cy_socket_bind(server_handle, &udp_server_addr, sizeof(udp_server_addr));

    for(;;)
    {
        if(received_msg_from_udp_client)
        {
            break;
        }

        vTaskDelay(RTOS_TASK_TICKS_TO_WAIT);
    }
}

Code Snippet 9: IPv4 multicast group - Join and leave an IPv4 multicast group

This code snippet demonstrates how to join an IPv4 multicast group, send a packet to the IPv4 multicast address, receive a packet from the IPv4 multicast group, and leave the IPv4 multicast group.


#define MAKE_IPV4_ADDRESS(a, b, c, d)     ((((uint32_t) d) << 24) | \
                                          (((uint32_t)  c) << 16) | \
                                          (((uint32_t)  b) << 8) |\
                                          ((uint32_t)   a))

/* IPv4 multicast group address. Change it to the mutlicast group address you want to join. */
#define IPV4_MULTICAST_GROUP_ADDRESS      MAKE_IPV4_ADDRESS(224, 1, 1, 1)

/* UDP Port number. Change it to the required port number. */
#define UDP_PORT                          (50007)

/* IPv4 address of your device. Change it to the IPv4 address of your device. */
#define IPV4_DEVICE_ADDRESS               MAKE_IPV4_ADDRESS(192, 168, 18, 9)

/* Buffer size to store the incoming multicast message. */
#define MAX_UDP_RECV_BUFFER_SIZE          (20)

void snippet_udp_ipv4_multicast_join_leave()
{
    cy_socket_t handle;
    cy_rslt_t result;
    uint32_t bytes_sent = 0;
    uint32_t bytes_received = 0;
    cy_socket_ip_mreq_t imr;

    (void)(result);

    /* Buffer to hold the data to be sent to the multicast group. */
    char tx_buffer[] = "Message to multicast group";

    /* Buffer to store the incoming message from the multicast group. */
    char rx_buffer[MAX_UDP_RECV_BUFFER_SIZE];

    /* Initialize the Secure Sockets Library. */
    result = cy_socket_init();

    /*
     * Add the code to obtain the IPv4 address of the device.
     */

    /* IPv4 address of the device. */
    cy_socket_ip_address_t ip_addr = {
        .ip.v4 = IPV4_DEVICE_ADDRESS, /* Attention: This IP address is hardcoded with random address in this snippet. It should be updated with the actual device IPv4 address. */
        .version = CY_SOCKET_IP_VER_V4
    };

    /* IPv4 address of the multicast group. */
    cy_socket_ip_address_t multicast_address = {
        .ip.v4 = IPV4_MULTICAST_GROUP_ADDRESS,
        .version = CY_SOCKET_IP_VER_V4
    };

    /* Socket address of the multicast group. */
    cy_socket_sockaddr_t socket_address = {
        .ip_address = multicast_address,
        .port = UDP_PORT
    };

    /* Fill the multicast request variable. */
    imr.if_addr = ip_addr;
    imr.multi_addr = multicast_address;

    /* Create a UDP socket. */
    result = cy_socket_create(CY_SOCKET_DOMAIN_AF_INET, CY_SOCKET_TYPE_DGRAM, CY_SOCKET_IPPROTO_UDP, &handle);

    /* Join an IPv4 multicast group. */
    result = cy_socket_setsockopt(handle, CY_SOCKET_SOL_IP, CY_SOCKET_SO_JOIN_MULTICAST_GROUP, &imr, sizeof(imr));

    /* Bind the UDP socket created to the multicast address and port. */
    result = cy_socket_bind(handle, &socket_address, sizeof(socket_address));

    /* Send a message to the multicast group. */
    result = cy_socket_sendto(handle, tx_buffer, strlen(tx_buffer), CY_SOCKET_FLAGS_NONE, &socket_address, sizeof(cy_socket_sockaddr_t), &bytes_sent);

    /* Receive a message from the multicast group. */
    result = cy_socket_recvfrom(handle, rx_buffer, MAX_UDP_RECV_BUFFER_SIZE, CY_SOCKET_FLAGS_NONE, NULL, NULL, &bytes_received);

    /* Leave the multicast group. */
    result = cy_socket_setsockopt(handle, CY_SOCKET_SOL_IP, CY_SOCKET_SO_LEAVE_MULTICAST_GROUP, &imr, sizeof(imr));
}

Code Snippet 10: IPv6 multicast group - Join and leave an IPv6 multicast group

This code snippet demonstrates how to join an IPv6 multicast group, send a packet to the IPv6 multicast address, receive a packet from the IPv6 multicast group, and leave the IPv6 multicast group.


/* Converts a 16-bit value from host byte order (little-endian) to network byte order (big-endian) */
#define HTONS(x) ( ( ( (x) & 0x0000FF00) >> 8 ) | ((x) & 0x000000FF) << 8 )

/* Arguments passed are uint16_t and in little-endian format. */
#define MAKE_IPV6_ADDRESS(a, b, c, d, e, f, g, h) { \
                                                    ( (uint32_t) (HTONS(a)) | ( (uint32_t) (HTONS(b)) << 16 ) ), \
                                                    ( (uint32_t) (HTONS(c)) | ( (uint32_t) (HTONS(d)) << 16 ) ), \
                                                    ( (uint32_t) (HTONS(e)) | ( (uint32_t) (HTONS(f)) << 16 ) ), \
                                                    ( (uint32_t) (HTONS(g)) | ( (uint32_t) (HTONS(h)) << 16 ) ), \
                                                  }

/* IPv6 Multicast group address. Change it to the mutlicast group address you want to join. */
#define IPV6_MULTICAST_GROUP_ADDRESS              MAKE_IPV6_ADDRESS( 0XFF02, 0, 0, 0, 0, 0, 0, 0XFB)

/* UDP Port. Change it to the required port number. */
#define UDP_PORT                                  (50007)

/* IPv6 address of your device. Change it to the IPv6 address of your device.*/
#define IPV6_DEVICE_ADDRESS                       MAKE_IPV6_ADDRESS( 0xFE80, 0, 0, 0, 0x29D, 0x6BFF, 0xFE9D, 0xE2B4)

void snippet_udp_ipv6_multicast_join_leave()
{
    cy_socket_t handle;
    cy_rslt_t result;
    uint32_t bytes_sent = 0;
    uint32_t bytes_received = 0;
    cy_socket_ip_mreq_t imr;

    (void)(result);

    /* Buffer to hold the data to be sent to the multicast group. */
    char tx_buffer[] = "Message to multicast group";

    /* Buffer to store the incoming message from the multicast group. */
    char rx_buffer[MAX_UDP_RECV_BUFFER_SIZE];

    /* Initialize the Secure Sockets Library. */
    result = cy_socket_init();

    /*
     * Add the code to obtain the IPv4 address of the device.
     */

    /* IPv6 address of the device. */
    cy_socket_ip_address_t ip_addr = {
        .ip.v6 = IPV6_DEVICE_ADDRESS, /* Attention: This IP address is hardcoded with random address in this snippet. It should be updated with the actual device IPv4 address. */
        .version = CY_SOCKET_IP_VER_V6
    };

    /* IPV6 address of the multicast group. */
    cy_socket_ip_address_t multicast_address = {
        .ip.v6 = IPV6_MULTICAST_GROUP_ADDRESS,
        .version = CY_SOCKET_IP_VER_V6
    };

    /* Fill the multicast request variable. */
    imr.if_addr = ip_addr;
    imr.multi_addr = multicast_address;

    /* Create a UDP socket. */
    result = cy_socket_create(CY_SOCKET_DOMAIN_AF_INET6, CY_SOCKET_TYPE_DGRAM, CY_SOCKET_IPPROTO_UDP, &handle);

    /* Join an IPv6 multicast group. */
    result = cy_socket_setsockopt(handle, CY_SOCKET_SOL_IP, CY_SOCKET_SO_JOIN_MULTICAST_GROUP, &imr, sizeof(imr));

    /* Socket address of the multicast group. */
    cy_socket_sockaddr_t socket_address = {
        .ip_address = multicast_address,
        .port = UDP_PORT
    };

    /* Bind the UDP socket created to the multicast address and port. */
    result = cy_socket_bind(handle, &socket_address, sizeof(socket_address));

    /* Send a message to the multicast group. */
    result = cy_socket_sendto(handle, tx_buffer, strlen(tx_buffer), CY_SOCKET_FLAGS_NONE, &socket_address, sizeof(cy_socket_sockaddr_t), &bytes_sent);

    /* Receive a message from the multicast group. */
    result = cy_socket_recvfrom(handle, rx_buffer, MAX_UDP_RECV_BUFFER_SIZE, CY_SOCKET_FLAGS_NONE, NULL, NULL, &bytes_received);

    /* Leave the multicast group. */
    result = cy_socket_setsockopt(handle, CY_SOCKET_SOL_IP, CY_SOCKET_SO_LEAVE_MULTICAST_GROUP, &imr, sizeof(imr));
}

Code Snippet 11: Enable broadcast messages - Enable broadcast messages, send a broadcast packet, and receive a broadcast packet.

This code snippet demonstrates how to enable broadcast messages, and send and receive a broadcast packet.


#define MAKE_IPV4_ADDRESS(a, b, c, d)     ((((uint32_t) d) << 24) | \
                                          (((uint32_t)  c) << 16) | \
                                          (((uint32_t)  b) << 8) |\
                                          ((uint32_t)   a))

/* Broadcast address. */
#define BROADCAST_ADDRESS                 MAKE_IPV4_ADDRESS(255, 255, 255, 255)

/* IP address to bind the socket for any incoming interface. */
#define IP_ADDRESS_ANY                    MAKE_IPV4_ADDRESS(0, 0, 0, 0)

/* UDP Port number. Change it to the required port number. */
#define UDP_PORT                          (50007)

/* Buffer size to store the incoming broadcast message. */
#define MAX_UDP_RECV_BUFFER_SIZE          (20)

void snippet_enable_broadcast_messages()
{
    cy_socket_t handle;
    cy_rslt_t result;
    uint32_t bytes_sent = 0;
    uint32_t bytes_received = 0;
    uint8_t broadcast_enable = 1;
    (void)(result);

    /* Buffer to hold the data to be sent to the multicast group. */
    char tx_buffer[] = "Broadcasting Message";

    /* Buffer to store the incoming broadcast message. */
    char rx_buffer[MAX_UDP_RECV_BUFFER_SIZE];

    /* Initialize the Secure Sockets Library. */
    result = cy_socket_init();

    /* Broadcast socket address. */
    cy_socket_sockaddr_t socket_address = {
        .ip_address.ip.v4 = BROADCAST_ADDRESS,
        .ip_address.version = CY_SOCKET_IP_VER_V4,
        .port = UDP_PORT
    };


    /* Socket address to bind the socket to. */
    cy_socket_sockaddr_t socket_address_any = {
        .ip_address.ip.v4 = IP_ADDRESS_ANY,
        .ip_address.version = CY_SOCKET_IP_VER_V4,
        .port = UDP_PORT
    };

    /* Create a UDP socket. */
    result = cy_socket_create(CY_SOCKET_DOMAIN_AF_INET, CY_SOCKET_TYPE_DGRAM, CY_SOCKET_IPPROTO_UDP, &handle);

    /* Enable broadcast messages. */
    result = cy_socket_setsockopt(handle, CY_SOCKET_SOL_SOCKET, CY_SOCKET_SO_BROADCAST, (void*)(&broadcast_enable), sizeof(broadcast_enable));

    /* Bind the UDP socket created to the broadcast address and port. */
    result = cy_socket_bind(handle, &socket_address_any, sizeof(socket_address_any));

    /* Send a broadcast message. */
    result = cy_socket_sendto(handle, tx_buffer, strlen(tx_buffer), CY_SOCKET_FLAGS_NONE, &socket_address, sizeof(cy_socket_sockaddr_t), &bytes_sent);

    /* Receive a broadcast message. */
    result = cy_socket_recvfrom(handle, rx_buffer, MAX_UDP_RECV_BUFFER_SIZE, CY_SOCKET_FLAGS_NONE, NULL, NULL, &bytes_received);
}

Code Snippet 12: Get the current time from the NTP server - Send an NTP request packet to the NTP server, and receive an NTP reply packet.

This code snippet demonstrates how to get the current time from the NTP server using a UDP socket.


/* Converts a 32-bit value from network byte order to host byte order. */
#define NTOHL(x)    ((((x) & (uint32_t)0x000000ffUL) << 24) | \
                     (((x) & (uint32_t)0x0000ff00UL) <<  8) | \
                     (((x) & (uint32_t)0x00ff0000UL) >>  8) | \
                     (((x) & (uint32_t)0xff000000UL) >> 24))

#define NTP_SERVER                                  "pool.ntp.org"
/* UDP port number of the NTP server. */
#define NTP_SERVER_PORT_NUM                         (123)

/* NTP epoch time.*/
#define NTP_EPOCH                                   (86400U * (365U * 70U + 17U))

/* LI: leap indicator. */
#define NTP_LEAP_INDICATOR_CLOCK_UNSYNCRONIZED      (3)

/* VN: version number. */
#define NTP_VERSION_NUM_V3                          (3)

/* Mode. */
#define NTP_MODE_CLIENT                             (3)

/*
 * NTP packet structure, taken from RFC 1305
 * http://www.ietf.org/rfc/rfc1305.txt
 */
typedef struct
{
    unsigned int mode : 3;
    unsigned int vn   : 3;
    unsigned int li   : 2;
    uint8_t      stratum;
    int8_t       poll;
    uint8_t      precision;
    uint32_t     root_delay;
    uint32_t     root_dispersion;
    uint32_t     reference_identifier;
    uint32_t     reference_timestamp_seconds;
    uint32_t     reference_timestamp_fraction;
    uint32_t     originate_timestamp_seconds;
    uint32_t     originate_timestamp_fraction;
    uint32_t     receive_timestamp_seconds;
    uint32_t     receive_timestamp_fraction;
    uint32_t     transmit_timestamp_seconds;
    uint32_t     transmit_timestamp_fraction;
} ntp_packet_t;

void snippet_get_ntp_time()
{
    cy_socket_t handle;
    cy_rslt_t result;
    uint32_t bytes_sent = 0;
    uint32_t bytes_received = 0;
    cy_socket_ip_address_t server_ip_addr;
    uint32_t seconds;
    (void)(result);
    (void)(seconds);

    /* NTP Request packet. */
    ntp_packet_t ntp_request;

    /* NTP Reply packet. */
    ntp_packet_t ntp_reply;

    /* Initialize the Secure Sockets Library. */
    result = cy_socket_init();

    /* Get the IP address of the NTP server. */
    result = cy_socket_gethostbyname(NTP_SERVER, CY_SOCKET_IP_VER_V4, &server_ip_addr);

    /* Server socket address. */
    cy_socket_sockaddr_t socket_address = {
        .ip_address = server_ip_addr,
        .port = NTP_SERVER_PORT_NUM
    };

    /* Create a UDP socket. */
    result = cy_socket_create(CY_SOCKET_DOMAIN_AF_INET, CY_SOCKET_TYPE_DGRAM, CY_SOCKET_IPPROTO_UDP, &handle);

    /* Initialize the NTP request packet to be sent to the server. */
    memset(&ntp_request, 0, sizeof(ntp_packet_t));
    ntp_request.li   = NTP_LEAP_INDICATOR_CLOCK_UNSYNCRONIZED;
    ntp_request.vn   = NTP_VERSION_NUM_V3;
    ntp_request.mode = NTP_MODE_CLIENT;

    /* Send the NTP request packet to the server. */
    result = cy_socket_sendto(handle, &ntp_request, sizeof(ntp_request), 0, &socket_address, (uint32_t)sizeof(socket_address), &bytes_sent);

    /* Receive the reply packet from the NTP server. */
    result = cy_socket_recvfrom(handle, &ntp_reply, sizeof(ntp_reply), 0, NULL, NULL, &bytes_received);

    /* Convert to January 1, 1970 epoch time in seconds. */
    seconds = NTOHL(ntp_reply.transmit_timestamp_seconds) - NTP_EPOCH;

    /* Delete the socket. */
    cy_socket_delete(handle);

    /* De-initialize the Secure Socket Library. */
    cy_socket_deinit();
}

Troubleshooting

Problem1: cy_socket_listen() fails if called on more than one socket.

Description: The default lwIP configuration provided by the Middleware Core library defines the MEMP_NUM_TCP_PCB_LISTEN option to 1; therefore, if cy_socket_listen() is called for the second socket, the function fails with the error code CY_RSLT_MODULE_SECURE_SOCKETS_NOMEM. Solution: Change MEMP_NUM_TCP_PCB_LISTEN value in lwipopts.h to support more than one server socket.

Problem2: Sometimes, the cy_socket_recv() function does not return for 10 seconds.

Description: cy_socket_recv() returns after 10 seconds if the requested number of bytes is not available in the socket. This happens because the default receive timeout is configured as 10 seconds when the socket is created. Solution: Change the default receive timeout value for the socket by calling the cy_socket_setsockopt() function with the CY_SOCKET_SO_RCVTIMEO socket option with the required timeout value.

Problem3: TCP packets are dropped.

Description: When an application is consuming data at a lower rate, the network stack continues to receive the data at the rate it arrives from the peer. At some point, the network stack’s receive queue can overflow causing packets to get dropped. Solution: Applications consuming data at a lower rate should adjust the TCP receive queue size and TCP Window size so that when the receive queue size becomes full, the TCP window size also becomes zero. To change the TCP receive queue size, change the DEFAULT_TCP_RECVMBOX_SIZE macro value in the lwipopts.h file. To change the TCP Window size, define the TCP_WND macro in lwipopts.h to override the default value defined the opt.h file.

Problem4: cy_socket_create() function fails with the CY_RSLT_MODULE_SECURE_SOCKETS_NOMEM error while creating multiple sockets.

Description: The maximum number of TCP and UDP sockets that can be created depends on the network stack configuration. Trying to create more than the maximum value configured can cause the cy_socket_create() function to return the error CY_RSLT_MODULE_SECURE_SOCKETS_NOMEM. Solution: Configure the maximum number of TCP and UDP sockets to be supported by changing the MEMP_NUM_TCP_PCB and MEMP_NUM_UDP_PCB values respectively in the lwipopts.h file. Also note that the total number of TCP and UDP configurations should not exceed the value of the MEMP_NUM_NETCONN macro defined in the lwipopts.h file.

Problem5: An existing socket cannot be reused to establish a new connection just with socket disconnect.

Description: lwIP does not support re-connect on a disconnected socket. Once a connected TCP socket is disconnected, it cannot be reused for a new connection or re-connection. Solution: Delete the disconnected socket and create a new socket using cy_socket_create, and try to connect with the new socket using cy_socket_connect.

Problem6: cy_socket_sendto() with multicast destination addresses fails on the SoftAP interface.

Description: If a socket is used for multicast operations over the SoftAP interface without binding it to the SoftAP interface, cy_socket_sendto() fails with the CY_RSLT_MODULE_SECURE_SOCKETS_ERROR_ROUTING error. Solution: Bind the socket to the SoftAP interface using the cy_socket_setsockopt() function with the CY_SOCKET_SO_BINDTODEVICE socket option.