#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>

#include "express.h"

#ifndef INADDR_NONE
#define INADDR_NONE	0xffffffff
#endif


extern int	errno;
/*
extern char	*sys_errlist[];
*/

/*
u_short htons();
u_long inet_addr();
*/

/*
 * connectsock - allocate & connect a socket using TCP or UDP
 */
int connectsock(char *host, char *service, char *protocol)
{
   struct hostent	*phe;
   struct servent	*pse;
   struct protoent *ppe;
   struct sockaddr_in sin;
   int s,type;
   char errmsg[100];
   
   bzero((char *)&sin, sizeof(sin));
   sin.sin_family = AF_INET;

   /* Map service name to port number */
   if ((pse = getservbyname(service, protocol)) != NULL)
     sin.sin_port = pse->s_port;
   else if ((sin.sin_port = htons((u_short)atoi(service)))==0) {
      sprintf(errmsg, "can't get \"%s\" service entry\n", service);
      perror(errmsg);
      cleanexit(1);
   }
   
   /* Map host name to IP address, allowing for dotted decimal */
   if((phe = gethostbyname(host)) != NULL)
     bcopy(phe->h_addr, (char *)&sin.sin_addr, phe->h_length);
   else if ( (sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE ) {
      sprintf(errmsg, "can't get \"%s\" host entry\n", host);
      perror(errmsg);
      cleanexit(1);
   }
   
   /* Map protocol name to protocol number */
   if((ppe = getprotobyname(protocol))==0) {
      sprintf(errmsg, "can't get \"%s\" protocol entry\n", protocol);
      perror(errmsg);
      cleanexit(1);
   }
   
   /* Use protocol to choose socket type */
   if(strcmp(protocol, "udp")==0)
     type = SOCK_DGRAM;
   else
     type = SOCK_STREAM;
   
   /* Allocate a socket */
   s = socket(PF_INET, type, ppe->p_proto);
   if(s < 0) {
      sprintf(errmsg, "can't create socket: %s\n", sys_errlist[errno]);
      perror(errmsg);
      cleanexit(1);
   }
   
   /* Connect the socket */
   if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) , 0) {
      sprintf(errmsg, "can't connect to %s.%s: %s\n", host, service,
	      sys_errlist[errno]);
      perror(errmsg);  
      cleanexit(1);
   }

   return s;
}


/*
 * connectsockproto - allocate & connect a socket using TCP or UDP
 * using known port number
 */
int connectsockproto(char *host, int proto, char *protocol)
{
   struct hostent	*phe;
   /*struct servent	*pse;*/
   struct protoent *ppe;
   struct sockaddr_in sin;
   int s,type;
   char errmsg[100];
   
#ifdef DEBUG
  fprintf(stderr, "connectsockproto: 1\n");
#endif

   bzero((char *)&sin, sizeof(sin));
   sin.sin_family = AF_INET;
   
#ifdef DEBUG
  fprintf(stderr, "connectsockproto: 2\n");
#endif

   /* Map service name to port number */
   if ((sin.sin_port = htons((u_short)proto))==0) {
       sprintf(errmsg, "can't cast \"%d\" service entry (yeah right...)\n", proto);
      perror(errmsg);
      cleanexit(1);
   }
   
#ifdef DEBUG
  fprintf(stderr, "connectsockproto: 3\n");
#endif

   /* Map host name to IP address, allowing for dotted decimal */
   if((phe = gethostbyname(host)) != NULL)
     bcopy(phe->h_addr, (char *)&sin.sin_addr, phe->h_length);
   else if ( (sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE ) {
      sprintf(errmsg, "can't get \"%s\" host entry\n", host);
      perror(errmsg);
      cleanexit(1);
   }
   
#ifdef DEBUG
  fprintf(stderr, "connectsockproto: 4\n");
#endif

   /* Map protocol name to protocol number */
   if((ppe = getprotobyname(protocol))==0) {
      sprintf(errmsg, "can't get \"%s\" protocol entry\n", protocol);
      perror(errmsg);
      cleanexit(1);
   }
   
#ifdef DEBUG
  fprintf(stderr, "connectsockproto: 5\n");
#endif

   /* Use protocol to choose socket type */
   if(strcmp(protocol, "udp")==0)
     type = SOCK_DGRAM;
   else
     type = SOCK_STREAM;
   
#ifdef DEBUG
  fprintf(stderr, "connectsockproto: 6\n");
#endif

   /* Allocate a socket */
   s = socket(PF_INET, type, ppe->p_proto);
   if(s < 0) {
      sprintf(errmsg, "can't create socket: %s\n", sys_errlist[errno]);
      perror(errmsg);
      cleanexit(1);
   }
   
#ifdef DEBUG
  fprintf(stderr, "connectsockproto: 7\n");
#endif

   /* Connect the socket */
   if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) , 0) {
      sprintf(errmsg, "can't connect to %s.%d: %s\n", host, proto,
	      sys_errlist[errno]);
      perror(errmsg);
      cleanexit(1);
   }
   
#ifdef DEBUG
  fprintf(stderr, "connectsockproto: 8 (end)\n");
#endif

   return s;
}

/* connectTCP.c */

int connectTCP(char *host, char *service)
{
   return connectsock(host, service, "tcp");
}

int connectTCPproto(char *host, int proto)
{
#ifdef DEBUG
  printf("TCP connecting to %s port %d\n", host, proto);
#endif
#ifdef DEBUG
  printf("TCP connecting to %s port %d\n", host, proto);
#endif
   return connectsockproto(host, proto, "tcp");
}

