#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

#include "inetlib.h"
/* ======================================================================== */

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


int connectUDP ( char * host, char * service )
{
  return connectsock (host, service, "udp");
}

/* ------------------------------------------------------------------------ 
   CONNECTSOCK - Connect socket
   Returns: 	Socket number,
		-1 failed to get service name (errno),
		-2 Cannot get host name (errno),
		-3 failed to get protocol name (errno),
		-4 failed to create socket,
		-5 failed to connect socket.
*/
int connectsock (char * host, char * service, const char * protocol)
{
  struct hostent *phe;
  struct servent *pse;
  struct protoent *ppe;
  struct sockaddr_in sin;
  int s, type;

  memset (&sin, 0, sizeof(sin));
  sin.sin_family = AF_INET;
  
  /* map service name to port number */
  if( (pse = getservbyname (service, protocol)) != 0 )
    sin.sin_port = pse->s_port;
  else if ( (sin.sin_port = htons((u_short) atoi(service))) == 0) {
    return -1;
  };

  /* map host name to ip address, allowing dotted decimal */
  if( (phe = gethostbyname (host)) != 0 )
    memcpy ( (char*) &sin.sin_addr, phe->h_addr, phe->h_length);
  else if ( (sin.sin_addr.s_addr = inet_addr(host)) == (in_addr_t)-1)
    return -2;

  /* map protocol name to protocol number */
  if ( (ppe = getprotobyname (protocol))== 0) {
    return -3;
  };

  /* use protocol to choose a 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) {
    return -4;
  };

  /* connect the socket */
  if (connect (s, (struct sockaddr *)(void*)&sin, sizeof (sin)) < 0) {
    close(s);
    return -5;
  };

  return s;
}

/* ======================================================================== */


int passiveUDP (char * service, int qlen)
{
  return passivesock (service, "udp", qlen);
}

int passiveTCP (char * service, int qlen)
{
  return passivesock (service, "tcp", qlen);
}

/* ------------------------------------------------------------------------ 
   PASSIVESOCK - creates a passive socket
   Returns: 	Socket number,
		-1 failed to create socket, ref to errno,
		-2 Cannot get service entry,
		-3 Cannot get protocol entry,
		-4 failed to bind, ref to errno,
		-5 listen failed, ref to errno.
*/

int passivesock (char * service, const char * protocol, int qlen)
{
  struct servent *pse;
  struct protoent *ppe;
  struct sockaddr_in sin;
  int s, type;

  memset ((char *) &sin, 0, sizeof (sin));
  sin.sin_family = AF_INET;
  sin.sin_addr.s_addr = htonl(INADDR_ANY);
  if( (pse = getservbyname (service, protocol)) != 0 )
    sin.sin_port = (unsigned short int) pse->s_port; 
  else
    if ( (sin.sin_port = htons ((u_short) atoi (service))) == 0) {
      return -2;
    };

  if ( ( ppe = getprotobyname (protocol)) == 0) {
      return -3; 
  };

  if (strcmp (protocol, "udp") == 0)  
    type = SOCK_DGRAM;
  else 
    type = SOCK_STREAM;

  s = socket (PF_INET, type, ppe->p_proto);
  if ( s < 0) {
    return -1;
  };

  if (bind (s, (struct sockaddr *)(void*)&sin, sizeof (sin)) < 0) {
    close(s);
    return -4;
  };

  if (type == SOCK_STREAM && listen (s, qlen) < 0) {
    close(s);
    return -5;
  };

  return s;
}


