/*
  eXosip - This is the eXtended osip library.
  Copyright (C) 2002,2003,2004,2005  Aymeric MOIZARD  - jack@atosc.org
  
  eXosip 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.
  
  eXosip 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 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
*/


#ifdef ENABLE_MPATROL
#include <mpatrol.h>
#endif


#include "eXosip2.h"

extern eXosip_t eXosip;

char *
_eXosip_transport_protocol (osip_message_t * msg)
{
  osip_via_t *via;

  via = (osip_via_t *) osip_list_get (&msg->vias, 0);
  if (via == NULL || via->protocol == NULL)
    return NULL;
  return via->protocol;
}

int
_eXosip_find_protocol (osip_message_t * msg)
{
  osip_via_t *via;

  via = (osip_via_t *) osip_list_get (&msg->vias, 0);
  if (via == NULL || via->protocol == NULL)
    return -1;
  else if (0 == osip_strcasecmp (via->protocol, "UDP"))
    return IPPROTO_UDP;
  else if (0 == osip_strcasecmp (via->protocol, "TCP"))
    return IPPROTO_TCP;
  return -1;;
}

int
_eXosip_tcp_find_socket (char *host, int port)
{
  int pos;
  struct eXosip_net *net;

  net = &eXosip.net_interfaces[1];

  for (pos = 0; pos < EXOSIP_MAX_SOCKETS; pos++)
    {
      if (net->net_socket_tab[pos].socket != 0)
        {
          if (0 == osip_strcasecmp (net->net_socket_tab[pos].remote_ip, host)
              && port == net->net_socket_tab[pos].remote_port)
            return net->net_socket_tab[pos].socket;
        }
    }
  return -1;
}

int
_eXosip_tcp_connect_socket (char *host, int port)
{
  int pos;
  struct eXosip_net *net;

  int res;
  struct addrinfo *addrinfo = NULL;
  struct addrinfo *curinfo;
  int sock = -1;

  net = &eXosip.net_interfaces[1];

  for (pos = 0; pos < EXOSIP_MAX_SOCKETS; pos++)
    {
      if (net->net_socket_tab[pos].socket == 0)
        {
          break;
        }
    }

  if (pos == EXOSIP_MAX_SOCKETS)
    return -1;

  res = eXosip_get_addrinfo (&addrinfo, host, port, IPPROTO_TCP);
  if (res)
    return -1;


  for (curinfo = addrinfo; curinfo; curinfo = curinfo->ai_next)
    {
      if (curinfo->ai_protocol && curinfo->ai_protocol != IPPROTO_TCP)
        {
          OSIP_TRACE (osip_trace
                      (__FILE__, __LINE__, OSIP_INFO2, NULL,
                       "eXosip: Skipping protocol %d\n", curinfo->ai_protocol));
          continue;
        }

      sock = (int) socket (curinfo->ai_family, curinfo->ai_socktype,
                           curinfo->ai_protocol);
      if (sock < 0)
        {
#if !defined(_WIN32_WCE)

          OSIP_TRACE (osip_trace
                      (__FILE__, __LINE__, OSIP_INFO2, NULL,
                       "eXosip: Cannot create socket!\n", strerror (errno)));
#endif

          continue;
        }

      if (curinfo->ai_family == AF_INET6)
        {
#ifdef IPV6_V6ONLY
          if (setsockopt_ipv6only (sock))
            {
              close (sock);
              sock = -1;
              OSIP_TRACE (osip_trace
                          (__FILE__, __LINE__, OSIP_INFO2, NULL,
                           "eXosip: Cannot set socket option!\n",
                           strerror (errno)));
              continue;
            }
#endif /* IPV6_V6ONLY */
        }
#if 0
      res = bind (sock, (struct sockaddr *) &net->ai_addr, curinfo->ai_addrlen);
      if (res < 0)
        {
          OSIP_TRACE (osip_trace
                      (__FILE__, __LINE__, OSIP_INFO2, NULL,
                       "eXosip: Cannot bind socket %s\n", strerror (errno)));
          close (sock);
          sock = -1;
          continue;
        }
#endif

      res = connect (sock, curinfo->ai_addr, curinfo->ai_addrlen);
      if (res < 0)
        {
#if !defined(_WIN32_WCE)

          OSIP_TRACE (osip_trace
                      (__FILE__, __LINE__, OSIP_INFO2, NULL,
                       "eXosip: Cannot bind socket node:%s family:%d %s\n",
                       host, curinfo->ai_family, strerror (errno)));
#endif

          close (sock);
          sock = -1;
          continue;
        }

      break;
    }

  freeaddrinfo (addrinfo);

  if (sock > 0)
    {
      net->net_socket_tab[pos].socket = sock;
      osip_strncpy (net->net_socket_tab[pos].remote_ip, host,
                    sizeof (net->net_socket_tab[pos].remote_ip) - 1);
      net->net_socket_tab[pos].remote_port = port;
      return sock;
    }

  return -1;
}


int
eXosip_transport_set (osip_message_t * msg, const char *transport)
{
  osip_via_t *via;

  via = (osip_via_t *) osip_list_get (&msg->vias, 0);
  if (via == NULL || via->protocol == NULL)
    return -1;

  if (0 == osip_strcasecmp (via->protocol, transport))
    return 0;

  osip_free (via->protocol);
  via->protocol = osip_strdup (transport);
  return 0;
}

int
_eXosip_recvfrom (int s, char *buf, int len, unsigned int flags,
                  struct sockaddr *from, socklen_t * fromlen)
{
  int message_size = 0;
  int length_done = 0;
  int real_size = 0;
  int i;
  int extra_data_discarded;

  if (!eXosip.http_port)
    {
      return recvfrom (s, buf, len, flags, from, fromlen);
    }


  /* we get the size of the HTTP data */
  i = recv (eXosip.net_interfaces[0].net_socket, (char *) &(message_size), 4, 0);

  real_size = message_size;
  if (message_size < 0)
    {
      return -1;                /* Connection error? */
    }
  if (message_size == 0)
    {
      buf[0] = '\0';
      return 0;
    }
  if (message_size > len - 1)
    message_size = len - 1;

  length_done = 0;

  i = recv (eXosip.net_interfaces[0].net_socket, buf, message_size, 0);
  length_done = i;

  if (length_done == real_size)
    {
      return length_done;
    }

  if (length_done < message_size)
    {
      /* continue reading up to message_size */
      while (length_done < message_size)
        {
          i =
            recv (eXosip.net_interfaces[0].net_socket, buf + length_done,
                  message_size - length_done, 0);
          length_done = length_done + i;
        }
    }

  extra_data_discarded = length_done;
  while (extra_data_discarded < real_size)
    {
      char buf2[2048];

      /* We have to discard the end of data... up to the next message */
      i = recv (eXosip.net_interfaces[0].net_socket, buf2, 2048, 0);
      extra_data_discarded = extra_data_discarded + i;
    }
  return length_done;
}

int
_eXosip_sendto (int s, const void *buf, size_t len, int flags,
                const struct sockaddr *to, socklen_t tolen)
{
  int i;
  char buf2[10000];

  if (!eXosip.http_port)
    {
      i = sendto (s, buf, len, flags, to, tolen);
      return i;
    }

  memset (buf2, '\0', sizeof (buf2));
  memcpy (buf2, &len, sizeof (int));
  memcpy (buf2 + sizeof (int), buf, len);

  i = send (s, (char *) buf2, len + sizeof (int), 0);   /* use TCP connection to proxy */
  if (i > 0)
    i = i - sizeof (int);

  return i;
}


syntax highlighted by Code2HTML, v. 0.9.1