LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (http://www.linuxquestions.org/questions/programming-9/)
-   -   C Socket Server unexpectedly shutting down (http://www.linuxquestions.org/questions/programming-9/c-socket-server-unexpectedly-shutting-down-740878/)

stuffradio 07-17-2009 05:50 PM

C Socket Server unexpectedly shutting down
 
I'm running a socket server that I found on one of the C programming websites. I've been trying this with other socket server scripts as well. It runs fine for a while, it accepts multiple clients... but then for some reason unbeknown to me, it shuts down. Also the last couple times I saw the server in the process list running, and I killed it anyways because it was not responding.

Anyone have any possible remedies for me?

Thanks!

jhwilliams 07-17-2009 06:40 PM

* Debug it with standard GNU utilities: gdb, strace, etc.
* Invoke the daemon with a log to some file you can go look at if it spits out to stdout/stderr.
* Post some code here, or a link to the code you're talking about?
--> read and understand the code and the error conditions.
* Core dump when it quits responding, (kill -6), then gdb the dump.

stuffradio 07-20-2009 12:41 AM

I'm using a different one right now, and it looks like it's working fine.

Code:

/*
 * Based on:
 * http://www.gnu.org/software/libc/manual/html_mono/libc.html#Server%20Example
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <syslog.h>
#include <stdarg.h>
#include <time.h>

#define PORT            1730  /* default port to listen on */
#define MAXMSG          10240
#define MAX_QUEUED_CONNS    5
#define MAX_SOCK_IDLE      10  /* minutes */
#define SECS_PER_MIN      60

/*
 * Global vars.
 */
static const char  gVersion[] = "@(#) tcpechoserver v1.4 " __DATE__;

const char        gScaryMsg[] =
    "\r\n\r\n                            WARNING\r\n"
    "      Unauthorized access to this system is forbidden and will be\r\n"
    "      prosecuted by law. By accessing this system, you agree that your\r\n"
    "      actions may be monitored if unauthorized usage is suspected.\r\n\r\n"
    "      Your IP address has been logged: ";

const char        gDiscMsg[] = "\r\nDisconnecting due to inactivity\r\n";

char              gHostNameBuf[512];
struct sockaddr_in gServerName;
int                gMaxFd;
int                gNumberClients;
int                gDebug;
int                gTcpListenSock;
int                gUdpSock;
time_t            gMaxSockIdle = MAX_SOCK_IDLE * SECS_PER_MIN;
time_t            gSockTime[FD_SETSIZE];
fd_set            gActive_fd_set;

#ifdef __CYGWIN__
/* Set default log file name for Cygwin build. */
char              gLogFilename[FILENAME_MAX] = { "C:/TEMP/tcpecho.log" };
#define SYSLOG  mySyslog
/* ------------------------------------------------
 *                                      mySyslog
 * ------------------------------------------------
 */
static void mySyslog (int level, const char *fmt, ...)
{
    static FILE    *logFile = NULL;
    va_list        ap;
    char            buf[1024];
    time_t          logTime;

    if (logFile == NULL)
    {
        logFile = fopen (gLogFilename, "a");
    }

    if (logFile != NULL)
    {
        va_start (ap, fmt);
        vsnprintf (buf, sizeof buf, fmt, ap);
        va_end (ap);

        logTime = time (NULL);
        fprintf (logFile, "%24.24s: %s\n", ctime (&logTime), buf);
        fflush (logFile);
    }
}
#else
#define SYSLOG  syslog
#endif

/* ------------------------------------------------
 *                              getRemoteHostname
 * ------------------------------------------------
 */
const char * getRemoteHostname (struct sockaddr_in sin)
{
    struct hostent *hp;

    hp = gethostbyaddr ((char *) &sin.sin_addr,
                        sizeof sin.sin_addr, AF_INET);
    if (hp)
    {
        /*
        * We found a corresponding hostname, format the string one way...
        */
        snprintf (gHostNameBuf, sizeof gHostNameBuf, "%s [%s]", hp->h_name,
                  inet_ntoa (sin.sin_addr));
    }
    else
    {
        /*
        * This host not in the host tables or Domain Name Server.
        */
        snprintf (gHostNameBuf, sizeof gHostNameBuf, "[%s]",
                  inet_ntoa (sin.sin_addr));
    }

    return gHostNameBuf;
}

/* ------------------------------------------------
 *                                    bindToPort
 * ------------------------------------------------
 */
int bindToPort (int sockStyle)
{
    int            sock;
    int            opt;

    /* Create the socket. */
    sock = socket (PF_INET, sockStyle, 0);
    if (sock < 0)
    {
        SYSLOG (LOG_USER, "socket failed");
        exit (EXIT_FAILURE);
    }

    /*
    * Set the "REUSEADDR" option on this socket. This will allow us to
    * bind() to it EVEN if there already connections in progress on this
    * port number. Otherwise, we would get an "Address already in use"
    * error.
    */
    if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0)
    {
      SYSLOG (LOG_USER, "setsockopt failed");
      exit (EXIT_FAILURE);
    }

    if (bind (sock, (struct sockaddr *) &gServerName, sizeof gServerName) < 0)
    {
        SYSLOG (LOG_USER, "bind failed");
        exit (EXIT_FAILURE);
    }

    return sock;
}

/* ------------------------------------------------
 *                                    closeSock
 * ------------------------------------------------
 */
void closeSock (int sock)
{
    SYSLOG (LOG_USER, "connection %d: disconnecting.", sock);
    close (sock);
    FD_CLR (sock, &gActive_fd_set);
    gNumberClients--;
}

/* ------------------------------------------------
 *                                echoTcp
 * ------------------------------------------------
 */
int echoTcp (int sock)
{
    int            nbytes;
    char            buffer[MAXMSG];

    nbytes = read (sock, buffer, MAXMSG);
    if (nbytes > 0)
    {
        /* Echo data read and log the time. */
        write (sock, buffer, nbytes);
        gSockTime[sock] = time(NULL);
        return nbytes;
    }
    else
    {
        /* End-of-file or error. */
        closeSock (sock);
        return -1;
    }
}

/* ------------------------------------------------
 *                              echoUdp
 * ------------------------------------------------
 */
void echoUdp (int sock)
{
    int                nbytes;
    int                size;
    struct sockaddr_in sin;
    char              buffer[MAXMSG];

    sin.sin_family      = AF_INET;
    sin.sin_addr.s_addr = INADDR_ANY;
    sin.sin_port        = gServerName.sin_port;
    size                = sizeof sin;

    nbytes = recvfrom (sock, buffer, MAXMSG, 0,
                      (struct sockaddr *) &sin, &size);
    if (nbytes < 0)
    {
        SYSLOG (LOG_USER, "recfrom failed");
        return;
    }

    /* Log the message. */
    if (gDebug)
    {
        SYSLOG (LOG_USER, "Rcvd UDP (%d bytes) from: [%s]  Port: %d",
                nbytes, inet_ntoa (sin.sin_addr), ntohs(sin.sin_port));
    }

    /*
    * If the source port is 0, we can't send the message back.
    */
    if ( ntohs(sin.sin_port) != 0 )
    {
        /* Echo the message back to the sender. */
        nbytes = sendto (sock, buffer, nbytes, 0,
                        (struct sockaddr *) &sin, size);
        if (nbytes < 0)
        {
            SYSLOG (LOG_USER, "sendto failed");
            return;
        }
    }
}

/* ------------------------------------------------
 *                              checkIdleSockets
 * ------------------------------------------------
 */
void checkIdleSockets ( void )
{
    int        sock;
    time_t      currentTime = time(NULL);

    //if (gDebug) SYSLOG(LOG_USER, "checkIdleSockets");

    /*
    * Check for an active socket that has been idle
    * for longer than gMaxSockIdle seconds.
    */
    for (sock = 0; sock <= gMaxFd; ++sock)
    {
        if (FD_ISSET (sock, &gActive_fd_set)  &&
            ((currentTime - gSockTime[sock]) > gMaxSockIdle ) &&
            (sock != gTcpListenSock) &&
            (sock != gUdpSock))
        {
            write (sock, gDiscMsg, sizeof gDiscMsg);
            closeSock (sock);
        }
    }
}

/* ------------------------------------------------
 *                                  acceptNewSock
 * ------------------------------------------------
 */
void acceptNewSock ( void )
{
    struct sockaddr_in clientName;
    int                acceptSock;
    int                size;
    char              buffer[MAXMSG];

    /* Accept new connection request on original socket. */
    size = sizeof clientName;
    acceptSock = accept (gTcpListenSock,
                        (struct sockaddr *) &clientName,
                        &size);
    if (acceptSock < 0)
    {
        SYSLOG (LOG_USER, "accept failed");
        exit (EXIT_FAILURE);
    }

    SYSLOG (LOG_USER,
            "connection %d from %s, port %hu.",
            acceptSock,
            getRemoteHostname (clientName),
            ntohs (clientName.sin_port));

    snprintf(buffer, sizeof buffer, "%s%s\r\n\r\n",
            gScaryMsg, gHostNameBuf);
    write (acceptSock, buffer, strlen(buffer));

    /*
    * Add newly accepted socket to the active set.
    */
    FD_SET (acceptSock, &gActive_fd_set);
    gMaxFd = MAX(gMaxFd, acceptSock);

    gSockTime[acceptSock] = time(NULL);
    gNumberClients++;
}

/* ------------------------------------------------
 *                                  processSockets
 * ------------------------------------------------
 */
void processSockets (fd_set  *pRead_fd_set)
{
    int                activeSock;

    /* Service all the sockets with input pending. */
    for (activeSock = 0; activeSock <= gMaxFd; ++activeSock)
    {
        if (FD_ISSET (activeSock, pRead_fd_set))
        {
            if (activeSock == gTcpListenSock)
            {
                /*
                * Accept a connection for a TCP socket.
                */
                acceptNewSock ();
            }
            else if (activeSock == gUdpSock)
            {
                /*
                * Echo data arriving on the UDP socket.
                */
                echoUdp (activeSock);
            }
            else
            {
                /*
                * Echo data arriving on a connected TCP socket.
                */
                echoTcp (activeSock);

            }          /* if (activeSock == gTcpListenSock)        */
        }              /* if (FD_ISSET (activeSock, pRead_fd_set)) */
    }                  /* for (activeSock = 0; ...)                */

}

/* ------------------------------------------------
 *                                        mainLoop
 * ------------------------------------------------
 */
void mainLoop (void)
{
    int            selectResult;
    fd_set          read_fd_set;
    struct timeval  selectTimeout;
    struct timeval *pSelectTimeout;

    /* Create the tcp socket and set it up to accept connections. */
    gTcpListenSock = bindToPort (SOCK_STREAM);
    if (listen (gTcpListenSock, MAX_QUEUED_CONNS) < 0)
    {
        SYSLOG (LOG_USER, "listen failed");
        exit (EXIT_FAILURE);
    }

    gUdpSock = bindToPort (SOCK_DGRAM);

    /* Initialize the set of active sockets. */
    FD_ZERO (&gActive_fd_set);
    FD_SET (gTcpListenSock, &gActive_fd_set);
    FD_SET (gUdpSock,      &gActive_fd_set);

    gMaxFd = MAX(gTcpListenSock, gUdpSock);
    gNumberClients = 0;

    while (1)
    {
        if ((gMaxSockIdle > 0) && (gNumberClients > 0))
        {
          /*
            * If there are any clients connected, we'll have
            * select timeout every so often so that we can
            * check for idle sockets and close them if they
            * have been idle too long.
            */
          selectTimeout.tv_usec =  0;
          selectTimeout.tv_sec  = 61;
          pSelectTimeout = &selectTimeout;
        }
        else
        {
            /*
            * If there are no clients, or the timeout is disabled,
            * we let select block until there is activity on the
            * listen socket.
            */
            pSelectTimeout = NULL;
        }

        read_fd_set = gActive_fd_set;

        /* Block until input arrives on one or more active sockets. */
        selectResult = select (gMaxFd+1, &read_fd_set, NULL, NULL, pSelectTimeout);

        if (selectResult < 0)
        {
            SYSLOG (LOG_USER, "select failed");
            exit (EXIT_FAILURE);
        }

        if (selectResult > 0)
        {
            processSockets (&read_fd_set);
        }

        if ((gMaxSockIdle > 0) && (selectResult >= 0))
        {
            /*
            * Data received or select timed out.
            */
            checkIdleSockets ();
        }
    }                          /* while (1)    */

    /* not reached */
}

/* ------------------------------------------------
 *                                          usage
 * ------------------------------------------------
 */
void usage (const char *progname)
{
    fprintf (stderr, "%s\n", gVersion);
#ifdef __CYGWIN__
    fprintf (stderr, "\nusage: %s [-adhlpt]\n", progname);
#else
    fprintf (stderr, "\nusage: %s [-adhpt]\n", progname);
#endif
    fprintf (stderr, "      -a <inetaddr>  set local address for bind\n");
    fprintf (stderr, "      -d              enable debug logging\n");
    fprintf (stderr, "      -h              print this help\n");
#ifdef __CYGWIN__
    fprintf (stderr, "      -l <logfile>    log to file <logfile> (default: %s)\n",
            gLogFilename);
#endif
    fprintf (stderr, "      -p #            set port for bind (default: %d)\n", PORT);
    fprintf (stderr, "      -t #            "
                    "set idle socket timeout in minutes (default: %d)\n"
                    "                      zero disables timeout\n\n",
                    MAX_SOCK_IDLE);
}

/* ------------------------------------------------
 *                                          main
 * ------------------------------------------------
 */
int main (int argc, char *argv[])
{
    char            ch;
    char          *progname;
    int            i;
    char            cmdLine[256];
    int            cmdIdx;

    /*
    * Trim path from program name.
    */
    progname = rindex (argv[0], '/');
    if (progname == NULL)
    {
        progname = argv[0];
    }
    else
    {
        progname++;
    }

    /* Set default socket name. */
    gServerName.sin_family      = AF_INET;
    gServerName.sin_port        = htons (PORT);
    gServerName.sin_addr.s_addr = htonl (INADDR_ANY);

    // Log the exact command line used to start the program.
    cmdIdx = 0;
    cmdIdx += sprintf(&cmdLine[cmdIdx], "# %s", progname);
    for (i=1; i<argc; i++)
    {
        cmdIdx += sprintf(&cmdLine[cmdIdx], " %s", argv[i]);
    }

    /*
    * Process cmd line options.
    */
#ifdef __CYGWIN__
    while ((ch = getopt (argc, argv, ":dhl:a:p:t:")) != -1)
#else
    while ((ch = getopt (argc, argv, ":dha:p:t:")) != -1)
#endif
    {
        switch (ch)
        {
        case 'h':
            usage (progname);
            exit (0);
            break;

        case 'd':
            gDebug = 1;
            break;

        case 'a':
            if (strcmp (optarg, "localhost") == 0)
            {
                gServerName.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
            }
            else
            {
                gServerName.sin_addr.s_addr = inet_addr (optarg);
                if (gServerName.sin_addr.s_addr == htonl (INADDR_NONE))
                {
                    fprintf (stderr, "Bad bind address: %s\n", optarg);
                    exit (-1);
                }
            }
            break;

        case 'p':
            {
                uint16_t        port = atoi (optarg);

                if (port < 1024)
                {
                    fprintf (stderr, "Can't bind to privileged port: %hu\n",
                            port);
                    exit (-1);
                }
                gServerName.sin_port = htons (port);
            }
            break;

        case 't':
            gMaxSockIdle = atoi (optarg) * SECS_PER_MIN;
            if (gMaxSockIdle < 0)
            {
                fprintf (stderr, "Error: invalid timeout value\n");
                exit (-1);
            }
            break;

#ifdef __CYGWIN__
        case 'l':
            strncpy (gLogFilename, optarg, sizeof gLogFilename);
            break;
#endif

        default:
            fprintf (stderr, "\nUnknown option");
            usage (progname);
            exit (-1);
            break;
        }
    }

    /*
    * Close all open file descriptors.
    */
    close (STDIN_FILENO);
    close (STDOUT_FILENO);
    close (STDERR_FILENO);

    /*
    * Fork to detach from shell.
    */
    if (fork () != 0)
    {
        exit (0);              /* parent exits */
    }

    SYSLOG (LOG_USER, cmdLine);
    SYSLOG (LOG_USER, "%s : port %hu",
            gVersion, ntohs (gServerName.sin_port));
    if (gDebug)
    {
        SYSLOG (LOG_USER, "Timeout = %d secs; local addr = %s", gMaxSockIdle,
                inet_ntoa (gServerName.sin_addr));
    }

    mainLoop ();                /* does not return */

    exit (0);
}

Can anyone tell me how to send data the socket server receives to a php script so I can insert the data in to a MySQL database?

chrism01 07-21-2009 12:32 AM

Why not just do it from C : http://dev.mysql.com/doc/refman/5.0/en/c.html ?


All times are GMT -5. The time now is 02:46 PM.