/*  Asp Address Search Protocol Client (file comm.c)                       */
/*  Copyright (C) 1996-2001 Stenio Brunetta                                */
/*                                                                         */
/*  This program is free software; you can redistribute it and/or modify   */
/*  it under the terms of the GNU General Public License as published by   */
/*  the Free Software Foundation; either version 2 of the License, or      */
/*  (at your option) any later version.                                    */
/*                                                                         */
/*  This program is distributed in the hope that it will be useful,        */
/*  but WITHOUT ANY WARRANTY; without even the implied warranty of         */  
/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
/*  GNU General Public License for more details.                           */
/*                                                                         */
/*  You should have received a copy of the GNU General Public License      */
/*  along with this program; if not, write to the Free Software            */
/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
/*                                                                         */
/*  Author's email address: stenio@brunettaeperin.it                       */

static char rcsid[] = "$Id: comm.c,v 1.16 2001/01/23 11:20:01 ste Exp $";

#include "asp.h"

void avoid_comm_rcsid_warning(void){
  rcsid[0] = 0;
}

#ifndef TEMP_FAILURE_RETRY
#define TEMP_FAILURE_RETRY(EXPR) (EXPR)
#endif

int input_timeout(int filedes, unsigned int seconds, unsigned int micros){
  fd_set set;
  struct timeval timeout;
  
  /* Initialize the file descriptor set. */
  FD_ZERO (&set);
  FD_SET (filedes, &set);
  
  /* Initialize the timeout data structure. */
  timeout.tv_sec = seconds;
  timeout.tv_usec = micros;
  
  /* `select' returns 0 if timeout, 1 if input available, -1 if error. */
  return  TEMP_FAILURE_RETRY(select (FD_SETSIZE, \
	&set, NULL, NULL, &timeout));
}

int verbose = 0;

int asp_send(int s, int len, char* msg, struct sockaddr* to){
  int out_stat, err, err_size = sizeof(int);

  if((out_stat = sendto(s, msg, len, 0, to, sizeof(struct sockaddr))) == -1){
    /* local send error */
#ifndef ENABLE_DEBUG
    if(errno != ECONNREFUSED) asp_perror("sendto");
#endif
  }

#ifndef ENABLE_DEBUG
if(verbose == 1) fprintf(stderr, "sent %s to: %s\n", msg, \
			 inet_ntoa(((struct sockaddr_in *)to)->sin_addr));
#endif

#ifdef ENABLE_DEBUG
    fprintf(stderr, "%s %d: sendto: %s out_stat: %d errno: %d\n", \
	    __FILE__, __LINE__, \
	    inet_ntoa(((struct sockaddr_in *)to)->sin_addr), out_stat, errno);
  if(errno != 0) fprintf(stderr, "%s\n", strerror(errno));
#endif

  /* Deletes possible remote errors. Sometimes getsockopt doesn't
     find the error even if it is impossible the packet had been
     delivered; this cause to wait even if all host2try refuse 
     the connection. :( */
  if((out_stat = getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &err_size)) == -1){
#ifndef ENABLE_DEBUG
    asp_perror("getsockopt");
#endif
  }

#ifdef ENABLE_DEBUG
  fprintf(stderr, "%s %d: getsockopt out_stat: %d err: %d errno: %d\n", \
	  __FILE__, __LINE__, out_stat, err, errno);
  if(errno != 0) fprintf(stderr, "%s\n", strerror(errno));
#endif

  if(err != 0) return 1; /* bad message */
  else return 0;
}

/* asp_recv ritorna:
   1 : trovato
   0 : non e` arrivata risposta
   -1: errore */

int asp_recv(int s, int len, char* buf, char* host2find, \
	       struct sockaddr* from, int delay){
  int in_stat;
  int size_from = sizeof(struct sockaddr);
  
  /* Aspetta finche` non arriva la risposta o finche` scadono */
  /* i delay secondi                                          */
  while((in_stat = input_timeout(s, delay, 0)) == 1){

    /* pulisce il buffer */
    bzero(buf, MSGSIZE);

    /* E' arrivato qualcosa... */
    if((in_stat = recvfrom(s, buf, len, 0, from, &size_from)) == -1){

#ifdef ENABLE_DEBUG
    fprintf(stderr, "%s %d: recvfrom in_stat: -1 errno: %d", __FILE__,\
	    __LINE__, errno);
    if(errno != 0) fprintf(stderr, " == %s\n", strerror(errno));
    else fprintf(stderr, "\n");
#endif

    /* Torna in ascolto per il tempo rimanente */
    continue;
    }

#ifdef ENABLE_DEBUG
    fprintf(stderr, "%s %d: recvfrom: %s mesg: %s in_stat: %d errno: %d", \
	    __FILE__, __LINE__, \
	    inet_ntoa(((struct sockaddr_in*)from)->sin_addr), buf, in_stat, \
	    errno);
    if(errno != 0) fprintf(stderr, " == %s\n", strerror(errno));
    else fprintf(stderr, "\n");
#endif

    /* Se arrivano risposte che non seguono il protocollo
       si torna in ascolto */
    if(strcmp(host2find, buf) != 0) continue;
    else return 1; /* Trovato! */
  }

  return in_stat; /* 0 o -1 */
}
