1.1.27.27.2 Example - TCP Server

#include <string.h>

#include "winc_socket.h"

#define TCP_SERVER_MAX_CLIENTS  2

typedef enum
{
    MODULE_STATE_INIT,
    MODULE_STATE_SOCKET_WAITING,
    MODULE_STATE_LISTEN,
    MODULE_STATE_LISTENING,
    MODULE_STATE_ERROR,
} MODULE_STATE;

typedef struct
{
    union sockaddr_union sockAddr;
} BSOCK_TCP_SERVER_INIT_TYPE;

static MODULE_STATE                 state;
static int                          sockh;
static int                          sockhClient[TCP_SERVER_MAX_CLIENTS] = {0};
static BSOCK_TCP_SERVER_INIT_TYPE   initData = {0};

void bsock_tcp_server_init(void *pInitData)
{
    if (NULL != pInitData)
    {
        memcpy(&initData, pInitData, sizeof(BSOCK_TCP_SERVER_INIT_TYPE));
    }

    state = MODULE_STATE_INIT;
}

void bsock_tcp_server_run(void)
{
    switch (state)
    {
        case MODULE_STATE_INIT:
        {
            state = MODULE_STATE_ERROR;

            sockh = socket(initData.sockAddr.sin_family, SOCK_STREAM, IPPROTO_TCP);

            if (sockh < 0)
            {
                break;
            }

            printf("opening socket %d\n", sockh);

            /* Fall through */
        }

        case MODULE_STATE_SOCKET_WAITING:
        {
            errno = 0;
            if (-1 == bind(sockh, (struct sockaddr*)&initData.sockAddr, sizeof(initData.sockAddr)))
            {
                printf("bind failed, errno is %d\n", errno);
                state = MODULE_STATE_ERROR;
                break;
            }

            printf("socket bound\n");

            /* Fall through */
        }

        case MODULE_STATE_LISTEN:
        {
            errno = 0;
            if (-1 == listen(sockh, TCP_SERVER_MAX_CLIENTS))
            {
                if (EAGAIN == errno)
                {
                    printf("socket not ready try again\n");
                    state = MODULE_STATE_LISTEN;
                }
                else
                {
                    printf("listen failed, errno is %d\n", errno);
                    state = MODULE_STATE_ERROR;
                }
            }
            else
            {
                printf("socket listening\n");
                state = MODULE_STATE_LISTENING;
            }

            break;
        }

        case MODULE_STATE_LISTENING:
        {
            int i;
            int numfds = 1;

            struct pollfd fd[1+TCP_SERVER_MAX_CLIENTS] = {0};

            fd[0].fd     = sockh;
            fd[0].events = POLLIN;

            for (i=0; i<TCP_SERVER_MAX_CLIENTS; i++)
            {
                fd[i+1].fd = sockhClient[i];

                if (0 != fd[i+1].fd)
                {
                    fd[i+1].events = POLLIN|POLLOUT;
                    numfds++;
                }
            }

            if (-1 == poll(fd, numfds, 0))
            {
                state = MODULE_STATE_ERROR;
                break;
            }

            if (0 != (fd[0].revents & POLLIN))
            {
                for (i=0; i<TCP_SERVER_MAX_CLIENTS; i++)
                {
                    union sockaddr_union sockAddr;
                    socklen_t sockAddrLen = sizeof(union sockaddr_union);
                    char ipStr[64];

                    if (0 == sockhClient[i])
                    {
                        sockhClient[i] = accept(sockh, (struct sockaddr*)&sockAddr, &sockAddrLen);

                        if (-1 == sockhClient[i])
                        {
                            sockhClient[i] = 0;
                        }
                        else
                        {
                            if (AF_INET == sockAddr.sin_family)
                            {
                                inet_ntop(sockAddr.sin_family, &sockAddr.in4.sin_addr, ipStr, sizeof(ipStr));
                            }
                            else if (AF_INET6 == sockAddr.sin_family)
                            {
                                inet_ntop(sockAddr.sin_family, &sockAddr.in6.sin6_addr, ipStr, sizeof(ipStr));
                            }

                            printf("accept %d from %s:%d\n", sockhClient[i], ipStr, ntohs(sockAddr.sin_port));
                        }

                        break;
                    }
                }
            }

            for (i=1; i<=TCP_SERVER_MAX_CLIENTS; i++)
            {
                if ((0 != fd[i].fd) && (0 != fd[i].revents))
                {
                    ssize_t numBytes = 0;
                    uint8_t buffer[128];

                    if (0 != (fd[i].revents & POLLIN))
                    {
                        errno = 0;
                        numBytes = recv(fd[i].fd, NULL, 0, MSG_PEEK|MSG_TRUNC);

                        if ((numBytes <= 0) && (errno != EWOULDBLOCK))
                        {
                            shutdown(fd[i].fd, SHUT_RDWR);
                            sockhClient[i-1] = 0;
                            break;
                        }

                        if (numBytes >= sizeof(buffer))
                        {
                            numBytes = sizeof(buffer);
                        }

                        errno = 0;
                        numBytes = recv(fd[i].fd, buffer, numBytes, 0);
                        if (numBytes <= 0)
                        {
                            if (errno != EWOULDBLOCK)
                            {
                                printf("recv failed, errno is %d\n", errno);
                                shutdown(fd[i].fd, SHUT_RDWR);
                                sockhClient[i-1] = 0;
                                break;
                            }
                        }

                        printf("recv: %d\n", numBytes);
                    }

                    if (0 != (fd[i].revents & POLLHUP))
                    {
                        printf("socket disconnected\n");

                        if (0 == (fd[i].revents & POLLIN))
                        {
                            shutdown(fd[i].fd, SHUT_RDWR);
                            sockhClient[i-1] = 0;
                            break;
                        }
                    }

                    if (0 != (fd[i].revents & POLLOUT))
                    {
                        if (numBytes > 0)
                        {
                            errno = 0;
                            numBytes = send(fd[i].fd, buffer, numBytes, 0);

                            if ((numBytes < 0) && (errno != EWOULDBLOCK) && (errno != EAGAIN))
                            {
                                printf("send failed, errno is %d\n", errno);
                                shutdown(fd[i].fd, SHUT_RDWR);
                                sockhClient[i-1] = 0;
                                break;
                            }
                        }
                    }
                }
            }

            break;
        }

        case MODULE_STATE_ERROR:
        {
            break;
        }

        default:
        {
            break;
        }
    }
}