No. 1 Story

HP job cuts loom for Australian employees

A number of Australian employees of Hewlett-Packard are facing the loss of their jobs as the global computer giant looks to slash its worldwide workforce by up to 30,000.

read more

Related Articles

Write, your, own, Linux, server, part, one
In only a couple of years, millions of Australians will directly be using the...
The Commonwealth Bank's chief information officer will visit Darwin tomorrow for meetings with Aboriginal...

Write your own Linux server part one

Business IT - Open Source

dwserv.cpp


/*
 *  DWSERV
 */

#include "dwserv.h"
#include <unistd.h>

#define VERSION "1.2\n"

bool logging = false;
bool verbose = false;
char FileName [PATH_MAX];

// ---------------------------------------------------------------------------
int main (int argc, char *argv [])
{
  struct sockaddr_in sin, fsin;
  struct protoent *ppe;
  int sock, ssock;
  socklen_t alen;
  int port = 6000;
  int qlen = 5;
  int pid;
  int fd;
  char nowtime [26];
  char Remote [80];
  int connections = 0;
  FILE *logfp = NULL;

  if (geteuid () != 0)
  {
    printf ("\n%s must be run with super-user privileges.\n", argv [0]);
    return 0;
  }

  FileName [0] = '\0';

// Process command line arguments.

  for (int i = 1; i < argc; i++)
  {
    if (strncmp (argv[i], "-p", 2) == 0)
      port = atoi (argv[i] + 2);

    else if (strncmp (argv[i], "-q", 2) == 0)
      qlen = atoi (argv[i] + 2);

    else if (strncmp (argv[i], "-f", 2) == 0)
    {
      strcpy (FileName, argv[i] + 2);
      logging = true;
    }
    else if (strncmp (argv[i], "-v", 2) == 0)
      verbose = logging = true;

    else if (strncmp (argv[i], "-l", 2) == 0)
      logging = true;

    else
    {
      DisplayHelpMessage (port, qlen);
      return 0;
    }
  }

// Set up the socket.

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

  if ((ppe = getprotobyname ("tcp")) == 0)
    errexit ("Can't find tcp: %s\n", strerror (errno));

  if ((sock = socket (PF_INET, SOCK_STREAM, ppe->p_proto)) < 0)
    errexit ("Can't create socket: %s\n", strerror (errno));

  if (bind (sock, (struct sockaddr *) &sin, sizeof (sin)) < 0)
    errexit ("Can't bind to port: %s\n", strerror (errno));

  if (listen (sock, qlen) < 0)
    errexit ("Can't listen on port: %s\n", strerror (errno));

// Print a welcome banner.

  printf ("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
                  "   DWServ Server\n"
                  "      Port: %4d\n"
                  "   Version: %s"
                  "-----------------------------\n"
                  "by  David M. Williams\n"
                  "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n", port, VERSION);

  log ("Listening on port %d (qlen = %d).\n", port, qlen);

// Set up the server safely.

// 1. Run the server in the background ...

  if ((pid = fork ()) < 0)
    errexit ("Error setting up server: %s\n", strerror (errno));

  if (pid)  // Non-zero is parent.
  {
    printf ("Server pid is %d.\n", pid);
    if (strlen (FileName) > 0)
      log ("Server pid is %d.\n\n", pid);
    exit (0);
  }

// 2. Detach from controlling tty ...

  fd = open ("/dev/tty", O_RDWR);
  ioctl (fd, TIOCNOTTY, 0);
  close (fd);

// 3. Miscellaneous commands ...

  umask (027);
  chdir ("/tmp");

// Be the server !

  while (1)
  {
// Wait for connections. If one is made, then get a slave socket to
// process it, in a child process. This way the server remains free
// to accept more connections.

    alen = sizeof (fsin);
    ssock = accept (sock, (struct sockaddr *) &fsin, &alen);
    if (ssock < 0)
    {
      if (errno == EINTR)
        continue;
      else
        errexit ("accept: %s\n", strerror (errno));
    }

    strcpy (Remote, IPtoAddress (fsin.sin_addr));
    log ("%s: connect from %s\n", CurrentDateTime (nowtime), Remote);

    signal (SIGCHLD, reaper);
    connections++;
    if (fork () == 0)
    {
      process (ssock, Remote, connections);
      exit (0);
    }
    else
      close (ssock);
  }
}

// ---------------------------------------------------------------------------
void DisplayHelpMessage (int port, int qlen)
{
  printf ("\nDWServ Server\n\n");
  printf ("\t\tSyntax:\tdwserv [flags]\n\n");
  printf ("\t-pPORT\t\tto specify the port to use.\n");
  printf ("\t\t\t(default = %d)\n", port);
  printf ("\t-qQLEN\t\tto specify the queue length.\n");
  printf ("\t\t\t(default = %d)\n", qlen);
  printf ("\t-l\t\tto perform logging.\n");
  printf ("\t-fFILENAME\tto specify a log file.\n");
  printf ("\t\t\t(default = stdout)\n");
  printf ("\t-v\t\tto specify verbose logging.\n");
  printf ("\t\t\t(default = off)\n\n");
}

// ---------------------------------------------------------------------------
char *CurrentDateTime (char *nowtime)
{
  time_t now;

  time (&now);
  strcpy (nowtime, ctime (&now));
  nowtime [strlen (nowtime) - 1] = '\0';

  return nowtime;
}

// ---------------------------------------------------------------------------
void WriteToFD (int filedesc, char *s)
{
  write (filedesc, s, strlen (s));
}

// ---------------------------------------------------------------------------
void log (const char *format, ...)
{
  va_list  args;
  FILE  *fp;

  if (logging)
  {
    fp = stdout;

    if (strlen (FileName) > 0)
    {
      if ((fp = fopen (FileName, "a")) < 0)
        fp = stdout;
    }

    va_start (args, format);
    vfprintf (fp, format, args);
    va_end (args);

    if (fp != stdout)
      fclose (fp);
  }
}

// ---------------------------------------------------------------------------
int errexit (const char *format, ...)
{
  va_list args;
  char errstr [255];

  va_start (args, format);
  vsprintf (errstr, format, args);
  log (errstr);
  fprintf (stderr, errstr);
  va_end (args);

  exit (1);
}

// ---------------------------------------------------------------------------
const char *IPtoAddress (struct in_addr ipA)
{
  unsigned long hostname;
  struct hostent *ip;

  hostname = inet_addr (inet_ntoa (ipA));

  if ((ip = gethostbyaddr ((char *) &hostname, sizeof (long), AF_INET))<0)
    return "unknown";
  else
    return ip->h_name;
}

// ---------------------------------------------------------------------------
void reaper (int sig)
// The reaper cleans up zombie children processes.
// In Unix, when a child process terminates it sends a message back to
// the parent process.  Unless this message is handled, the child process
// will wait around forever taking up resources.
{
  int status;

  wait3 (&status, WNOHANG, (struct rusage *) 0);
}

// ---------------------------------------------------------------------------
void process (int ssock, char *Remote, int connections)
// This function handles the processing of a socket connection.
{
  StringVector *svec = new StringVector;
  int count = 0, n;
  char TmpBuf [LINELEN], InMsg [LINELEN];
  char OutMsg [MAX_STRING];
  char Command [5], Data [97];
  char nowtime [26];
  bool keepgoing = true;

// Display an innocent banner (anything to hide the real purpose).

  while (count < 3)
  {
    sprintf (OutMsg, "%s\n", CurrentDateTime (nowtime));
    WriteToFD (ssock, OutMsg);

    if ((n = read (ssock, InMsg, LINELEN - 1)) > 0)
    {
      InMsg [n] = '\0';

// Strip CR's and LF's
      if ((InMsg [strlen (InMsg) - 1] == 10) ||
         (InMsg [strlen (InMsg) - 1] == 13))
        InMsg [strlen (InMsg) - 1] = '\0';
      if ((InMsg [strlen (InMsg) - 1] == 10) ||
         (InMsg [strlen (InMsg) - 1] == 13))
        InMsg [strlen (InMsg) - 1] = '\0';

      if (strcmp (InMsg, SECRET_PASSWORD) == 0)
        count = 999;
    }

    count++;
  }

  if (count < 900)
  {
    close (ssock);
    return;
  }

// Loop until exit or connection lost.

  keepgoing = true;
  while (keepgoing)
  {

// Read input.
    WriteToFD (ssock, "");      // Send no prompt.

    if ((n = read (ssock, InMsg, LINELEN - 1)) <= 0)
      keepgoing = false;  // No more.
    else
      InMsg [n] = '\0';

// Process input.
    strcpy (OutMsg, "");

    if (keepgoing)
    {
      StripString (InMsg, Command, Data);

// Here are the main functions ...

// Aliases
      if (strcmp (Command, "ALIA") == 0)
        GetAliases (Data, OutMsg);

// Groups
      else if (strcmp (Command, "GROU") == 0)
        GetGroup (Data, OutMsg);

// Make new account
      else if (strcmp (Command, "MAKE") == 0)
        CreateAccount (Data, OutMsg);

// Start a process
      else if (strcmp (Command, "STRT") == 0)
        StartProcess (Data, OutMsg);

// Return the version number
      else if (strcmp (Command, "VERS") == 0)
        strcpy (OutMsg, VERSION);

// Miscellaneous commands ...

      else if (strcmp (Command, "QUIT") == 0)
      {
        keepgoing = false;
        strcpy (OutMsg, "");
      }

      else if (strcmp (Command, "STAT") == 0)
        sprintf (OutMsg, "%d connections.\n", connections);

      else
        sprintf (OutMsg, "");

      if (strlen (OutMsg) > 0)
        WriteToFD (ssock, OutMsg);

      if (verbose)
        log ("%d  %s\t%s\t%s\t%s\n", connections, Remote, Command,
                  Data, OutMsg);
    }

// And loop again!
  }

// Close the socket and finish !
  close (ssock);
}

// ---------------------------------------------------------------------------
void StripString (char *InMsg, char *Command, char *Data)
{
  int i, count;

  while (strlen (InMsg) < 4)
    strcat (InMsg, " ");

  for (i = 0; i < 4; i++)
    Command [i] = toupper (InMsg [i]);
  Command [i] = '\0';

  while ((InMsg [i] != ' ') && (InMsg [i] != '\0'))
    i++;

  while ((InMsg [i] == ' ') && (InMsg [i] != '\0'))
    i++;

  count = 0;
  while ((InMsg [i] != '\0') && (InMsg [i] != 13) && (InMsg [i] != 10))
    Data [count++] = InMsg [i++];
  Data [count] = '\0';
}