/* Server TCP interativ (in rafala)

   Trimite clientului conectat o rafala de mesaje, 
   incluzind din cind in cind si o serie de date out-of-band
   
   Autor: Sabin-Corneliu Buraga <busaco@infoiasi.ro> (c)1998-2003
   Versiunea: 1.0 (ultima actualizare: 16 aprilie 2003)
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <netdb.h>

/* portul folosit */
#define PORT 8081

/* numarul de trimiteri ale mesajului */
#define MAX_WRITES 5

/* eroarea returnata de unele apeluri */
extern int errno;

/* prototipul functiei de trimitere a datelor */
void trimite_date (int);

/* programul */
int
main ()
{
  /* structurile pentru server si client */
  struct sockaddr_in server;
  struct sockaddr_in from;
  /* descriptori de socket */
  int sd, client;
  /* lungimea structurii sockaddr_in */
  int len;
  /* optiunea de reutilizarea a adresei pentru socket */
  char opt;
  /* adresa simbolica a adresei clientului */
  char site[80];
  /* structura utilizata pentru rezolvarea adresei */
  struct hostent *host;

  /* creare socket */
  if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
    {
      perror ("socket()");
      exit (1);
    }
  /* pregatim structurile de date */
  bzero (&server, sizeof (server));
  /* umplem structura folosita de server */
  server.sin_family = AF_INET;
  server.sin_addr.s_addr = htonl (INADDR_ANY);
  server.sin_port = htons (PORT);

  opt = 1;
  /* setam optiunea de a reutiliza portul */
  setsockopt (sd, SOL_SOCKET, SO_REUSEADDR, (void *) &opt, sizeof (opt));

  /* atasam socketul */
  if (bind (sd, (struct sockaddr *) &server, sizeof (struct sockaddr)) == -1)
    {
      perror ("bind()");
      exit (1);
    }

  /* punem serverul sa asculte daca vin clienti sa se conecteze */
  if (listen (sd, 5) == -1)
    {
      perror ("listen()");
      exit (1);
    }

  printf ("Asteptam la portul %d...\n", PORT);
  fflush (stdout);
  /* servim in mod iterativ clientii... */
  while (1)
    {
      len = sizeof (from);
      /* acceptam conexiunea din partea unui client */
      client = accept (sd, (struct sockaddr *) &from, &len);
      /* eroare la acceptarea conexiunii de la un client */
      if (client < 0)
	{
	  perror ("accept()");
	  continue;
	}
      /* determinam adresa simbolica a IP-ului clientului */
      strcpy (site, (char *) inet_ntoa (from.sin_addr));
      if ((host =
	   gethostbyaddr ((char *) &from.sin_addr, 4, AF_INET)) != NULL)
	strcpy (site, host->h_name);	/* preluam numele simbolic */

      printf ("S-a conectat un client de la %s.\n", site);
      fflush (stdout);
      printf ("Ii trimitem datele...\n");
      trimite_date (client);
      printf ("Deconectam clientul.\n", client);
      fflush (stdout);
      /* inchidem conexiunea cu clientul */
      close (client);
    }
}

/* trimiterea de mesaje unui client */
void
trimite_date (int fd)
{
  /* mesajul */
  char buffer[] = "Acesta este un mesaj transmis de serverul de rafala...\n";
  /* iterator */
  int i;

  for (i = 0; i < MAX_WRITES; i++)
    {
      if (write (fd, buffer, strlen (buffer)) < 0)
	{
	  perror ("write()");
	  return;
	}
      if (i % 2)
	{
	  /* trimitem din cind in cind si un mesaj out-of-band (OOB) */
	  if (send (fd, (char *) &buffer[0], sizeof (buffer[0]), MSG_OOB) < 0)
	    {
	      perror ("send()");
	    }
	}
      sleep (1);		/* nu dorim sa ne obosim... */
    }
}

