int socket_transport_listen()

in linux/src/socket_transport_linux.c [556:643]


int socket_transport_listen(SOCKET_TRANSPORT_HANDLE socket_transport, uint16_t port)
{
    int result;
    // Codes_SOCKET_TRANSPORT_LINUX_11_054: [ If socket_transport is NULL, socket_transport_listen shall fail and return a non-zero value. ]
    if (socket_transport == NULL ||
        // Codes_SOCKET_TRANSPORT_LINUX_11_055: [ If port is 0, socket_transport_listen shall fail and return a non-zero value. ]
        port == 0)
    {
        LogError("Invalid arguments: SOCKET_TRANSPORT_HANDLE socket_transport: %p, uint16_t port: %" PRIu16 "",
            socket_transport, port);
        result = MU_FAILURE;
    }
    else
    {
        // Codes_SOCKET_TRANSPORT_LINUX_11_056: [ If the transport type is not SOCKET_BINDING, socket_transport_listen shall fail and return a non-zero value. ]
        if (socket_transport->type != SOCKET_BINDING)
        {
            LogError("Invalid socket type for this API expected: SOCKET_BINDING, actual: %" PRI_MU_ENUM, MU_ENUM_VALUE(SOCKET_TYPE, socket_transport->type));
            result = MU_FAILURE;
        }
        else
        {
            // Codes_SOCKET_TRANSPORT_LINUX_11_057: [ socket_transport_listen shall call sm_open_begin to begin the open. ]
            SM_RESULT open_result = sm_open_begin(socket_transport->sm);
            if (open_result != SM_EXEC_GRANTED)
            {
                // Codes_SOCKET_TRANSPORT_LINUX_11_058: [ If sm_open_begin does not return SM_EXEC_GRANTED, socket_transport_listen shall fail and return a non-zero value. ]
                LogError("sm_open_begin failed with %" PRI_MU_ENUM, MU_ENUM_VALUE(SM_RESULT, open_result));
                result = MU_FAILURE;
            }
            else
            {
                // Codes_SOCKET_TRANSPORT_LINUX_11_059: [ socket_transport_listen shall call socket with the params AF_INET, SOCK_STREAM and IPPROTO_TCP. ]
                socket_transport->socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
                if (socket_transport->socket == INVALID_SOCKET)
                {
                    LogErrorNo("Could not create socket");
                    result = MU_FAILURE;
                }
                else
                {
                    struct sockaddr_in service;

                    const int enable = 1;
                    // Codes_SOCKET_TRANSPORT_LINUX_11_083: [ socket_transport_listen shall set the SO_REUSEADDR option on the socket. ]
                    (void)setsockopt(socket_transport->socket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));

                    service.sin_family = AF_INET;
                    service.sin_addr.s_addr = htonl(INADDR_ANY);
                    service.sin_port = htons(port);

                    // Codes_SOCKET_TRANSPORT_LINUX_11_060: [ socket_transport_listen shall bind to the socket by calling bind. ]
                    if (bind(socket_transport->socket, (struct sockaddr*)&service, sizeof(service)) != 0)
                    {
                        LogErrorNo("Could not bind socket, port=%" PRIu16 "", port);
                        result = MU_FAILURE;
                    }
                    else if (set_nonblocking(socket_transport->socket) != 0)
                    {
                        LogErrorNo("Could not set listening socket in non-blocking mode");
                        result = MU_FAILURE;
                    }
                    else
                    {
                        // Codes_SOCKET_TRANSPORT_LINUX_11_061: [ socket_transport_listen shall start listening to incoming connection by calling listen. ]
                        if (listen(socket_transport->socket, SOMAXCONN) != 0)
                        {
                            LogErrorNo("Could not start listening for connections");
                            result = MU_FAILURE;
                        }
                        else
                        {
                            // Codess_SOCKET_TRANSPORT_LINUX_11_062: [ If successful socket_transport_listen shall call sm_open_end with true. ]
                            sm_open_end(socket_transport->sm, true);
                            result = 0;
                            goto all_ok;
                        }
                    }
                    // Codes_SOCKET_TRANSPORT_LINUX_11_063: [ If any failure is encountered, socket_transport_listen shall call sm_open_end with false, fail and return a non-zero value. ]
                    close(socket_transport->socket);
                }
                sm_open_end(socket_transport->sm, false);
            }
        }
    }
all_ok:
    return result;
}