Search code examples
clinuxsocketsposixdaemon

Daemonize() issues on Debian


I'm currently writing a multi-process client and a multi-treaded server for some project i have.

The server is a Daemon. In order to accomplish that, i'm using the following daemonize() code:

static void daemonize(void)
{
    pid_t pid, sid;

    /* already a daemon */
    if ( getppid() == 1 ) return;

    /* Fork off the parent process */
    pid = fork();
    if (pid < 0) {
        exit(EXIT_FAILURE);
    }
    /* If we got a good PID, then we can exit the parent process. */
    if (pid > 0) {
        exit(EXIT_SUCCESS);
    }

    /* At this point we are executing as the child process */

    /* Change the file mode mask */
    umask(0);

    /* Create a new SID for the child process */
    sid = setsid();
    if (sid < 0) {
        exit(EXIT_FAILURE);
    }

    /* Change the current working directory.  This prevents the current
       directory from being locked; hence not being able to remove it. */
    if ((chdir("/")) < 0) {
        exit(EXIT_FAILURE);
    }

    /* Redirect standard files to /dev/null */
    freopen( "/dev/null", "r", stdin);
    freopen( "/dev/null", "w", stdout);
    freopen( "/dev/null", "w", stderr);
}

int main( int argc, char *argv[] ) {
    daemonize();

    /* Now we are a daemon -- do the work for which we were paid */
    return 0;
}

I have a strange side effect when testing the server on Debian (Ubuntu).

The accept() function always fail to accept connections, the pid returned is -1

I have no idea what causing this, since in RedHat & CentOS it works well.

When i remove the call to daemonize(), everything works well on Debian, when i add it back, same accept() error reproduce.

I've been monitring the /proc//fd, everything looks good.

Something in the daemonize() and the Debian release just doesn't seem to work. (Debian GNU/Linux 5.0, Linux 2.6.26-2-286 #1 SMP)

Any idea what causing this?

Thank you


Solution

  • The accept(2) manpage says:

    EINVAL Socket is not listening for connections, or addrlen is invalid (e.g., is negative).

    Likely you have something like

    struct sockaddr_in;
    socklen_t len;
    ...
    
    new_fd = new_fd = accept(sockfd,(struct sockaddr *)&addr,&len);
    

    However, you need to set len to the size of the address you pass in:

    struct sockaddr_in addr;
    socklen_t len;
    len = sizeof(addr);
    ...
    new_fd = new_fd = accept(sockfd,(struct sockaddr *)&addr,&len);
    

    So, by some (un)lucky means your uninitialized 'len' variable get some nonsense value in some cases, and accept fails, while it happens to work in other scenarios.