/* 
 * Thomas Pantzer: netutils.cc, v0.1b  28.1.98 18:6 
 * 
 * 
 * Copyright 1998 by Thomas Pantzer
 * 
 * Permission to use, copy, modify, and distribute this software for noncommercial 
 * use and without fee is hereby granted, provided that the above copyright notice 
 * appear in all copies and that both that copyright notice and this permission 
 * notice appear in supporting documentation, and that the name of the Author not be 
 * used in advertising or publicity pertaining to distribution of the software 
 * without specific, written prior permission. The Author makes no representations about
 * the suitability of this software for any purpose.  It is provided "as is" 
 * without expressed or implied warranty. 
 * 
 * 
 * pantec@aix520.informatik.uni-leipzig.de   (Thomas Pantzer) 
 * 
 */




#include "netutils.h"
#include "utils.h"
#include "copyright.h"



void hostname_str(struct sockaddr_in *Client,char *result)
{
  unsigned long int i,j;
  unsigned char k,l,m,n;
  char st[256],st2[256];
  struct hostent *remote;

  i=Client->sin_addr.s_addr / 65536;
  j=Client->sin_addr.s_addr % 65536;
  k=i / 256;
  l=i % 256;
  m=j / 256;
  n=j % 256;
  
//  sprintf(result,"%d.%d.%d.%d",n,m,l,k);

#if (sun || hpux)
  sprintf(st,"%d.%d.%d.%d",k,l,m,n);
  sprintf(st2,"%c%c%c%c",k,l,m,n);
#else
  sprintf(st,"%d.%d.%d.%d",n,m,l,k);
  sprintf(st2,"%c%c%c%c",n,m,l,k);
#endif    

#ifdef DEBUG_SOCKETS  
  fprintf(stderr,"remote address: %s\n",st); 
  fprintf(stderr,"remote port: %d\n",Client->sin_port);
#endif  

  remote = gethostbyaddr(st2,strlen(st2),AF_INET); 
  if (remote == NULL)
     {
#ifdef DEBUG_SOCKETS   
      ErrorMsg("gethostbyaddr");
#endif  
      sprintf(result,"%s:%d",st,Client->sin_port);
     } 
   else  
     {
#ifdef DEBUG_SOCKETS
      fprintf(stderr,"remote name: %s\n",remote->h_name);
#endif      
      sprintf(result,"%s:%d",remote->h_name,Client->sin_port);
     } 
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// zum bestimmen der Portnummer aus /etc/services (falls vorhanden)
//________________________________________________________________
int GetTCPPort(char proto[64], int defport)
{
  struct servent *MyService;

  MyService = getservbyname(proto,"tcp");

  if (MyService != NULL)
       {
#ifdef DEBUG_SOCKETS
        fprintf(stderr,"using port %d from default service for %s\n",
                  ntohs(MyService->s_port),MyService->s_name);
#endif  
        return ntohs(MyService->s_port);  
       } 
     else 
       return defport; 
}  

int clConnect(char *hname, int port_num, char may_fail)
{
  struct hostent *HostName; 

  struct sockaddr_in ServerAddr;
  int _Sock = -1;
  char ST[256];

  HostName = gethostbyname(hname);
 
  if (HostName == (struct hostent *) 0)
     {
#ifdef DEBUG_SOCKETS   
       fprintf(stderr,"gethostbyname(%s): failed\b\n",ST);
#endif  
       perror("gethostbyname"); 	
       if (may_fail == false)
	  exit(2);
	else
	  return -1;
     }
  
  ServerAddr.sin_port=htons(port_num);
  ServerAddr.sin_family=AF_INET;
  ServerAddr.sin_addr.s_addr=*(unsigned long int *)HostName->h_addr;
  
  _Sock = socket(AF_INET,SOCK_STREAM,0);
  if (_Sock==-1)
   {
     if (may_fail == false)
	{
	 perror("socket()");	
	 exit(3);
	}	
      else
	return -1;			
   }
   
  if (connect(_Sock,(struct sockaddr *)&ServerAddr,sizeof(ServerAddr))==-1)
   {
     if (may_fail == false)
	{
	 perror("connect()"); 	
	 exit(4);
	} 
      else
	{
	 close(_Sock);
	 return -1;		
	}	
   }

#ifdef DEBUG_SOCKETS
  fprintf(stderr,"assigning socket=%d\n",_Sock);
#endif   
  return _Sock; 
}

int clConnect_to(char *hname, int port_num)
{
	return clConnect(hname,port_num,false);
}


void ShutDown(int sd)
{
   struct linger L;

   L.l_onoff = 0;
//   L.l_linger = LINGER_TIMEOUT;    
   L.l_linger = 0;
  
#if (linux || hpux)  
   if (setsockopt(sd,SOL_SOCKET,SO_LINGER,&L,sizeof(struct linger)) == -1)
#else
  #if (sun || AIX)
   if (setsockopt(sd,SOL_SOCKET,SO_LINGER,(char *)&L,sizeof(struct linger)) == -1)
  #else
      #error edit typecast of setsockopt for your system
  #endif   
#endif

#ifdef DEBUG_SOCKETS   
      ErrorMsg("setsockopt()");  
#else
	;
#endif  
//   close(sd);
   int rt = shutdown(sd,1);
   if (rt < 0)
      {
       switch(errno)
         {
	  case ENOTCONN:
	    break;

	  default:
	    perror("shutdown(1)\n"); 	
	    break;
	 }	
      }	

   int fflag = fcntl(sd,F_GETFL);

   fflag &= ~(O_NDELAY | O_NONBLOCK);
   fcntl(sd,F_SETFL,fflag);

   char *dummy = new char [64*1024];
   read(sd,dummy,(64*1024));	
   delete dummy;
	
   fcntl(sd,F_SETFL,O_NONBLOCK|O_NDELAY);  // get it faster to shut up
   rt = shutdown(sd,2);
   if (rt < 0)
      {
       switch(errno)
         {
	  case ENOTCONN:
	    break;

	  default:
	    perror("shutdown(2)\n"); 	
	    break;
	 }	
      }	


//   usleep(50000);

   close(sd);
}


int svAccept(int Sock)
{
   int peer;
   int CNameLen;
   struct sockaddr_in ClientAddr;
   char st[256];

   CNameLen = sizeof(sockaddr_in);
   peer = accept(Sock,(struct sockaddr *)&ClientAddr,&CNameLen);
   
   hostname_str(&ClientAddr,&st[0]);
#ifdef DEBUG_SOCKETS   
   fprintf(stderr,"connect from %s\n",st);
#endif
   return peer;
}

int svListen(int portx)
{
   return svListen(portx,true);
}

int svListen(int port, char fail)
{
   int L;
   struct sockaddr_in ServerAddr;

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

   L = socket(AF_INET,SOCK_STREAM,0);
   if ((L == -1) && (fail==true))
      {
//#ifdef DEBUG_SOCKETS   
       ErrorMsg("socket()");
//#endif  
       exit(2);
      } 

   if ((bind(L,(struct sockaddr *)&ServerAddr,sizeof(ServerAddr))==-1) && (fail ==true))
      {
//#ifdef DEBUG_SOCKETS   
       ErrorMsg("bind()");
//#endif  
       exit(3); 
      }
  
   if ((listen(L,1) == -1) && (fail == true))
      {
//#ifdef DEBUG_SOCKETS   
       ErrorMsg("listen()");
//#endif  
       exit(4);
      }

//   fcntl(L,F_SETFL,O_NONBLOCK);
   
   return L;
}



