#include <stdio.h>
#include <hesiod.h>
#include "Connect.h"
#include "slw.h"

extern char *pname;
extern void printError();

#define E(x) if (x) printError(1)
#define ED(x) if (x) printError(0)

Addr openConnection(from, who)
     Addr from;
     char *who;
{
  char to[50];
  Addr dest;

  sprintf(to, "%s:%s/%s", PORTDOMAIN, who, PORTNAME);

  if (Connect_NameToAddress(to, &dest))
    {
    errorCheck:
      switch(Error)
	{
	case UDP_UNKNOWNSERVICE:
	  /* fprintf(stderr,
	     "Warning: Service %s not in /etc/services; using port %d\n",
	     PORTNAME, PORTNUMBER); */
	  Error_Pop();
	  sprintf(to, "%s:%s/%d", PORTDOMAIN, who, PORTNUMBER);
	  if (Connect_NameToAddress(to, &dest))
	    goto errorCheck; /* Can't get UNKNOWNSERVICE with explicit port */
	  break;
	case CONNECT_UNKNOWNNAME:
	  ED(CHECK);
	  break;
	default:
	  E(CHECK);
	}
    }

  /*
   * Need discussion of the semantics of OpenConnection
   * here. :-)
   */
  if (dest != NOADDRESS)
    if (Connect_OpenConnection(from, dest))
      {
	if (Error_Severity == S_FATAL)
	  {
	    Connect_FreeAddress(dest);
	    dest = NOADDRESS;
	    ED(CHECK);
	  }
      }

  if (dest == NOADDRESS)
    dest = from;

  return dest;
}

int askQuestionOfServer(req, repl)
     Packet *req, *repl;
{
  static int didhes = 0, curserver = 0, validaddress = 0;
  static char **servernames;
  static Addr servers[MAXSERVERS];
  int i, startserver, patient;

  if (!didhes)
    {
      /*
       * Initialize server list.
       */
      didhes = 1;

      servernames = hes_resolve(SLOCNAME, SLOC);
      if (servernames == NULL)
	{
	  switch(hes_error())
	    {
	    case HES_ER_NOTFOUND:
	      fprintf(stderr, "%s: Hesiod doesn't know about %s.\n",
		      pname, SLOCNAME);
	      break;
	    case HES_ER_CONFIG:
	      fprintf(stderr,
     "%s: Hesiod indicates possible local hesiod configuration problems.\n",
		      pname);
	      break;
	    case HES_ER_NET:
	      fprintf(stderr, "%s: Hesiod reports network problems.\n", pname);
	      break;
	    }

	  fprintf(stderr, "%s: Could not find any servers.\n", pname);
	  exit(1);
	}

      for (i = 0; i < MAXSERVERS; i++)
	servers[i] = NOADDRESS;
    }

  startserver = curserver;

  /*
   * See if we can talk to anyone.
   */
  while (1)
    {
      if (servers[curserver] == NOADDRESS)
	  servers[curserver] = openConnection(req->Source,
					      servernames[curserver]);

      if (servers[curserver] != req->Source)
	{
	  validaddress = 1;
	  req->Destination = servers[curserver];

	  patient = NUMRETRIES;
	  while (patient)
	    {
	      E(Connect_SendPacket(req));
	      if (Connect_Wait(repl, RETRY))
		{
		  if (Error == CONNECT_TIMEOUT)
		    {
		      Error_Pop();
		      patient--;
		      continue;
		    }
		  else
		    {
		      ED(CHECK);
		      exit(3);
		    }
		}
	      else
		return 0;
	    }
	}

      curserver++;
      if (servernames[curserver] == NULL)
	{
	  curserver = 0;
	  if (startserver == curserver)
	    return 1;
	}
    }
}
