/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/***************************************************************************
 *            socket.cc
 *
 *  Mon Nov  8 10:49:33 CET 2004
 *  Copyright  2004 Bent Bisballe
 *  deva@aasimon.org
 ****************************************************************************/

/*
 *  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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
#include <config.h>

#include "socket.h"

Socket::Socket(Error* _err)
{
  error = _err;
  connected = false;
  err = 0;
}

Socket::Socket(u_short port, Error* _err)
{
  error = _err;
  connected = false;
  err = 0;

  // create socket
  ssocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 
  // PF_INET: ipv4, PF_INET6: ipv6
  // tcp: IPPROTO_TCP
  // upd: IPPROTO_UDP

  if (ssocket < 0) {
    err = 1;
    char errbuf[] = "Socket: socket() failed!\0";
    if(error) error->pushError(errbuf);
    else perror(errbuf);
  }

  socketaddr.sin_family = AF_INET; // Use "internet protocol" IP
  socketaddr.sin_port = htons(port);  // connect to that port
  socketaddr.sin_addr.s_addr = INADDR_ANY;
  // INADDR_ANY puts your IP address automatically 
}


Socket::~Socket()
{
  //  if(err) perror("Socket: No socket to kill");
  //  printf("Socket: I'm melting...[%d]\n", ssocket);
  if(ssocket >= 0) close(ssocket);  // close server socket
}


Socket Socket::slisten()
{
  Socket s = Socket();

  if(err) {
    char errbuf[] = "Socket: No socket present!\0";
    if(error) error->pushError(errbuf);
    else perror(errbuf);
    return s;
  }
  if(!connected) {
    // bind socket to address specified by "sa" parameter
    err = bind(ssocket, (struct sockaddr*)&socketaddr, sizeof(socketaddr));
    
    if (err) {
      perror("Socket: bind() failed");
      return s;
    }
    
    // start listen for connection - kernel will accept connection 
    // requests (max 5 in queue)
    err = listen(ssocket, 5);
    if(err) {
      char errbuf[] = "Socket: listen() failed!\0";
      if(error) error->pushError(errbuf);
      else perror(errbuf);
      return s;
    }
  }

  // accept new connection and get its connection descriptor
  int csalen = sizeof(s.socketaddr);

  s.ssocket = accept(ssocket, 
                     (struct sockaddr*)&s.socketaddr, 
                     (socklen_t*)&csalen);

  if (s.ssocket < 0) {
    err = 1;
    char errbuf[] = "Socket: accept() failed!\0";
    if(error) error->pushError(errbuf);
    else perror(errbuf);
    return s;
  }

  connected = true;
  s.connected = true;
  return s;
}


int Socket::sconnect(char *ip)
{
  if(err) {
    perror("Socket: No socket present");
    return err;
  }

  // FIXME: gethostbyname()
  socketaddr.sin_addr.s_addr = inet_addr(ip); 
  //inet_aton (ip, &socketaddr.sin_addr);
  
  err = connect(ssocket, (struct sockaddr*)&socketaddr, sizeof(socketaddr));
  if (err) {
    char errbuf[] = "Socket: connect() failed!\0";
    if(error) error->pushError(errbuf);
    else perror(errbuf);
    return err;
  }
  //  fprintf(stderr, "Socket connected\n");
  connected = true;
  return 0;
}


bool Socket::isConnected()
{
  return connected;
}