/* servOOB_TCP.c
               riceve dati da uno stream TCP, anche fuori banda
   su SunOS compilare con gcc -o servOOB_TCP.c -lsocket -lnsl servOOB_TCP.c
   su linux               gcc -o servOOB_TCP servOOB_TCP.c                   

   eseguire ad esempio su 130.136.2.7 lanciando la seguente riga di comandi:
   servOOB_TCP 5001 
   */



#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>

#define SOCKET_ERROR   ((int)-1)
#define SIZEBUF 10000

void usage(void)
{  printf ("usage: servTCP LOCAL_PORT_NUMBER\n"); exit(1); }

int main(int argc, char *argv[])
{
  #define MAXSIZE 100 
  struct sockaddr_in Local, Cli;
  char string_remote_ip_address[100];
  short int remote_port_number, local_port_number;
  int socketfd, newsocketfd, OptVal, len, ris;
  int n, nread, nwrite;
  char buf[MAXSIZE];
  char str[10];
  int i;
  fd_set rfds, efds, afds;

  if(argc!=2) { printf ("necessario 1 parametri\n"); usage(); exit(1);  }
  else {
    local_port_number = atoi(argv[1]);
  }

  /* get a stream socket */
  printf ("socket()\n");
  socketfd = socket(AF_INET, SOCK_STREAM, 0);
  if (socketfd == SOCKET_ERROR) {
    printf ("socket() failed, Err: %d \"%s\"\n", errno,strerror(errno));
    exit(1);
  }

  /* avoid EADDRINUSE error on bind() */
  OptVal = 1;
  printf ("setsockopt()\n");
  ris = setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, (char *)&OptVal, sizeof(OptVal));
  if (ris == SOCKET_ERROR)  {
    printf ("setsockopt() SO_REUSEADDR failed, Err: %d \"%s\"\n", errno,strerror(errno));
    exit(1);
  }

  /* name the socket */
  memset ( &Local, 0, sizeof(Local) );
  Local.sin_family		=	AF_INET;
  /* indicando INADDR_ANY viene collegato il socket all'indirizzo locale IP     */
  /* dell'interaccia di rete che verrą utilizzata per inoltrare il datagram IP  */
  Local.sin_addr.s_addr	=	htonl(INADDR_ANY);         /* wildcard */
  Local.sin_port		=	htons(local_port_number);
  printf ("bind()\n");
  ris = bind(socketfd, (struct sockaddr*) &Local, sizeof(Local));
  if (ris == SOCKET_ERROR)  {
    printf ("bind() failed, Err: %d \"%s\"\n",errno,strerror(errno));
    exit(1);
  }

  printf ("listen()\n");
  ris = listen(socketfd, 10 );
  if (ris == SOCKET_ERROR)  {
    printf ("listen() failed, Err: %d \"%s\"\n",errno,strerror(errno));
    exit(1);
  }

  /* wait for connection request */
  memset ( &Cli, 0, sizeof(Cli) );
  printf ("accept()\n");
  len=sizeof(Cli);
  newsocketfd = accept(socketfd, (struct sockaddr*) &Cli, &len);
  if (newsocketfd == SOCKET_ERROR)  {
    printf ("accept() failed, Err: %d \"%s\"\n",errno,strerror(errno));
    exit(1);
  }


  FD_ZERO(&afds);
  FD_SET(newsocketfd,&afds);
  rfds=afds;
  efds=afds;
  while(1) {
	rfds=afds;
	efds=afds;
    i=select(newsocketfd+1, &rfds, NULL, &efds, NULL);
	if(i<0)  {
	     char msgerror[1024];
		 sprintf(msgerror,"select failed [err %d] ",errno);
		 perror(msgerror); return(1);
	  }  

   /* LETTURA FUORI BANDA */
	if( FD_ISSET(newsocketfd,&efds) ) {
		n=recv(newsocketfd, str, 10, MSG_OOB);
		if(n<0) {
			char msgerror[1024];
			sprintf(msgerror,"recv(MSG_OOB) failed [err %d] ",errno);
			perror(msgerror); return(1);
		}  
		else  if(n==0) {
			char msgerror[1024];
			sprintf(msgerror,"recv(MSG_OOB): connection close");
			perror(msgerror); return(1);
		}  
		else{
			printf("\nRECEIVED OUT OF BAND DATA\n");
			printf("%s ",str);
		}
	}
   /* LETTURA NORMALE */
	if( FD_ISSET(newsocketfd,&rfds) ) {
		n=read(newsocketfd, str, 10);
		if(n<0) {
			char msgerror[1024];
			sprintf(msgerror,"read() failed [err %d] ",errno);
			perror(msgerror); return(1);
		}  
		else if(n==0) {
			char msgerror[1024];
			sprintf(msgerror,"read(): connection close");
			perror(msgerror); return(1);
		}  
		else
			printf("%s ",str);
	}
  }


  /* scrittura solo per svegliare il client */
  nwrite=0;
  printf ("write()\n");
  while( (n=write(newsocketfd, &(buf[nwrite]), nread-nwrite)) >0 )
     nwrite+=n;
  if(n<0) {
    char msgerror[1024];
    sprintf(msgerror,"write() failed [err %d] ",errno);
    perror(msgerror); return(1);
  }

  /* chiusura */
  printf ("close()\n");
  close(newsocketfd);
  close(socketfd);

  return(0);
}


