/* tcp.cpp
 *
 * Copyright (C) DFS Deutsche Flugsicherung (2004, 2005). 
 * All Rights Reserved.
 *
 * TCP server functions for IPv4
 *
 * Version 0.2
 * adr 11sep2005 TCP client
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

 /* Socket io */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <assert.h>
#include <sys/types.h>
#include <netdb.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/errno.h>
#include <fcntl.h>

/* error handling */
#include <assert.h>

#include <signal.h>

#include "intercomd.h"

int tcp_server_init(int port)
/* open the server (listen) port - do this one time*/
{
  int fd = socket(PF_INET, SOCK_STREAM, 0);
  assert_errno(fd >= 0);

  struct sockaddr_in sock;
  memset((char *) &sock, 0, sizeof(sock));
  sock.sin_family = AF_INET;
  sock.sin_addr.s_addr = htonl(INADDR_ANY);
  sock.sin_port = htons(port);
  if (bind(fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) {
    fprintf(stderr, "tcp_recv_init(): bind() failed\n");
    exit(2);
  }

  int ret = listen(fd, 1);
  assert_errno(ret >= 0);

  return fd;
}

#define SA  struct sockaddr

int
socket_async(char *addr, int port) {
/* Tcl Prozedur socket -async */
/* in addr: Server IP-Adresse auf den gehoert wird */
/* in port: Server TCP-Port auf den gehoert wird  */
  struct sockaddr_in	servaddr;
  struct hostent	*foreign_host;
  int                   sockfd;
  int                   flags;

  /* Siehe Stevens[1998] Kap. 15.4 oder man 2 connect */
  
  /* init local part */
  sockfd = socket(AF_INET, SOCK_STREAM, 0);
  if (sockfd < 0) {
    syslog(LOG_WARNING, "socket_async(): local socket() failed");  
    return -1;
  }
  if (sockfd >= 64) {
    syslog(LOG_WARNING, "socket_async(): local socket() sockfd >= 64");  
    return -1;
  }

  /* init foreign part */
  memset((char *)&servaddr, 0, sizeof(servaddr));

  foreign_host = gethostbyname(addr);
  if (foreign_host == NULL || foreign_host->h_length == 0) {
    syslog(LOG_WARNING,     
     "socket_async(): gethostbyname(%s) failed", 
     addr);
    return -1;
  }
  memcpy(&servaddr.sin_addr.s_addr, foreign_host->h_addr_list[0], foreign_host->h_length);
  servaddr.sin_family = AF_INET;
  servaddr.sin_port = htons(port);
  
  /* NONBLOCK */
  flags = fcntl(sockfd, F_GETFL, 0);
  fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

  if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) != 0) {
    if (errno != EINPROGRESS) {
      perror("tcl.c::socket_async() connect() failed");
      return -1;
    }
  }
  
  printf("info tcp.cpp::socket_async(): host=%s IP=0x%X Port=%u\n", 
   addr, ntohl(servaddr.sin_addr.s_addr), port);

  return sockfd;
}



int tcp_server_init2(int listen_fd)
/* open the communication (connection) - do this for every client */
{
  // fprintf(stderr, "tcp_server_init2\n");

  // avoid blocking accept() 
  int flags = fcntl(listen_fd, F_GETFL);
  int ret = fcntl(listen_fd, F_SETFL, flags | O_NONBLOCK);
  assert_errno(ret >= 0);

  struct sockaddr_in sock;
  socklen_t socklen = sizeof(sock);
  int fd = accept(listen_fd, (struct sockaddr *) &sock, &socklen);
  assert_errno(fd >= 0);

  return fd;
}
