Search code examples
csocketsrecvunix-socket

Why does recv() give me errno 88 when accept works?


Why do I get errno 88 for recv() in the following code? I seem to be using the right socket and accept seems to work. The program runs fine, I can connect from a client, but as soon as I send a single byte of data, recv() fails. I am using the correct socket fd as far as I can understand and I have no idea what is causing this to fail.

#include <stdbool.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>


#include "log.h"
#include "server.h"
#include "protocol.h"




bool run_alarm_server ()
{
    llog(LOG_INFO, "Starting alarm server.");


    alarm_on = false;
    unlink(SOCKET_PATH);


    int                success;
    int                sock;
    int                conn;
    bool               run;
    char               buf[1];
    struct sockaddr_un srvaddr;


    success = false;


    memset(&srvaddr, 0, sizeof(srvaddr));
    srvaddr.sun_family = AF_UNIX;
    strcpy(srvaddr.sun_path, SOCKET_PATH);


    if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
        llog(LOG_ERROR, "Failed to create socket.");
    } else {
        llog (LOG_DEBUG, "Created socket.");
    }


    if (bind(sock, (struct sockaddr *) &srvaddr, SUN_LEN(&srvaddr)) < 0) {
        llog(LOG_ERROR, "Failed to bind to socket.");
    } else {
        llog(LOG_DEBUG, "Bound to socket.");
    }


    if (listen(sock, SERVER_QUEUE_LEN) < 0) {
        llog(LOG_ERROR, "Failed to listen on socket.");
    } else {
        llog(LOG_INFO, "Listening on socket.");
    }


    run = true;

    while (run) {
        if ((conn = accept(sock, NULL, NULL) < 0)) {
            llog(LOG_ERROR, "Failed to accept connection on socket.");
        } else {
            llog(LOG_INFO, "Accepted connection on socket.");
        }


        if (recv(conn, buf, sizeof(buf) / sizeof(buf[0]), 0) < 0) {
            llog(LOG_ERROR, "Failed to receive data on socket.");
        } else {
            llog(LOG_DEBUG, "Received data on socket.");
        }


        switch (buf[0]) {
            case ALARM_END:
                alarm_on = false;
                llog(LOG_ALARM, "The alarm has ended.");
                break;

            case ALARM_START:
                alarm_on = true;
                llog(LOG_ALARM, "The alarm has started.");
                break;

            case ALARM_ARM:
                llog(LOG_ALARM, "The system has been armed.");
                break;

            case ALARM_DISARM:
                alarm_on = false;
                llog(LOG_ALARM, "The system has been disarmed.");
                break;

            case ALARM_STATUS:
                llog(LOG_INFO, "The alarm status has been requested.");


                char alarm_status[1];

                if (alarm_on) {
                    alarm_status[0] = (char) 0x01;
                } else {
                    alarm_status[0] = (char) 0x00;
                }


                if (send(conn, (const void *) alarm_status, 1, 0) < 0) {
                    llog(LOG_ERROR, "Failed to send alarm status.");
                    run     = false;;
                } else {
                    llog(LOG_DEBUG, "Alarm status sent.");
                }

                break;

            case ALARM_QUIT:

                llog(LOG_INFO, "Exiting.");

                run     = false;
                success = true;
                break;
        }
    }


    if (socket >= 0) {
        close(sock);
    }

    if (conn >= 0) {
        close(conn);
    }


    unlink(SOCKET_PATH);


    return success;
}

Solution

  • Your problem is here:

    if ((conn = accept(sock, NULL, NULL) < 0)) {
    

    This line is being interpreted as:

    if (conn = (accept(sock, NULL, NULL) < 0)) {
    

    ... which means that conn will be set to 1 (aka boolean true) if the accept() call returns a negative value, or to 0 (aka boolean false) otherwise.

    I think what you intended was something like this:

    if ((conn = accept(sock, NULL, NULL)) < 0) {