SCTP Discussions

Text archives Help


[SCTP-Discussion] sctplib-1.0.8 on QNX Neutrino RTOS 6.4.1: fix to adaptation.c


Chronological Thread 
  • From: amedeo bonfiglio <amedeo.bonfiglio AT rcm.inet.it>
  • To: sctp-discussion AT sctp.de
  • Subject: [SCTP-Discussion] sctplib-1.0.8 on QNX Neutrino RTOS 6.4.1: fix to adaptation.c
  • Date: Sat, 14 Nov 2009 11:21:44 +0100
  • List-archive: <http://lists.franken.de/pipermail/sctp-discussion>
  • List-id: SCTP Discussions <sctp-discussion.sctp.de>

Hi all,
I am using sctplib-1.0.8 on QNX Neutrino RTOS 6.4.1.
I want to let you know of a little fix I had to make to the function adl_gatherLocalAddresses() within the file adaptation.c (the original version did not work).
I had modified the part which gathers the master address information following the hints as suggested in http://www.qnx.com/developers/docs/6.4.0/io-pkt_en/user_guide/migrating.html#Coexistence.

I attach my version of the file adaptation.c.
May be it it useful to some one else.

Below are the differences form the original file.

Regards,
Amedeo Bonfiglio


diff adaptation.c adaptation.c-orig

2170,2172d2169
< *
< * Changed by Amedeo Bonfiglio as shown in
< * http://www.qnx.com/developers/docs/6.4.0/io-pkt_en/user_guide/migrating.html#Coexistence
2329,2343c2326,2333
< // amedeo+
< if (ifrequest->ifr_addr.sa_len + IFNAMSIZ > sizeof(struct ifreq))
< pos += ifrequest->ifr_addr.sa_len + IFNAMSIZ;
< else
< pos += sizeof(struct ifreq);
<
< // amedeo-
< //pos += (ifrequest->ifr_addr.sa_len + sizeof(ifrequest->ifr_name));
< //
< //if (ifrequest->ifr_addr.sa_len == 0) {
< // /* if the interface has no address then you must
< // * skip at a minium a sockaddr structure
< // */
< // pos += sizeof(struct sockaddr);
< //}
---
> pos += (ifrequest->ifr_addr.sa_len + sizeof(ifrequest->ifr_name));
>
> if (ifrequest->ifr_addr.sa_len == 0) {
> /* if the interface has no address then you must
> * skip at a minium a sockaddr structure
> */
> pos += sizeof(struct sockaddr);
> }
2436,2450c2426,2433
< // amedeo+
< if (ifrequest->ifr_addr.sa_len + IFNAMSIZ > sizeof(struct ifreq))
< pos += ifrequest->ifr_addr.sa_len + IFNAMSIZ;
< else
< pos += sizeof(struct ifreq);
<
< // amedeo-
< //pos += (ifrequest->ifr_addr.sa_len + sizeof(ifrequest->ifr_name));
< //
< //if (ifrequest->ifr_addr.sa_len == 0){
< // /* if the interface has no address then you must
< // * skip at a minium a sockaddr structure
< // */
< // pos += sizeof(struct sockaddr);
< //}
---
> pos += (ifrequest->ifr_addr.sa_len + sizeof(ifrequest->ifr_name));
>
> if (ifrequest->ifr_addr.sa_len == 0){
> /* if the interface has no address then you must
> * skip at a minium a sockaddr structure
> */
> pos += sizeof(struct sockaddr);
> }


/* $Id: adaptation.c 2093 2009-01-15 10:19:14Z dreibh $
 * --------------------------------------------------------------------------
 *
 *           //=====   //===== ===//=== //===//  //       //   //===//
 *          //        //         //    //    // //       //   //    //
 *         //====//  //         //    //===//  //       //   //===<<
 *              //  //         //    //       //       //   //    //
 *       ======//  //=====    //    //       //=====  //   //===//
 *
 * ---------------A SCTP implementation according to RFC 4960 ---------------
 *
 * Copyright (C) 2000 by Siemens AG, Munich, Germany.
 * Copyright (C) 2001-2004 Andreas Jungmaier
 * Copyright (C) 2004-2009 Thomas Dreibholz
 *
 * Acknowledgements:
 * Realized in co-operation between Siemens AG and the University of
 * Duisburg-Essen, Institute for Experimental Mathematics, Computer
 * Networking Technology group.
 * This work was partially funded by the Bundesministerium fuer Bildung und
 * Forschung (BMBF) of the Federal Republic of Germany
 * (Förderkennzeichen 01AK045).
 * The authors alone are responsible for the contents.
 *
 * 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 3 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Contact: sctp-discussion AT sctp.de
 *          dreibh AT iem.uni-due.de
 *          tuexen AT fh-muenster.de
 *          andreas.jungmaier AT web.de
 */

#include "adaptation.h"
#include "timer_list.h"

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


#ifndef WIN32
   #include <sys/time.h>
   #include <netinet/in_systm.h>
   #include <netinet/ip.h>
   #include <netdb.h>
   #include <arpa/inet.h>      /* for inet_ntoa() under both SOLARIS/LINUX */
   //-amedeo: #include <sys/errno.h>
   #include <sys/uio.h>        /* for struct iovec */
   #include <sys/param.h>
   #include <sys/ioctl.h>
   #include <netinet/tcp.h>
   #include <net/if.h>
#ifdef SCTP_OVER_UDP
   #include <netinet/udp.h>
#endif
#else
    #include <winsock2.h>
    #include <WS2tcpip.h>

    #include <sys/timeb.h>
    #define ADDRESS_LIST_BUFFER_SIZE        4096
    struct ip
    {
        unsigned char ip_verlen;
       unsigned char ip_tos;        /* type of service */
        u_short ip_len;             /* total length */
        u_short ip_id;              /* identification */
        u_short ip_off;             /* fragment offset field */
        unsigned char ip_ttl;       /* time to live */
        unsigned char ip_p;            /* protocol */
        u_short ip_sum;             /* checksum */
        struct in_addr ip_src, ip_dst; /* source and dest address */
    };

#endif

#ifdef HAVE_IPV6
    #if defined (LINUX)
        #include <netinet/ip6.h>
    #else
        /* include files for IPv6 header structs */
    #endif
#endif

#if defined (LINUX)
    #define LINUX_PROC_IPV6_FILE "/proc/net/if_inet6"
    #include <asm/types.h>
    #include <linux/rtnetlink.h>
#else /* this may not be okay for SOLARIS !!! */
#ifndef WIN32
    #define USES_BSD_4_4_SOCKET
    #include <net/if.h>
    #include <net/if_dl.h>
    #include <net/if_types.h>
    #include <net/route.h>
#ifndef SOLARIS
    //-amedeo: #include <net/if_var.h>
    //-amedeo: #include <machine/param.h>
    #define ROUNDUP(a, size) (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
    #define NEXT_SA(ap) ap = (struct sockaddr *) \
        ((caddr_t) ap + (ap->sa_len ? ROUNDUP(ap->sa_len, sizeof (u_long)) : sizeof(u_long)))
#else
   #include <sys/sockio.h>
   #define NEXT_SA(ap) ap = (struct sockaddr *) ((caddr_t) ap + sizeof(struct sockaddr))
   #define RTAX_MAX RTA_NUMBITS
   #define RTAX_IFA 5
   #define _NO_SIOCGIFMTU_
#endif
#endif
#endif

#define     IFA_BUFFER_LENGTH   1024

#ifndef IN_EXPERIMENTAL
#define  IN_EXPERIMENTAL(a)   ((((int) (a)) & 0xf0000000) == 0xf0000000)
#endif

#ifndef IN_BADCLASS
#define  IN_BADCLASS(a)    IN_EXPERIMENTAL((a))
#endif

#ifdef HAVE_SYS_POLL_H
    #include <sys/poll.h>
#else
    #define POLLIN     0x001
    #define POLLPRI    0x002
    #define POLLOUT    0x004
    #define POLLERR    0x008
#endif

#ifdef LIBRARY_DEBUG
 #define ENTER_TIMER_DISPATCHER printf("Entering timer dispatcher.\n"); fflush(stdout);
 #define LEAVE_TIMER_DISPATCHER printf("Leaving  timer dispatcher.\n"); fflush(stdout);
 #define ENTER_EVENT_DISPATCHER printf("Entering event dispatcher.\n"); fflush(stdout);
 #define LEAVE_EVENT_DISPATCHER printf("Leaving  event dispatcher.\n"); fflush(stdout);
#else
 #define ENTER_TIMER_DISPATCHER
 #define LEAVE_TIMER_DISPATCHER
 #define ENTER_EVENT_DISPATCHER
 #define LEAVE_EVENT_DISPATCHER
#endif


#define POLL_FD_UNUSED     -1
#define NUM_FDS     20

#define    EVENTCB_TYPE_SCTP       1
#define    EVENTCB_TYPE_UDP        2
#define    EVENTCB_TYPE_USER       3
#define    EVENTCB_TYPE_ROUTING    4


#ifdef SCTP_OVER_UDP
int dummy_sctp_udp;
int dummy_sctpv6_udp;

guint32 inet_checksum(const void* ptr, size_t count)
{
   guint16* addr = (guint16*)ptr;
   guint32  sum  = 0;

   while(count > 1)  {
     sum += *(guint16*)addr++;
     count -= 2;
   }

   if(count > 0) {
      sum += *(unsigned char*)addr;
   }

   while(sum>>16) {
      sum = (sum & 0xffff) + (sum >> 16);
   }

   return(~sum);
}
#endif


/**
 *  Structure for callback events. The function "action" is called by the event-handler,
 *  when an event occurs on the file-descriptor.
 */
struct event_cb
{
    int sfd;
    int eventcb_type;
    /* pointer to possible arguments, associations etc. */
    void *arg1;
    void *arg2;
    void (*action) ();
    void* userData;
};

struct data {
   char* dat;
   int   len;
   void (*cb)();
};

#ifdef HAVE_RANDOM
static long rstate[2];
#endif

#ifdef WIN32
struct input_data {
    DWORD len;
    char buffer[1024];
    HANDLE event, eventback;
};



static int fds[NUM_FDS];
static int fdnum;
HANDLE            hEvent, handles[2];
static HANDLE  stdin_thread_handle;
WSAEVENT       stdinevent;
static struct input_data   idata;
#endif

unsigned int
adl_random(void)
{
#ifdef HAVE_RANDOM
    return (unsigned int) random();
#else
    return (unsigned int)rand();
#endif
}

/*
 * An extended poll() implementation based on select()
 *
 * During the select() call, another thread may change the FD list,
 * a revision number keeps track that results are only reported
 * when the FD has already been registered before select() has
 * been called. Otherwise, the event will be reported during the
 * next select() call.
 * This solves the following problem:
 * - Thread #1 registers user callback for socket n
 * - Thread #2 starts select()
 * - A read event on socket n occurs
 * - extendedPoll() returns
 * - Thread #2 sends a notification (e.g. using pthread_condition) to thread #1
 * - Thread #2 again starts select()
 * - Since Thread #1 has not yet read the data, there is a read event again
 * - Now, the thread scheduler selects the next thread
 * - Thread #1 now gets CPU time, deregisters the callback for socket n
 *      and completely reads the incoming data. There is no more data to read!
 * - Thread #1 again registers user callback for socket n
 * - Now, thread #2 gets the CPU again and can send a notification
 *      about the assumed incoming data to thread #1
 * - Thread #1 gets the read notification and tries to read. There is no
 *      data, so the socket blocks (possibily forever!) or the read call
 *      fails.
 */

static long revision = 0;

struct extendedpollfd {
   int       fd;
   short int events;
   short int revents;
   long      revision;
};

int extendedPoll(struct extendedpollfd* fdlist,
                 int*                   count,
                 int                    time,
                 void                   (*lock)(void* data),
                 void                   (*unlock)(void* data),
                 void*                  data)
{
   struct timeval    timeout;
   struct timeval*   to;
   fd_set            readfdset;
   fd_set            writefdset;
   fd_set            exceptfdset;
   int               fdcount;
   int               n;
   int               ret;
   int i;

   if(time < 0) {
      to = NULL;
   }
   else {
      to = &timeout;
      timeout.tv_sec  = time / 1000;
      timeout.tv_usec = (time % 1000) * 1000;
   }


   /* Initialize structures for select() */
   fdcount = 0;
   n = 0;
   FD_ZERO(&readfdset);
   FD_ZERO(&writefdset);
   FD_ZERO(&exceptfdset);

   for(i = 0; i < *count; i++) {
      if(fdlist[i].fd < 0) {
         continue;
      }
      n = MAX(n,fdlist[i].fd);
      if(fdlist[i].events & (POLLIN|POLLPRI)) {
         FD_SET(fdlist[i].fd, &readfdset);
      }
      if(fdlist[i].events & POLLOUT) {
         FD_SET(fdlist[i].fd, &writefdset);
      }
      if(fdlist[i].events & (POLLIN|POLLOUT)) {
         FD_SET(fdlist[i].fd, &exceptfdset);
      }
      fdcount++;
   }


   if(fdcount == 0) {
      ret = 0;
   }
   else {
      /*
       * Set the revision number of all entries to the current revision.
       */
      for(i = 0; i < *count; i++) {
         fdlist[i].revision = revision;
      }

      /*
       * Increment the revision number by one -> New entries made by
       * another thread during select() call will get this new revision number.
       */
      revision++;


      if(unlock) {
         unlock(data);
      }

      ret = select(n + 1, &readfdset, &writefdset, &exceptfdset, to);

      if(lock) {
         lock(data);
      }


      for(i = 0; i < *count; i++) {
         fdlist[i].revents = 0;
         if(fdlist[i].revision >= revision) {
            FD_CLR(fdlist[i].fd, &readfdset);
            FD_CLR(fdlist[i].fd, &writefdset);
            FD_CLR(fdlist[i].fd, &exceptfdset);
         }
      }

      if(ret > 0) {
         for(i = 0; i < *count; i++) {
            fdlist[i].revents = 0;
            /*
             * If fdlist's revision is equal the current revision, then the fdlist entry
             * has been added by another thread during the poll() call. If this is the
             * case, skip the results here (they will be reported again when select()
             * is called the next time).
             */
            if(fdlist[i].revision < revision) {
               if((fdlist[i].events & POLLIN) && FD_ISSET(fdlist[i].fd, &readfdset)) {
                  fdlist[i].revents |= POLLIN;
               }
               if((fdlist[i].events & POLLOUT) && FD_ISSET(fdlist[i].fd, &writefdset)) {
                  fdlist[i].revents |= POLLOUT;
               }
               if((fdlist[i].events & (POLLIN|POLLOUT)) && FD_ISSET(fdlist[i].fd, &exceptfdset)) {
                  fdlist[i].revents |= POLLERR;
               }
            }
         }
      }
   }

   return(ret);
}



/* a static counter - for stats we should have more counters !  */
static unsigned int number_of_sendevents = 0;
/* a static receive buffer  */
static unsigned char rbuf[MAX_MTU_SIZE + 20];
/* a static value that keeps currently treated timer id */
static unsigned int current_tid = 0;


static struct extendedpollfd poll_fds[NUM_FDS];
static int num_of_fds = 0;

static int sctp_sfd = -1;       /* socket fd for standard SCTP port....      */

#ifdef HAVE_IPV6
static int sctpv6_sfd = -1;
#endif

/* will be added back later....
   static int icmp_sfd = -1;  */      /* socket fd for ICMP messages */

static struct event_cb *event_callbacks[NUM_FDS];

/**
 *  converts address-string (hex for ipv6, dotted decimal for ipv4
 *  to a sockunion structure
 *  @return 0 for success, else -1.
 */
int adl_str2sockunion(guchar * str, union sockunion *su)
{
    int ret;

    memset((void*)su, 0, sizeof(union sockunion));

#ifndef WIN32
   ret = inet_aton((const char *)str, &su->sin.sin_addr);
#else
   if ((su->sin.sin_addr.s_addr = inet_addr(str)) == INADDR_NONE)
      ret=0;
   else {
      ret=1;
   }
#endif
    if (ret > 0) {              /* Valid IPv4 address format. */
        su->sin.sin_family = AF_INET;
#ifdef HAVE_SIN_LEN
        su->sin.sin_len = sizeof(struct sockaddr_in);
#endif                          /* HAVE_SIN_LEN */
        return 0;
    }
#ifdef HAVE_IPV6
    ret = inet_pton(AF_INET6, (const char *)str, &su->sin6.sin6_addr);
    if (ret > 0) {              /* Valid IPv6 address format. */
        su->sin6.sin6_family = AF_INET6;
#ifdef SIN6_LEN
        su->sin6.sin6_len = sizeof(struct sockaddr_in6);
#endif                          /* SIN6_LEN */
        return 0;
    }
#endif                          /* HAVE_IPV6 */
    return -1;
}

int adl_sockunion2str(union sockunion *su, guchar * buf, size_t len)
{
    if (su->sa.sa_family == AF_INET){
        if (len > 16) len = 16;
        strncpy((char *)buf, inet_ntoa(su->sin.sin_addr), len);
        return(1);
    }
#ifdef HAVE_IPV6
    else if (su->sa.sa_family == AF_INET6) {
        if (inet_ntop(AF_INET6, &su->sin6.sin6_addr, (char *)buf, len)==NULL) return 0;
        return (1);
    }
#endif                          /* HAVE_IPV6 */
    return 0;
}

boolean adl_equal_address(union sockunion * a, union sockunion * b)
{
#ifdef HAVE_IPV6
   union sockunion        my_a;
   union sockunion        my_b;
   const union sockunion* one;
   const union sockunion* two;
   unsigned int           count;

#if defined __APPLE__ || defined FreeBSD
#define s6_addr32 __u6_addr.__u6_addr32
#endif

   if(a->sa.sa_family == AF_INET) {
      my_a.sin6.sin6_family = AF_INET6;
      my_a.sin6.sin6_port   = a->sin.sin_port;
      my_a.sin6.sin6_addr.s6_addr32[0] = 0x00000000;
      my_a.sin6.sin6_addr.s6_addr32[1] = 0x00000000;
      my_a.sin6.sin6_addr.s6_addr32[2] = 0x00000000;
      my_a.sin6.sin6_addr.s6_addr32[3] = a->sin.sin_addr.s_addr;
      one = &my_a;
   }
   else {
      one = a;
   }
   if(b->sa.sa_family == AF_INET) {
      my_b.sin6.sin6_family = AF_INET6;
      my_b.sin6.sin6_port   = b->sin.sin_port;
      my_b.sin6.sin6_addr.s6_addr32[0] = 0x00000000;
      my_b.sin6.sin6_addr.s6_addr32[1] = 0x00000000;
      my_b.sin6.sin6_addr.s6_addr32[2] = 0x00000000;
      my_b.sin6.sin6_addr.s6_addr32[3] = b->sin.sin_addr.s_addr;
      two = &my_b;
   }
   else {
      two = b;
   }
#else
   const union sockunion* one = a;
   const union sockunion* two = b;
#endif

    switch (sockunion_family(one)) {
    case AF_INET:
        if (sockunion_family(two) != AF_INET)
            return FALSE;
        return (sock2ip(one) == sock2ip(two));
        break;
#ifdef HAVE_IPV6
    case AF_INET6:
        if (sockunion_family(two) != AF_INET6)
            return FALSE;
        for (count = 0; count < 16; count++)
            if (sock2ip6(one)[count] != sock2ip6(two)[count])
                return FALSE;
        return TRUE;
        break;
#endif
    default:
        error_logi(ERROR_MAJOR, "Address family %d not supported", sockunion_family(one));
        return FALSE;
        break;
    }
}


int adl_setReceiveBufferSize(int sfd,int new_size)
{
    int ch = new_size;
    if (setsockopt (sfd, SOL_SOCKET, SO_RCVBUF, (void*)&ch, sizeof(ch)) < 0) {
        error_log(ERROR_MAJOR, "setsockopt: SO_RCVBUF failed !");
        return -1;
    }
    printf("Current_event_log_=%d, INTERNAL_EVENT_0=%d\n", Current_event_log_, INTERNAL_EVENT_0);
    event_log1(INTERNAL_EVENT_0, __FILE__, "set receive buffer size to : %d bytes",ch);
    event_logi(INTERNAL_EVENT_0, "set receive buffer size to : %d bytes",ch);
    return 0;
}


gint adl_open_sctp_socket(int af, int* myRwnd)
{
    int sfd, ch;
    socklen_t opt_size;
#ifdef WIN32
    struct sockaddr_in me;
#endif

#ifdef SCTP_OVER_UDP
    if ((sfd = socket(af, SOCK_RAW, IPPROTO_UDP)) < 0) {
#else
    if ((sfd = socket(af, SOCK_RAW, IPPROTO_SCTP)) < 0) {
#endif
        return sfd;
    }

#ifdef WIN32
    /* binding to INADDR_ANY to make Windows happy... */
    memset((void *)&me, 0, sizeof(me));
    me.sin_family      = AF_INET;
#ifdef HAVE_SIN_LEN
    me.sin_len         = sizeof(me);
#endif
    me.sin_addr.s_addr = INADDR_ANY;
    bind(sfd, (const struct sockaddr *)&me, sizeof(me));
#endif

    switch (af) {
        case AF_INET:
            *myRwnd = 0;
            opt_size=sizeof(*myRwnd);
            if (getsockopt (sfd, SOL_SOCKET, SO_RCVBUF, (void*)myRwnd, &opt_size) < 0) {
                error_log(ERROR_FATAL, "getsockopt: SO_RCVBUF failed !");
                *myRwnd = -1;
            }
            event_logi(INTERNAL_EVENT_0, "receive buffer size initially is : %d", *myRwnd);

#if defined (LINUX)
            adl_setReceiveBufferSize(sfd, 10*0xFFFF);

            ch = IP_PMTUDISC_DO;
            if (setsockopt(sfd, IPPROTO_IP, IP_MTU_DISCOVER, (char *) &ch, sizeof(ch)) < 0) {
                error_log(ERROR_FATAL, "setsockopt: IP_PMTU_DISCOVER failed !");
            }
            opt_size=sizeof(*myRwnd);
            if (getsockopt (sfd, SOL_SOCKET, SO_RCVBUF, (void*)myRwnd, &opt_size) < 0) {
                error_log(ERROR_FATAL, "getsockopt: SO_RCVBUF failed !");
                *myRwnd = -1;
            }
            event_logi(INTERNAL_EVENT_0, "receive buffer size finally is : %d", *myRwnd);
#endif
            break;
#ifdef HAVE_IPV6
        case AF_INET6:
            *myRwnd = 0;
            opt_size=sizeof(*myRwnd);
            if (getsockopt (sfd, SOL_SOCKET, SO_RCVBUF, (void*)myRwnd, &opt_size) < 0) {
                error_log(ERROR_FATAL, "getsockopt: SO_RCVBUF failed !");
                *myRwnd = -1;
            }
            event_logi(INTERNAL_EVENT_0, "receive buffer size is : %d",*myRwnd);
            /* also receive packetinfo on IPv6 sockets, for getting dest address */
            ch = 1;
#ifdef HAVE_IPV6_RECVPKTINFO
            /* IMPORTANT:
               The new option name is now IPV6_RECVPKTINFO!
               IPV6_PKTINFO expects an extended parameter structure now
               and had to be replaced to provide the original functionality! */
            if (setsockopt(sfd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &ch, sizeof(ch)) < 0) {
                error_log(ERROR_FATAL, "setsockopt: IPV6_RECVPKTINFO failed");
                abort();
            }
#else
            if (setsockopt(sfd, IPPROTO_IPV6, IPV6_PKTINFO, &ch, sizeof(ch)) < 0) {
                error_log(ERROR_FATAL, "setsockopt: IPV6_PKTINFO failed");
                abort();
            }
#endif
            break;
#endif
        default:
            error_log(ERROR_MINOR, "Unknown address family.");
            break;
    }
    event_logi(INTERNAL_EVENT_0, "Created raw socket %d with options\n", sfd);
    return (sfd);
}


gint adl_get_sctpv4_socket(void)
{
    /* this is a static variable ! */
    return sctp_sfd;
}


#ifdef HAVE_IPV6
gint adl_get_sctpv6_socket(void)
{
    /* this is a static variable ! */
    return sctpv6_sfd;
}
#endif


/**
 * This function creates a UDP socket bound to localhost, for asynchronous
 * interprocess communication with an Upper Layer process.
 * @return the socket file descriptor. Used to register a callback function
 */
int adl_open_udp_socket(union sockunion* me)
{
    guchar buf[1000];
    int ch, sfd;

    switch (sockunion_family(me)) {
        case AF_INET:
            if ((sfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
                error_log(ERROR_FATAL, "SCTP: socket creation failed for UDP socket !");
            }
            ch = bind(sfd, (struct sockaddr *)me, sizeof(struct sockaddr_in));
            adl_sockunion2str(me, buf, SCTP_MAX_IP_LEN);
            event_logiii(VERBOSE,
                 " adl_open_udp_socket : Create socket %u, binding to address %s, result %d",sfd, buf, ch);
            if (ch == 0)
                return (sfd);
            return -1;
            break;
#ifdef HAVE_IPV6
        case AF_INET6:
            if ((sfd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
                error_log(ERROR_FATAL, "SCTP: socket creation failed for UDPv6 socket");
            }
            ch = bind(sfd, (struct sockaddr *)me, sizeof(struct sockaddr_in6));
            adl_sockunion2str(me, buf, SCTP_MAX_IP_LEN);
            event_logiii(VERBOSE,
                 " adl_open_udp_socket : Create socket %u, binding to address %s, result %d",sfd, buf, ch);
            if (ch == 0)
                return (sfd);
            return -1;
            break;
#endif
        default:
            return -1;
            break;
     }

}

/**
 * function to be called when we get a message from a peer sctp instance in the poll loop
 * @param  sfd the socket file descriptor where data can be read...
 * @param  buf pointer to a buffer, where we data is stored
 * @param  len number of bytes to be sent, including the ip header !
 * @param  address, where data goes from
 * @param    dest_len size of the address
 * @return returns number of bytes actually sent, or error
 */
int adl_sendUdpData(int sfd, unsigned char* buf, int length,
                     unsigned char destination[], unsigned short dest_port)
{
    union sockunion dest_su;
    int dest_len;
    int result;

    if (sfd < 0) {
        error_log(ERROR_MAJOR, "You are trying to send UDP data on an invalid fd");
        return -1;
    }

    if ((sfd == sctp_sfd)
#ifdef HAVE_IPV6
        || (sfd == sctpv6_sfd)
#endif
                               ) {
        error_log(ERROR_MAJOR, "You are trying to send UDP data on a SCTP socket");
        return -1;
    }
    result = adl_str2sockunion(destination, &dest_su);

    if (result != 0) {
        error_logi(ERROR_MAJOR, "Invalid destination address in sctp_sendUdpData(%s)",destination);
        return -1;
    }
    if (buf == NULL) {
        error_log(ERROR_MAJOR, "Invalid buffer sctp_sendUdpData()");
        return -1;
    }
    if (dest_port == 0) {
        error_log(ERROR_MAJOR, "Invalid port in sctp_sendUdpData()");
        return -1;
    }
    switch (sockunion_family(&dest_su)) {
        case AF_INET:
            dest_su.sin.sin_port = htons(dest_port);
            dest_len = sizeof(struct sockaddr_in);
            result = sendto(sfd, buf, length, 0, (struct sockaddr *) &(dest_su.sin), dest_len);
            break;
#ifdef HAVE_IPV6
        case AF_INET6:
            dest_su.sin6.sin6_port = htons(dest_port);
            dest_len = sizeof(struct sockaddr_in6);
            result = sendto(sfd, buf, length, 0, (struct sockaddr *) &(dest_su.sin6), dest_len);
            break;
#endif
        default :
            error_logi(ERROR_MAJOR, "Invalid address family in sctp_sendUdpData(%s)",destination);
            result = -1;
            break;
    }
    return result;
}



/**
 * function to be called when library sends a message on an SCTP socket
 * @param  sfd the socket file descriptor where data will be sent
 * @param  buf pointer to a buffer, where data to be sent is stored
 * @param  len number of bytes to be sent
 * @param  destination address, where data is to be sent
 * @param    dest_len size of the address
 * @return returns number of bytes actually sent, or error
 */
int adl_send_message(int sfd, void *buf, int len, union sockunion *dest, unsigned char tos)
{
    int txmt_len = 0;
    unsigned char old_tos;
    socklen_t opt_len;
    int tmp;
#ifdef SCTP_OVER_UDP
    guchar      outBuffer[65536];
    udp_header* udp;
#endif

#ifdef HAVE_IPV6
    guchar hostname[MAX_MTU_SIZE];
#endif

    switch (sockunion_family(dest)) {

    case AF_INET:
        number_of_sendevents++;
        opt_len = sizeof(old_tos);
        tmp = getsockopt(sfd, IPPROTO_IP, IP_TOS, &old_tos, &opt_len);
        tmp = setsockopt(sfd, IPPROTO_IP, IP_TOS, &tos, sizeof(unsigned char));
        event_logii(VVERBOSE, "adl_send_message: set IP_TOS %u, result=%d", tos,tmp);

        event_logiiii(VERBOSE,
                     "AF_INET : adl_send_message : sfd : %d, len %d, destination : %s, send_events %u",
                     sfd, len, inet_ntoa(dest->sin.sin_addr), number_of_sendevents);

#ifdef SCTP_OVER_UDP
        if(len + sizeof(udp_header) > sizeof(outBuffer)) {
           error_log(ERROR_FATAL, "Data block too large ! bye !\n");
        }
        memcpy(&outBuffer[sizeof(udp_header)], buf, len);

        udp = (udp_header*)&outBuffer;
        udp->src_port = htons(SCTP_OVER_UDP_UDPPORT);
        udp->dest_port = htons(SCTP_OVER_UDP_UDPPORT);
        udp->length = htons(sizeof(udp_header) + len);
        udp->checksum = 0x0000;

        txmt_len = sendto(sfd, (char*)&outBuffer, sizeof(udp_header) + len,
                          0, (struct sockaddr *) &(dest->sin), sizeof(struct sockaddr_in));
        if(txmt_len >= (int)sizeof(udp_header)) {
           txmt_len -= (int)sizeof(udp_header);
        }
#else
        txmt_len = sendto(sfd, buf, len, 0, (struct sockaddr *) &(dest->sin), sizeof(struct sockaddr_in));
#endif

        if (txmt_len < 0) {
            error_logi(ERROR_MAJOR, "AF_INET : sendto()=%d !", txmt_len);
        }
        tmp = setsockopt(sfd, IPPROTO_IP, IP_TOS, &old_tos, sizeof(unsigned char));
    break;
#ifdef HAVE_IPV6
    case AF_INET6:
        number_of_sendevents++;
        inet_ntop(AF_INET6, sock2ip6(dest), (char *)hostname, MAX_MTU_SIZE);

        event_logiiii(VVERBOSE,
                     "AF_INET6: adl_send_message : sfd : %d, len %d, destination : %s, send_events: %u",
                        sfd, len, hostname, number_of_sendevents);

#ifdef SCTP_OVER_UDP
        if(len + sizeof(udp_header) > sizeof(outBuffer)) {
           error_log(ERROR_FATAL, "Data block too large ! bye !\n");
        }
        memcpy(&outBuffer[sizeof(udp_header)], buf, len);

        udp = (udp_header*)&outBuffer;
        udp->src_port = htons(SCTP_OVER_UDP_UDPPORT);
        udp->dest_port = htons(SCTP_OVER_UDP_UDPPORT);
        udp->length = htons(sizeof(udp_header) + len);
        udp->checksum = 0x0000;

        txmt_len = sendto(sfd, (char*)&outBuffer, sizeof(udp_header) + len,
                          0, (struct sockaddr *) &(dest->sin6), sizeof(struct sockaddr_in6));
        if(txmt_len >= (int)sizeof(udp_header)) {
           txmt_len -= (int)sizeof(udp_header);
        }
#else
        txmt_len = sendto(sfd, buf, len, 0, (struct sockaddr *)&(dest->sin6), sizeof(struct sockaddr_in6));
#endif
        break;
#endif
    default:
        error_logi(ERROR_MAJOR,
                   "adl_send_message : Adress Family %d not supported here",
                   sockunion_family(dest));
        txmt_len = -1;
    }
    return txmt_len;
}

/**
 * function to assign an event mask to a certain poll
 */
void assign_poll_fd(int fd_index, int sfd, int event_mask)
{
    if (fd_index > NUM_FDS)
        error_log(ERROR_FATAL, "FD_Index bigger than NUM_FDS ! bye !\n");

    poll_fds[fd_index].fd = sfd; /* file descriptor */
    poll_fds[fd_index].events = event_mask;
    /*
     * Set the entry's revision to the current extendedPoll() revision.
     * If another thread is currently inside extendedPoll(), extendedPoll()
     * will notify that this entry is new and skip the possibly wrong results
     * until the next invocation.
     */
    poll_fds[fd_index].revision = revision;
    poll_fds[fd_index].revents  = 0;
}


/**
 * remove a sfd from the poll_list, and shift that list to the left
 * @return number of sfd's removed...
 */
int adl_remove_poll_fd(gint sfd)
{
    int i, tmp, counter = 0;
    for (i = 0, tmp = 0; i < NUM_FDS; i++, tmp++) {
        if (tmp < NUM_FDS) {
            poll_fds[i].fd = poll_fds[tmp].fd;
            poll_fds[i].events = poll_fds[tmp].events;
            poll_fds[i].revents = poll_fds[tmp].revents;
            poll_fds[i].revision = poll_fds[tmp].revision;
            event_callbacks[i] = event_callbacks[tmp];
        } else {
            poll_fds[i].fd = POLL_FD_UNUSED;
            poll_fds[i].events = 0;
            poll_fds[i].revents = 0;
            poll_fds[i].revision = 0;
            event_callbacks[i] = NULL;
        }
        if (poll_fds[i].fd == sfd) {
            tmp = i + 1;
            if (tmp < NUM_FDS) {
                poll_fds[i].fd = poll_fds[tmp].fd;
                poll_fds[i].events = poll_fds[tmp].events;
                poll_fds[i].revents = poll_fds[tmp].revents;
                poll_fds[i].revision = poll_fds[tmp].revision;
                free(event_callbacks[i]);
                event_callbacks[i] = event_callbacks[tmp];
            } else {
                poll_fds[i].fd = POLL_FD_UNUSED;
                poll_fds[i].events = 0;
                poll_fds[i].revents = 0;
                poll_fds[i].revision = 0;
                free(event_callbacks[i]);
                event_callbacks[i] = NULL;
            }
            counter++;
            num_of_fds -= 1;
        }
      #ifdef WIN32
      for (i = 0; i < NUM_FDS; i++)
   {
      if (fds[i]==sfd)
      {
         fds[i]=-1;
         fdnum--;
         break;
      }
   }
#endif
    }
    return (counter);
}

/**
 * function to register a file descriptor, that gets activated for certain read/write events
 * when these occur, the specified callback funtion is activated and passed the parameters
 * that are pointed to by the event_callback struct
 */

int
adl_register_fd_cb(int sfd, int eventcb_type, int event_mask,
                   void (*action) (void *, void *) , void* userData)
{
   #ifdef WIN32

int ret, i;
if (sfd!=0)
{

   ret = WSAEventSelect(sfd, hEvent, FD_READ | FD_WRITE |
   FD_ACCEPT | FD_CLOSE | FD_CONNECT);
    if (ret == SOCKET_ERROR)
    {
        error_log(ERROR_FATAL, "WSAEventSelect() failed\n");
        return (-1);
    }
   for (i=0; i<NUM_FDS;i++)
   {
      if (fds[i]==-1)
      {
         fds[i]=sfd;
         fdnum++;
         break;
      }
   }
}
#endif

    if (num_of_fds < NUM_FDS && sfd >= 0) {
        assign_poll_fd(num_of_fds, sfd, event_mask);
        event_callbacks[num_of_fds] = (struct event_cb*)malloc(sizeof(struct event_cb));
        if (!event_callbacks[num_of_fds])
            error_log(ERROR_FATAL, "Could not allocate memory in  register_fd_cb \n");
        event_callbacks[num_of_fds]->sfd = sfd;
        event_callbacks[num_of_fds]->eventcb_type = eventcb_type;

        event_callbacks[num_of_fds]->action = (void (*) (void))action;
        event_callbacks[num_of_fds]->userData = userData;
        num_of_fds++;
        return num_of_fds;
    } else
        return (-1);
}

#ifndef CMSG_ALIGN
#ifdef ALIGN
#define CMSG_ALIGN ALIGN
#else
#define CMSG_ALIGN(len) ( ((len)+sizeof(long)-1) & ~(sizeof(long)-1) )
#endif
#endif

#ifndef CMSG_SPACE
#define CMSG_SPACE(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(len))
#endif

#ifndef CMSG_LEN
#define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
#endif

/**
 * function to be called when we get an sctp message. This function gives also
 * the source and destination addresses.
 *
 * @param  sfd      the socket file descriptor where data can be read...
 * @param  dest     pointer to a buffer, where we can store the received data
 * @param  maxlen   maximum number of bytes that can be received with call
 * @param  from     address, where we got the data from
 * @param  to       destination address of that message
 * @return returns number of bytes received with this call
 */
int adl_receive_message(int sfd, void *dest, int maxlen, union sockunion *from, union sockunion *to)
{
    int len;
#ifdef SCTP_OVER_UDP
#ifdef LINUX
    udp_header*    udp;
#else
    struct udphdr * udp;
#endif
    unsigned char* ptr;
    int            i;
#endif
#ifdef HAVE_IPV6
    struct msghdr rmsghdr;
    struct cmsghdr *rcmsgp;
    struct iovec  data_vec;
#endif
#ifdef LINUX
    struct iphdr *iph;
#else
    struct ip *iph;
#endif

#ifdef HAVE_IPV6
    unsigned char m6buf[(CMSG_SPACE(sizeof (struct in6_pktinfo)))];
    struct in6_pktinfo *pkt6info;
#endif

    len = -1;
    if ((dest == NULL) || (from == NULL) || (to == NULL)) return -1;

    if (sfd == sctp_sfd) {
        len = recv (sfd, dest, maxlen, 0);
#ifdef LINUX
        iph = (struct iphdr *)dest;
#else
        iph = (struct ip *)dest;
#endif
        to->sa.sa_family = AF_INET;
        to->sin.sin_port = htons(0);
#ifdef LINUX
        to->sin.sin_addr.s_addr = iph->daddr;
#else
        to->sin.sin_addr.s_addr = iph->ip_dst.s_addr;
#endif
        from->sa.sa_family = AF_INET;
        from->sin.sin_port = htons(0);
#ifdef LINUX
        from->sin.sin_addr.s_addr = iph->saddr;
#else
        from->sin.sin_addr.s_addr = iph->ip_src.s_addr;
#endif

#ifdef SCTP_OVER_UDP
#ifdef LINUX
        if(len < (int)sizeof(struct iphdr) + (int)sizeof(udp_header)) {
#else
        if(len < (int)sizeof(struct ip) + (int)sizeof(struct udphdr)) {
#endif
            return -1;
        }
#ifdef LINUX
        udp = (udp_header*)((long)dest + (long)sizeof(struct iphdr));
#else
        udp = (struct udphdr *)((long)dest + (long)sizeof(struct ip));
#endif
#ifdef LINUX
        if(ntohs(udp->dest_port) != SCTP_OVER_UDP_UDPPORT) {
#else
       if(ntohs(udp->uh_dport) != SCTP_OVER_UDP_UDPPORT) {
#endif
            return -1;
        }
        ptr = (unsigned char*)udp;
#ifdef LINUX
        for(i = 0;i < len - (int)(sizeof(struct iphdr) + sizeof(udp_header));i++) {
           *ptr = ptr[sizeof(udp_header)];
#else
        for(i = 0;i < len - (int)(sizeof(struct ip) + sizeof(struct udphdr));i++) {
           *ptr = ptr[sizeof(struct udphdr)];
#endif
           ptr++;
        }
#ifdef LINUX
        len -= sizeof(udp_header);
#else
        len -= sizeof(struct udphdr);
#endif
#endif
    }
#ifdef HAVE_IPV6
    data_vec.iov_base = dest;
    data_vec.iov_len  = maxlen;
    if (sfd == sctpv6_sfd) {
        rcmsgp = (struct cmsghdr *)m6buf;
        pkt6info = (struct in6_pktinfo *)(CMSG_DATA(rcmsgp));

        /* receive control msg */
        rcmsgp->cmsg_level = IPPROTO_IPV6;
        rcmsgp->cmsg_type = IPV6_PKTINFO;
        rcmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo));

        rmsghdr.msg_flags = 0;
        rmsghdr.msg_iov = &data_vec;
        rmsghdr.msg_iovlen = 1;
        rmsghdr.msg_name =      (caddr_t) &(from->sin6);
        rmsghdr.msg_namelen =   sizeof (struct sockaddr_in6);
        rmsghdr.msg_control = (caddr_t) m6buf;
        rmsghdr.msg_controllen = sizeof (m6buf);
        memset (from, 0, sizeof (struct sockaddr_in6));
        memset (to,   0, sizeof (struct sockaddr_in6));

        len = recvmsg (sfd, &rmsghdr, 0);

        /* Linux sets this, so we reset it, as we don't want to run into trouble if
           we have a port set on sending...then we would get INVALID ARGUMENT  */
        from->sin6.sin6_port = htons(0);

        to->sa.sa_family = AF_INET6;
        to->sin6.sin6_port = htons(0);
        to->sin6.sin6_flowinfo = htonl(0);
        memcpy(&(to->sin6.sin6_addr), &(pkt6info->ipi6_addr), sizeof(struct in6_addr));

#ifdef SCTP_OVER_UDP
#ifdef LINUX
        if(len < (int)sizeof(udp_header)) {
#else
        if(len < (int)sizeof(struct udphdr)) {
#endif
            return -1;
        }
#ifdef LINUX
        udp = (udp_header*)dest;
#else
        udp = (struct udphdr *)dest;
#endif
#ifdef LINUX
	if(ntohs(udp->dest_port) != SCTP_OVER_UDP_UDPPORT) {
#else
	if(ntohs(udp->uh_dport) != SCTP_OVER_UDP_UDPPORT) {
#endif
            return -1;
        }
        ptr = (unsigned char*)udp;
#ifdef LINUX
        for(i = 0;i < len - (int)sizeof(udp_header);i++) {
           *ptr = ptr[sizeof(udp_header)];
#else
        for(i = 0;i < len - (int)sizeof(struct udphdr);i++) {
           *ptr = ptr[sizeof(struct udphdr)];
#endif
           ptr++;
        }
#ifdef LINUX
        len -= sizeof(udp_header);
#else
        len -= sizeof(struct udphdr);
#endif
#endif
    }
#endif

    if (len < 0) error_log(ERROR_MAJOR, "recvmsg()  failed in adl_receive_message() !");

    return len;
}


/**
 * function to be called when we get a message from a peer sctp instance in the poll loop
 * @param  sfd the socket file descriptor where data can be read...
 * @param  dest pointer to a buffer, where we can store the received data
 * @param  maxlen maximum number of bytes that can be received with call
 * @param  address, where we got the data from
 * @param    from_len size of the address
 * @return returns number of bytes received with this call
 */
int adl_get_message(int sfd, void *dest, int maxlen, union sockunion *from, socklen_t *from_len)
{
    int len;

    len = recvfrom(sfd, dest, maxlen, 0, (struct sockaddr *) from, from_len);
    if (len < 0)
        error_log(ERROR_FATAL, "recvfrom  failed in get_message(), aborting !");

    return len;
}

/**
 * this function is responsible for calling the callback functions belonging
 * to all of the file descriptors that have indicated an event !
 * TODO : check handling of POLLERR situation
 * @param num_of_events  number of events indicated by poll()
 */
void dispatch_event(int num_of_events)
{
    int i = 0;
    int length=0;
    socklen_t src_len;
    union sockunion src, dest;
    struct sockaddr_in *src_in;
    guchar src_address[SCTP_MAX_IP_LEN];
    unsigned short portnum=0;

#if !defined (LINUX)
    struct ip *iph;
#else
    struct iphdr *iph;
#endif
    int hlen=0;
    ENTER_EVENT_DISPATCHER;
    for (i = 0; i < num_of_fds; i++) {

    if (!poll_fds[i].revents)
        continue;

        if (poll_fds[i].revents & POLLERR) {
            /* We must have specified this callback funtion for treating/logging the error */
            if (event_callbacks[i]->eventcb_type == EVENTCB_TYPE_USER) {
                event_logi(VERBOSE, "Poll Error Condition on user fd %d", poll_fds[i].fd);
                ((sctp_userCallback)*(event_callbacks[i]->action)) (poll_fds[i].fd, poll_fds[i].revents, &poll_fds[i].events, event_callbacks[i]->userData);
            } else {
                error_logi(ERROR_MINOR, "Poll Error Condition on fd %d", poll_fds[i].fd);
                ((sctp_socketCallback)*(event_callbacks[i]->action)) (poll_fds[i].fd, NULL, 0, NULL, 0);
            }
        }

        if ((poll_fds[i].revents & POLLPRI) || (poll_fds[i].revents & POLLIN) || (poll_fds[i].revents & POLLOUT)) {
            if (event_callbacks[i]->eventcb_type == EVENTCB_TYPE_USER) {
                    event_logi(VERBOSE, "Activity on user fd %d - Activating USER callback", poll_fds[i].fd);
                    ((sctp_userCallback)*(event_callbacks[i]->action)) (poll_fds[i].fd, poll_fds[i].revents, &poll_fds[i].events, event_callbacks[i]->userData);

            } else if (event_callbacks[i]->eventcb_type == EVENTCB_TYPE_UDP) {
                src_len = sizeof(src);
                length = adl_get_message(poll_fds[i].fd, rbuf, MAX_MTU_SIZE, &src, &src_len);
                event_logi(VERBOSE, "Message %d bytes - Activating UDP callback", length);
                adl_sockunion2str(&src, src_address, SCTP_MAX_IP_LEN);

                switch (sockunion_family(&src)) {
                    case AF_INET :
                        portnum = ntohs(src.sin.sin_port);
                        break;
#ifdef HAVE_IPV6
                    case AF_INET6:
                        portnum = ntohs(src.sin6.sin6_port);
                        break;
#endif
                    default:
                        portnum = 0;
                        break;
                }
                ((sctp_socketCallback)*(event_callbacks[i]->action)) (poll_fds[i].fd, rbuf, length, src_address, portnum);

            } else if (event_callbacks[i]->eventcb_type == EVENTCB_TYPE_SCTP) {
                length = adl_receive_message(poll_fds[i].fd, rbuf, MAX_MTU_SIZE, &src, &dest);

                if(length < 0) break;

                event_logiiii(VERBOSE, "SCTP-Message on socket %u , len=%d, portnum=%d, sockunion family %u",
                     poll_fds[i].fd, length, portnum, sockunion_family(&src));

                switch (sockunion_family(&src)) {
                case AF_INET:
                    src_in = (struct sockaddr_in *) &src;
                    event_logi(VERBOSE, "IPv4/SCTP-Message from %s -> activating callback",
                               inet_ntoa(src_in->sin_addr));
#if defined (LINUX)
                    iph = (struct iphdr *) rbuf;
                    hlen = iph->ihl << 2;
#elif defined (WIN32)
                    iph = (struct ip *) rbuf;
                    hlen = (iph->ip_verlen & 0x0F) << 2;
#else
                    iph = (struct ip *) rbuf;
                    hlen = iph->ip_hl << 2;
#endif
                    if (length < hlen) {
                        error_logii(ERROR_MINOR,
                                    "dispatch_event : packet too short (%d bytes) from %s",
                                    length, inet_ntoa(src_in->sin_addr));
                    } else {
                        length -= hlen;
                        mdi_receiveMessage(poll_fds[i].fd, &rbuf[hlen], length, &src, &dest);
                    }
                    break;
#ifdef HAVE_IPV6
                case AF_INET6:
                    adl_sockunion2str(&src, src_address, SCTP_MAX_IP_LEN);
                    /* if we have additional options, we must parse them, and deduct the sizes :-( */
                    event_logii(VERBOSE, "IPv6/SCTP-Message from %s (%d bytes) -> activating callback",
                                   src_address, length);

                    mdi_receiveMessage(poll_fds[i].fd, &rbuf[hlen], length, &src, &dest);
                    break;

#endif                          /* HAVE_IPV6 */
                default:
                    error_logi(ERROR_MAJOR, "Unsupported Address Family Type %u ", sockunion_family(&src));
                    break;

                }
            }
        }
        poll_fds[i].revents = 0;
    }                       /*   for(i = 0; i < num_of_fds; i++) */
    LEAVE_EVENT_DISPATCHER;
}


/**
 * function calls the respective callback funtion, that is to be executed as a timer
 * event, passing it two arguments
 */
void dispatch_timer(void)
{
    int tid, result;
    AlarmTimer* event;

    ENTER_TIMER_DISPATCHER;
    if (timer_list_empty()) {
        LEAVE_TIMER_DISPATCHER;
        return;
    }
    result = get_msecs_to_nexttimer();

    if (result == 0) {  /* i.e. a timer expired */
        result = get_next_event(&event);

        tid = event->timer_id;
        current_tid = tid;

        (*(event->action)) (tid, event->arg1, event->arg2);
        current_tid = 0;

        result = remove_timer(event);
        if (result) /* this can happen for a timeout that occurs on a deleted assoc ? */
            error_logi(ERROR_MAJOR, "remove_item returned %d", result);
    }
    LEAVE_TIMER_DISPATCHER;
    return;
}


void adl_add_msecs_totime(struct timeval *t, unsigned int msecs)
{
    long seconds = 0, microseconds = 0;
    struct timeval tmp, res;
    seconds = msecs / 1000;
    microseconds = (msecs % 1000) * 1000;
    tmp.tv_sec = seconds;
    tmp.tv_usec = microseconds;

    timeradd(t, &tmp, &res);
    memcpy(t, &res, sizeof(res));
    return;
}

/**
 * helper function for the sake of a cleaner interface :-)
 */
int adl_gettime(struct timeval *tv)
{
#ifdef WIN32
      struct timeb tb;
      ftime(&tb);
      tv->tv_sec=tb.time;
      tv->tv_usec=tb.millitm*1000;
   return 0;
#else
   return (gettimeofday(tv, (struct timezone *) NULL));
#endif
}

/**
 * function is to return difference in msecs between time a and b (i.e. a-b)
 * @param a later time (e.g. current time)
 * @param b earlier time
 * @return -1 if a is earlier than b, else msecs that passed from b to a
 */
int adl_timediff_to_msecs(struct timeval *a, struct timeval *b)
{
    struct timeval result;
    int retval;
    /* result = a-b */
    timersub(a, b, &result);
    retval = result.tv_sec * 1000 + result.tv_usec / 1000;
    event_logi(VVERBOSE, "Computed Time Difference : %d msecs", retval);
    return ((retval < 0) ? -1 : retval);
}

/**
 * function initializes the array of fds we want to use for listening to events
 * USE    POLL_FD_UNUSED to differentiate between used/unused fds !
 */
int init_poll_fds(void)
{
    int i;
    for (i = 0; i < NUM_FDS; i++) {
        assign_poll_fd(i, POLL_FD_UNUSED, 0);
      #ifdef WIN32
      fds[i]=-1;
#endif
    }
    num_of_fds = 0;
#ifdef WIN32
   fdnum=0;
#endif
    return (0);
}




/**
 *  function to check for events on all poll fds (i.e. open sockets), or else
 *  execute the next timer event. Executed timer events are removed from the list.
 *  Wrapper to poll() -- returns after timeout or read event
 *  @return  number of events that where seen on the socket fds, 0 for timer event, -1 for error
 *  @author  ajung, dreibh
 */
int adl_extendedEventLoop(void (*lock)(void* data), void (*unlock)(void* data), void* data)
{
    int result;
    unsigned int u_res;
    int msecs;



    if(lock != NULL) {
       lock(data);
    }

    msecs = get_msecs_to_nexttimer();

    /* returns -1 if no timer in list */
    /* if (msecs > GRANULARITY || msecs < 0) */
    if (msecs < 0)
        msecs = GRANULARITY;
    if (msecs == 0) {
        dispatch_timer();
        if(unlock != NULL) {
           unlock(data);
        }
        return (0);
    }

    /*  print_debug_list(INTERNAL_EVENT_0); */
    result = extendedPoll(poll_fds, &num_of_fds, msecs, lock, unlock, data);
    switch (result) {
    case -1:
        result = 0;
        break;
    case 0:
        dispatch_timer();
        break;
    default:
        u_res = (unsigned int) result;
        event_logi(INTERNAL_EVENT_0,
                   "############### %d Read Event(s) occurred -> dispatch_event() #############",
                   u_res);
        dispatch_event(result);
        break;
    }

    if(unlock != NULL) {
        unlock(data);
    }
    return (result);
}

/**
 *  function to check for events on all poll fds (i.e. open sockets), or else
 *  execute the next timer event. Executed timer events are removed from the list.
 *  Wrapper to poll() -- returns after timeout or read event
 *    @return  number of events that where seen on the socket fds, 0 for timer event, -1 for error
 *  @author  ajung
 *  @author  dreibh
 */
int adl_eventLoop()
{
#ifdef WIN32

   int n, ret,i, j;
   WSANETWORKEVENTS  ne;
   int length=0, hlen=0, msecs;
   union sockunion src, dest;
   struct ip *iph;
   struct sockaddr_in *src_in;
   unsigned short portnum;


   msecs = get_msecs_to_nexttimer();

   /* returns -1 if no timer in list */
   if (msecs < 0)
      msecs = GRANULARITY;
   if (msecs == 0) {
      dispatch_timer();
   return (0);
   }

   n = MsgWaitForMultipleObjects(2, handles, FALSE, msecs, QS_KEY);
      if (n==1 && idata.len>0)
      {
         for (i=0; i< NUM_FDS; i++)
         {

            if (event_callbacks[i]->sfd==0)
            {

               (*(event_callbacks[i]->action))(idata.buffer,idata.len);
               SetEvent(idata.eventback);
               memset(idata.buffer, 0, sizeof(idata.buffer));
               idata.len=0;
               break;
            }
         }
      }
      else if (n==0)
      {
         for (i=0; i<fdnum; i++)
         {
         ret = WSAEnumNetworkEvents(fds[i], hEvent, &ne);
            if (ret == SOCKET_ERROR)
            {
               error_log(ERROR_FATAL, "WSAEnumNetworkEvents() failed!");
               return (-1);
            }
            if (ne.lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
            {
               for (j=0; j<NUM_FDS; j++)
                  if (event_callbacks[i]->sfd==fds[i])
                  {
                  length = adl_receive_message(fds[i], rbuf, MAX_MTU_SIZE, &src, &dest);
                  portnum = ntohs(src.sin.sin_port);
                  if(length < 0) break;
                  event_logiiii(VERBOSE, "SCTP-Message on socket %u , len=%d, portnum=%d, sockunion family %u",
                     fds[i], length, portnum, sockunion_family(&src));

                    src_in = (struct sockaddr_in *) &src;
                    event_logi(VERBOSE, "IPv4/SCTP-Message from %s -> activating callback",
                               inet_ntoa(src_in->sin_addr));
                  iph = (struct ip *) rbuf;
                    hlen = (iph->ip_verlen & 0x0F) << 2;
               if (length < hlen)
               {
                        error_logii(ERROR_MINOR,
                                    "dispatch_event : packet too short (%d bytes) from %s",
                                    length, inet_ntoa(src_in->sin_addr));
                    } else
               {
                        length -= hlen;
                        mdi_receiveMessage(fds[i], &rbuf[hlen], length, &src, &dest);
                    }
                    break;
                  }

            }
         }
      }
      return 1;
#else

   return(adl_extendedEventLoop(NULL, NULL, NULL));
#endif
}


int adl_extendedGetEvents(void (*lock)(void* data), void (*unlock)(void* data), void* data)
{
   int result;
   unsigned int u_res;

   if(lock != NULL) {
     lock(data);
   }
   result = extendedPoll(poll_fds, &num_of_fds, 0, lock, unlock, data);
   if(unlock != NULL) {
     unlock(data);
   }

   switch (result) {
   case -1:
      result =  0;
     break;
   case 0:
      result =  0;
    break;
   default:
      u_res = (unsigned int) result;
      event_logi(INTERNAL_EVENT_0,
                 "############### %d Read Event(s) occurred -> dispatch_event()#############",
                 u_res);
      dispatch_event(result);
      result = 1;
    break;
   }

   return (result);
}


/**
 *     function to check for events on all poll fds (i.e. open sockets), or else
 *     execute the next timer event. Executed timer events are removed from the list.
 *  Wrapper to poll() -- returns at once or after a read event
 *    @return  0 if no file descriptor event occurred, -1 for error
 *    @author  ajung
 */
int adl_getEvents(void)
{
   return(adl_extendedGetEvents(NULL, NULL, NULL));
}


#ifdef WIN32

static DWORD WINAPI stdin_read_thread(void *param)
{
    struct input_data *indata = (struct input_data *) param;

    HANDLE inhandle;

    inhandle = GetStdHandle(STD_INPUT_HANDLE);

   while (ReadFile(inhandle, indata->buffer, sizeof(indata->buffer),
          &indata->len, NULL) && indata->len > 0)
   {
   SetEvent(indata->event);

   WaitForSingleObject(indata->eventback, INFINITE);
   memset(indata->buffer, 0, sizeof(indata->buffer));
    }
    indata->len = 0;
   memset(indata->buffer, 0, sizeof(indata->buffer));
    SetEvent(indata->event);

   return 0;
}
#endif


#ifdef SCTP_OVER_UDP
int open_dummy_socket(int family)
{
   struct sockaddr_in in;
   struct sockaddr_in6 in6;
   int sd;
   int on;

   if(family == AF_INET6) {
      memset(&in6, 0, sizeof(in6));
      in6.sin6_family = AF_INET;
      in6.sin6_port   = htons(SCTP_OVER_UDP_UDPPORT);
   }
   else {
      memset(&in, 0, sizeof(in));
      in.sin_family = AF_INET;
      in.sin_port   = htons(SCTP_OVER_UDP_UDPPORT);
   }

   sd = socket(family, SOCK_DGRAM, IPPROTO_UDP);
   if(sd < 0) {
      return -1;
   }

   on = 1;
   if(setsockopt(sd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) < 0) {
      close(sd);
      return -1;
   }

   if(family == AF_INET6) {
      if(bind(sd, (struct sockaddr*)&in6, sizeof(in6)) < 0) {
         return -1;
      }
   }
   else {
      if(bind(sd, (struct sockaddr*)&in, sizeof(in)) < 0) {
         return -1;
      }
   }

   return sd;
}
#endif


int adl_init_adaptation_layer(int * myRwnd)
{
    struct timeval curTime;
#ifdef WIN32
    WSADATA        wsaData;
    int            Ret;
#endif
#ifdef HAVE_IPV6
    int myRwnd6 = 32767;
#endif

#ifdef WIN32
    if ((Ret = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0)
    {
        error_log(ERROR_FATAL, "WSAStartup failed.");
        return SCTP_SPECIFIC_FUNCTION_ERROR;
    }
   hEvent = WSACreateEvent();
    if (hEvent == NULL)
    {
        error_log(ERROR_FATAL, "WSACreateEvent() of hEvent failed!");
        return -1;
    }

   stdinevent = WSACreateEvent();
    if (stdinevent == NULL)
    {
        error_log(ERROR_FATAL, "WSACreateEvent() of stdinevent failed!");
        return -1;
    }

   handles[0]=hEvent;
   handles[1]=stdinevent;
#endif

    /* initialize random number generator */
    adl_gettime(&curTime);
#ifdef HAVE_RANDOM
    rstate[0] = curTime.tv_sec;
    rstate[1] = curTime.tv_usec;
    initstate(curTime.tv_sec, (char *) rstate, 8);
    setstate((char *) rstate);
#else
    /* FIXME: this may be too weak (better than nothing however) */
    srand(curTime.tv_usec);
#endif

    init_poll_fds();
    init_timer_list();
    /*  print_debug_list(INTERNAL_EVENT_0); */
    sctp_sfd = adl_open_sctp_socket(AF_INET, myRwnd);
    /* set a safe default */
    if (*myRwnd == -1) *myRwnd = 8192;

    if (sctp_sfd < 0) return sctp_sfd;

#ifdef SCTP_OVER_UDP
    dummy_sctp_udp = open_dummy_socket(AF_INET);
    if(dummy_sctp_udp < 0) {
        error_log(ERROR_MAJOR, "Could not open UDP dummy socket !");
        return dummy_sctp_udp;
    }
#endif

    /* we should - in a later revision - add back the a function that opens
       appropriate ICMP sockets (IPv4 and/or IPv6) and registers these with
       callback functions that also set PATH MTU correctly */
#ifdef HAVE_IPV6
    /* icmpv6_sfd = int adl_open_icmpv6_socket(); */
    sctpv6_sfd = adl_open_sctp_socket(AF_INET6, &myRwnd6);
    if (sctpv6_sfd < 0) {
        error_log(ERROR_MAJOR, "Could not open IPv6 socket - running IPv4 only !");
        sctpv6_sfd = -1;
    }
    else {
#ifdef SCTP_OVER_UDP
       dummy_sctpv6_udp = open_dummy_socket(AF_INET6);
       if(dummy_sctpv6_udp < 0) {
           error_log(ERROR_MAJOR, "Could not open UDP/IPv6 dummy socket !");
           sctpv6_sfd = -1;
       }
#endif
    }

    /* adl_register_socket_cb(icmpv6_sfd, adl_icmpv6_cb); */

    /* set a safe default */
    if (myRwnd6 == -1) *myRwnd = 8192;
#endif

    /* icmp_sfd = int adl_open_icmp_socket(); */
    /* adl_register_socket_cb(icmp_sfd, adl_icmp_cb); */

/* #if defined(HAVE_SETUID) && defined(HAVE_GETUID) */
     /* now we could drop privileges, if we did not use setsockopt() calls for IP_TOS etc. later */
     /* setuid(getuid()); */
/* #endif   */
     return 0;
}


/**
 * this function is supposed to open and bind a UDP socket listening on a port
 * to incoming udp pakets on a local interface (a local union sockunion address)
 * @param  me   pointer to a local address, that will trigger callback, if it receives UDP data
 * @param  scf  callback funtion that is called when data has arrived
 * @return new UDP socket file descriptor, or -1 if error ocurred
 */
int adl_registerUdpCallback(unsigned char me[],
                            unsigned short my_port,
                            sctp_socketCallback scf)
{
    int result, new_sfd;
    union sockunion my_address;

#ifdef WIN32
   error_log(ERROR_MAJOR, "WIN32: Registering ULP-Callbacks for UDP not installed !");
        return -1;
#endif
   if (ntohs(my_port) == 0) {
        error_log(ERROR_MAJOR, "Port 0 is not allowed ! Fix your program !");
        return -1;
    }
    if (adl_str2sockunion(me, &my_address) < 0) {
        error_logi(ERROR_MAJOR, "Could not convert address string %s !", me);
        return -1;
    }

    switch (sockunion_family(&my_address)) {
        case AF_INET:
            event_logi(VERBOSE, "Registering ULP-Callback for UDP socket on port %u",ntohs(my_port));
            my_address.sin.sin_port = htons(my_port);
            break;
#ifdef HAVE_IPV6
        case AF_INET6:
            event_logi(VERBOSE, "Registering ULP-Callback for UDPv6 socket on port %u",ntohs(my_port));
            my_address.sin6.sin6_port = htons(my_port);
            break;
#endif
        default:
            error_log(ERROR_MINOR, "UNKNOWN ADDRESS TYPE - CHECK YOUR PROGRAM !");
            break;
    }

    new_sfd = adl_open_udp_socket(&my_address);

    if (new_sfd != -1) {
        result = adl_register_fd_cb(new_sfd, EVENTCB_TYPE_UDP, POLLIN | POLLPRI, (void(*)(void *,void *))scf, NULL);
        event_logi(INTERNAL_EVENT_0, "Registered ULP-Callback: now %d registered callbacks !!!",result);
        return  new_sfd;
    }
    return -1;
}



int adl_unregisterUdpCallback(int udp_sfd)
{
    if (udp_sfd <= 0) return -1;
    if (udp_sfd == sctp_sfd) return -1;
#ifdef HAVE_IPV6
    if (udp_sfd == sctpv6_sfd) return -1;
#endif
    return adl_remove_cb(udp_sfd);
}


/**
 * this function is supposed to register a callback function for catching
 * input from the Unix STDIN file descriptor. We expect this to be useful
 * in test programs mainly, so it is provided here for convenience.
 * @param  scf  callback funtion that is called (when return is hit)
 * @return 0, or -1 if error ocurred
 */
int adl_registerUserCallback(int fd, sctp_userCallback sdf, void* userData, short int eventMask)
{
    int result;
   #ifdef WIN32
   error_log(ERROR_MAJOR, "WIN32: Registering User Callbacks not installed !");
        return -1;
#endif
    /* 0 is the standard input ! */
    result = adl_register_fd_cb(fd, EVENTCB_TYPE_USER, eventMask, (void (*) (void *,void *))sdf, userData);
    if (result != -1) {
        event_logii(EXTERNAL_EVENT,"----------> Registered User Callback: fd=%d result=%d -------\n", fd, result);
    }
    return result;
}

#ifndef WIN32
void readCallback(int fd, short int revents, short int* events, void* userData)
{
   int n;

   struct data *udata=(struct data *)userData;

   n=read(0,(char *)udata->dat, udata->len);
   ((sctp_StdinCallback )udata->cb)(udata->dat, n);
}
#endif

int adl_registerStdinCallback(sctp_StdinCallback sdf, char* buffer, int length)
{
    int result;


#ifdef WIN32
   unsigned long in_threadid;
   idata.event = stdinevent;
   idata.eventback = CreateEvent(NULL, FALSE, FALSE, NULL);

   if (!(stdin_thread_handle=CreateThread(NULL, 0, stdin_read_thread,
               &idata, 0, &in_threadid))) {
      fprintf(stderr, "Unable to create input thread\n");
      exit(1);
    }

    result = adl_register_fd_cb(0, EVENTCB_TYPE_USER, 0, (void (*) (void *,void *))sdf, NULL);
#else
   struct data *userData;
   userData = (struct data*)malloc(sizeof (struct data));
    memset(userData, 0, sizeof(struct data));
   userData->dat=buffer;
   userData->len=length;
   userData->cb=(void (*) (void))sdf;
   result = adl_register_fd_cb(0, EVENTCB_TYPE_USER, POLLIN | POLLPRI, (void (*) (void *,void *))readCallback,userData);
#endif
   if (result != -1) {
        event_logii(EXTERNAL_EVENT,"----------> Registered Stdin Callback: fd=%d result=%d -------\n", 0, result);
    }
    return result;
}


int adl_unregisterStdinCallback()
{
    #ifdef WIN32
   TerminateThread(stdin_thread_handle,0);
   #endif
   adl_remove_poll_fd(0);
    return 0;
}



int adl_unregisterUserCallback(int fd)
{
    adl_remove_poll_fd(fd);
    return 0;
}


int
adl_register_socket_cb(gint sfd, sctp_socketCallback scf)
{
    return (adl_register_fd_cb(sfd, EVENTCB_TYPE_SCTP, POLLIN | POLLPRI, (void(*)(void *,void *))scf, NULL));
}


/**
 *      This function adds a callback that is to be called some time from now. It realizes
 *      the timer (in an ordered list).
 *      @param      milliseconds  action is to be started in milliseconds ms from now
 *      @param      action        pointer to a function to be executed, when timer goes off
 *      @return     returns an id value, that can be used to cancel a timer
 *      @author     ajung
 */
unsigned int adl_startMicroTimer(unsigned int seconds, unsigned int microseconds,
                            sctp_timerCallback timer_cb, int ttype, void *param1, void *param2)
{
    unsigned int result = 0;
    AlarmTimer* item;
    struct timeval talarm, delta, now;

    delta.tv_sec = seconds;
    /* make sure, user cannot confuse us :-) */
    delta.tv_sec += (microseconds / 1000000);  /* usually 0 */
    delta.tv_usec = (microseconds % 1000000);

    adl_gettime(&now);
    item = (AlarmTimer*)malloc(sizeof(AlarmTimer));
    if (item == NULL) return 0;

    timeradd(&now, &delta, &talarm);
    item->timer_type = ttype;
    item->action_time = talarm;
    item->action = timer_cb;
    item->arg1 = param1;
    item->arg2 = param2;
    result = insert_item(item);

    return (result);
}

unsigned int
adl_startTimer(unsigned int milliseconds, sctp_timerCallback timer_cb, int ttype,
                void *param1, void *param2)
{
    unsigned int secs, usecs;
    unsigned int result = 0;

    secs = milliseconds / 1000;
    usecs =  (milliseconds - (secs * 1000))*1000;
    result = adl_startMicroTimer(secs, usecs, timer_cb, ttype, param1, param2);
    return result;
}

/**
 *      This function adds a callback that is to be called some time from now. It realizes
 *      the timer (in an ordered list).
 *      @param      tid        timer-id of timer to be removed
 *      @return     returns 0 on success, 1 if tid not in the list, -1 on error
 *      @author     ajung
 */
int adl_stopTimer(unsigned int tid)
{
    if (tid != current_tid)
        return (remove_item(tid));
    else
        return 0;
}

/**
 *      Restarts a timer currently running
 *      @param      timer_id   the value returned by set_timer for a certain timer
 *      @param      milliseconds  action is to be started in milliseconds ms from now
 *      @return     new timer id , zero when there is an error (i.e. no timer)
 *      @author     ajung
 */
unsigned int adl_restartTimer(unsigned int timer_id, unsigned int milliseconds)
{
    unsigned int result;
    result = update_item(timer_id, milliseconds);
    event_logiii(VVERBOSE,
                 "Restarted Timer : timer_id = %u, msecs = %u, result = %u",
                 timer_id, milliseconds, result);
    return result;
}

unsigned int adl_restartMicroTimer(unsigned int timer_id, unsigned int seconds, unsigned int microseconds)
{
    unsigned int result;
    result = micro_update_item(timer_id, seconds, microseconds);
    event_logiiii(VVERBOSE,
                 "Restarted Micro-Timer : timer_id = %u, secs = %u, usecs=%u result = %u",
                 timer_id, seconds, microseconds, result);
    return result;

}


/**
 *    function to close a bound socket from our list of socket descriptors
 *    @param    sfd    socket file descriptor to be closed
 *    @return  0 on success, -1 for error, 1 if socket was not bound
 *    @author  ajung
 */
int adl_remove_cb(int sfd)
{
    int result;
#ifdef WIN32
   result = closesocket(sfd);
#else
    result = close(sfd);
#endif
    if (result < 0)
        error_log(ERROR_FATAL, "Close Socket resulted in an error");
    adl_remove_poll_fd(sfd);
    return result;
}

/**
 * An address filtering function
 * @param newAddress  a pointer to a sockunion address
 * @param flags       bit mask hiding (i.e. filtering) address classes
 * returns TRUE if address is not filtered, else FALSE if address is filtered by mask
 */
gboolean adl_filterInetAddress(union sockunion* newAddress, AddressScopingFlags  flags)
{
    switch (sockunion_family(newAddress)) {
        case AF_INET :
            event_log(VERBOSE, "Trying IPV4 address");
            if (
                (IN_MULTICAST(ntohl(newAddress->sin.sin_addr.s_addr)) && (flags & flag_HideMulticast)) ||
                (IN_EXPERIMENTAL(ntohl(newAddress->sin.sin_addr.s_addr)) && (flags & flag_HideReserved)) ||
                (IN_BADCLASS(ntohl(newAddress->sin.sin_addr.s_addr)) && (flags & flag_HideReserved)) ||
                ((INADDR_BROADCAST == ntohl(newAddress->sin.sin_addr.s_addr)) && (flags & flag_HideBroadcast))||
                ((INADDR_LOOPBACK == ntohl(newAddress->sin.sin_addr.s_addr)) && (flags & flag_HideLoopback)) ||
                ((INADDR_LOOPBACK != ntohl(newAddress->sin.sin_addr.s_addr)) && (flags & flag_HideAllExceptLoopback))||
      (ntohl(newAddress->sin.sin_addr.s_addr) == INADDR_ANY)
                ) {
            event_log(VERBOSE, "Filtering IPV4 address");
            return FALSE;
         }
         break;
#ifdef HAVE_IPV6
      case AF_INET6 :
 #if defined (LINUX)
        if (
            (!IN6_IS_ADDR_LOOPBACK(&(newAddress->sin6.sin6_addr.s6_addr)) && (flags & flag_HideAllExceptLoopback)) ||
            (IN6_IS_ADDR_LOOPBACK(&(newAddress->sin6.sin6_addr.s6_addr)) && (flags & flag_HideLoopback)) ||
            (IN6_IS_ADDR_LINKLOCAL(&(newAddress->sin6.sin6_addr.s6_addr)) && (flags & flag_HideLinkLocal)) ||
            (!IN6_IS_ADDR_LINKLOCAL(&(newAddress->sin6.sin6_addr.s6_addr)) && (flags & flag_HideAllExceptLinkLocal)) ||
            (!IN6_IS_ADDR_SITELOCAL(&(newAddress->sin6.sin6_addr.s6_addr)) && (flags & flag_HideAllExceptSiteLocal)) ||
            (IN6_IS_ADDR_SITELOCAL(&(newAddress->sin6.sin6_addr.s6_addr)) && (flags & flag_HideSiteLocal)) ||
            (IN6_IS_ADDR_MULTICAST(&(newAddress->sin6.sin6_addr.s6_addr)) && (flags & flag_HideMulticast)) ||
             IN6_IS_ADDR_UNSPECIFIED(&(newAddress->sin6.sin6_addr.s6_addr))
                 ) {
            event_log(VERBOSE, "Filtering IPV6 address");
            return FALSE;
        }
 #else
        if (
            (!IN6_IS_ADDR_LOOPBACK(&(newAddress->sin6.sin6_addr)) && (flags & flag_HideAllExceptLoopback)) ||
            (IN6_IS_ADDR_LOOPBACK(&(newAddress->sin6.sin6_addr)) && (flags & flag_HideLoopback)) ||
            (!IN6_IS_ADDR_LINKLOCAL(&(newAddress->sin6.sin6_addr)) && (flags & flag_HideAllExceptLinkLocal)) ||
            (!IN6_IS_ADDR_SITELOCAL(&(newAddress->sin6.sin6_addr)) && (flags & flag_HideAllExceptSiteLocal)) ||
            (IN6_IS_ADDR_LINKLOCAL(&(newAddress->sin6.sin6_addr)) && (flags & flag_HideLinkLocal)) ||
            (IN6_IS_ADDR_SITELOCAL(&(newAddress->sin6.sin6_addr)) && (flags & flag_HideSiteLocal)) ||
            (IN6_IS_ADDR_MULTICAST(&(newAddress->sin6.sin6_addr)) && (flags & flag_HideMulticast)) ||
             IN6_IS_ADDR_UNSPECIFIED(&(newAddress->sin6.sin6_addr))
                 ) {
            event_log(VERBOSE, "Filtering IPV6 address");
            return FALSE;
        }
 #endif
         break;
#endif
      default :
        event_log(VERBOSE, "Default : Filtering Address");
        return FALSE;
        break;
    }
    return TRUE;
}




/*
 * this is an ugly part to code, so it was taken an adapted from the
 * SCTP reference implementation by Randy Stewart
 * see http://www.sctp.org
 * returns TRUE is successful, else FALSE
 *
 * Changed by Stefan Jansen <stefan.jansen AT gmx.de>, Aug 1st, 2002.
 * When going through the ifreq array, numAlocAddr was used as upper bound.
 * But at this time numAlocAddr counts also IPv6 addresses from
 * /proc/net/if_inet6 and is therefore too much. Thus I introduced a new
 * counter named numAlocIPv4Addr.
 * This error lead to a kernel error message because the kernel tried to load
 * a kernel module when the non-existing network devices were accessed on
 * SuSE Linux 7.3, kernel 2.4.16-4GB, GCC 2.95.3, glibc-2.2.4-64.
 *
 * Changed by Amedeo Bonfiglio as shown in
 * http://www.qnx.com/developers/docs/6.4.0/io-pkt_en/user_guide/migrating.html#Coexistence
 */
gboolean adl_gatherLocalAddresses(union sockunion **addresses,
     int *numberOfNets,
     int sctp_fd,
     gboolean with_ipv6,
     int *max_mtu,
     const AddressScopingFlags  flags)

{

#ifdef WIN32
   union sockunion *localAddresses=NULL;

   SOCKET           s[MAXIMUM_WAIT_OBJECTS];
    WSAEVENT         hEvent[MAXIMUM_WAIT_OBJECTS];
    WSAOVERLAPPED    ol[MAXIMUM_WAIT_OBJECTS];
    struct addrinfo *local=NULL,hints,
                    *ptr=NULL;
    SOCKET_ADDRESS_LIST *slist=NULL;
    DWORD            bytes;
    char             addrbuf[ADDRESS_LIST_BUFFER_SIZE],host[NI_MAXHOST],serv[NI_MAXSERV];
    int              socketcount=0,
                     addrbuflen=ADDRESS_LIST_BUFFER_SIZE,
                     rc,i, j,hostlen = NI_MAXHOST,servlen = NI_MAXSERV;
   struct sockaddr_in Addr;


    /* Enumerate the local bind addresses - to wait for changes we only need
        one socket but to enumerate the addresses for a particular address
      family, we need a socket of that type  */

    memset(&hints, 0, sizeof(hints));
    hints.ai_flags  = AI_PASSIVE;
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_protocol = IPPROTO_UDP;

    if ((rc = getaddrinfo(NULL,"0",&hints,&local))!=0)
    {
        local=NULL;
      fprintf(stderr, "Unable to resolve the bind address!\n");
        return -1;
    }

     /* Create a socket and event for each address returned*/
    ptr = local;
    while (ptr)
    {
        s[socketcount] = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
        if (s[socketcount] == INVALID_SOCKET)
        {
            fprintf(stderr, "socket failed: %d\n", WSAGetLastError());
            return -1;
        }

        hEvent[socketcount] = WSACreateEvent();
        if (hEvent == NULL)
        {
            fprintf(stderr, "WSACreateEvent failed: %d\n", WSAGetLastError());
            return -1;
        }

        socketcount++;

        ptr = ptr->ai_next;

        if (ptr && (socketcount > MAXIMUM_WAIT_OBJECTS))
        {
            printf("Too many address families returned!\n");
            break;
        }
    }

        for(i=0; i < socketcount ;i++)
        {
            memset(&ol[i], 0, sizeof(WSAOVERLAPPED));
            ol[i].hEvent = hEvent[i];
            if ((rc = WSAIoctl(s[i],SIO_ADDRESS_LIST_QUERY,NULL,0,addrbuf,addrbuflen,
                   &bytes,NULL, NULL))== SOCKET_ERROR)
            {
                fprintf(stderr, "WSAIoctl: SIO_ADDRESS_LIST_QUERY failed: %d\n", WSAGetLastError());
                return -1;
            }

            slist = (SOCKET_ADDRESS_LIST *)addrbuf;
         localAddresses = calloc(slist->iAddressCount,sizeof(union sockunion));
            for(j=0; j < slist->iAddressCount ;j++)
            {
            if ((rc = getnameinfo(slist->Address[j].lpSockaddr, slist->Address[j].iSockaddrLength,
               host,hostlen,serv,servlen,NI_NUMERICHOST | NI_NUMERICSERV))!=0)
               fprintf(stderr, "%s: getnameinfo failed: %d\n", __FILE__, rc);
            Addr.sin_family=slist->Address[j].lpSockaddr->sa_family;
            Addr.sin_addr.s_addr=inet_addr(host);
            memcpy(&((localAddresses)[j]),&Addr,sizeof(Addr));
            }

            /* Register for change notification*/
           if ((rc = WSAIoctl(s[i],SIO_ADDRESS_LIST_CHANGE,NULL,0,NULL,0,&bytes,&ol[i],NULL))== SOCKET_ERROR)
            {
                if (WSAGetLastError() != WSA_IO_PENDING)
                {
                    fprintf(stderr, "WSAIoctl: SIO_ADDRESS_LIST_CHANGE failed: %d\n", WSAGetLastError());
                    return -1;
                }
            }
        }

       freeaddrinfo(local);

    for(i=0; i < socketcount ;i++)
        closesocket(s[i]);

   *addresses = localAddresses;
    *numberOfNets=slist->iAddressCount;
   *max_mtu=1500;
   return TRUE;
#else
#if defined (LINUX)
    int addedNets;
    char addrBuffer[256];
    FILE *v6list;
    struct sockaddr_in6 sin6;
    int numAlocIPv4Addr = 0;
#endif

    char addrBuffer2[64];
    /* unsigned short intf_flags; */
    struct ifconf cf;
    int pos=0,copSiz=0,numAlocAddr=0,ii;
    char buffer[8192];
    struct sockaddr *toUse;
    int saveMTU = 1500; /* default maximum MTU for now */
#ifdef HAS_SIOCGLIFADDR
    struct if_laddrreq lifaddr;
#endif
    struct ifreq local;
    struct ifreq *ifrequest,*nextif;
    int dup,xxx,tmp;
    union sockunion * localAddresses = NULL;

    cf.ifc_buf = buffer;
    cf.ifc_len = 8192;
    *max_mtu = 0;
    *numberOfNets = 0;

    /* Now gather the master address information */
    if(ioctl(sctp_fd, SIOCGIFCONF, (char *)&cf) == -1) {
        return(FALSE);
    }

#ifdef USES_BSD_4_4_SOCKET
    for (pos = 0; pos < cf.ifc_len; ) {
        ifrequest = (struct ifreq *)&buffer[pos];
#ifdef SOLARIS
      pos += (sizeof(struct sockaddr) + sizeof(ifrequest->ifr_name));
#else
        // amedeo+
        if (ifrequest->ifr_addr.sa_len + IFNAMSIZ > sizeof(struct ifreq))
			pos += ifrequest->ifr_addr.sa_len + IFNAMSIZ;
		else
			pos += sizeof(struct ifreq);

        // amedeo-
        //pos += (ifrequest->ifr_addr.sa_len + sizeof(ifrequest->ifr_name));
        //
        //if (ifrequest->ifr_addr.sa_len == 0) {
        //    /* if the interface has no address then you must
        //     * skip at a minium a sockaddr structure
        //     */
        //    pos += sizeof(struct sockaddr);
        //}
#endif
        numAlocAddr++;
    }
#else
    numAlocAddr = cf.ifc_len / sizeof(struct ifreq);
    /* ????????????  numAlocAddr++; */
    ifrequest = cf.ifc_req;
#endif
#if defined  (LINUX)
    numAlocIPv4Addr = numAlocAddr;
    addedNets = 0;
    v6list = fopen(LINUX_PROC_IPV6_FILE,"r");
    if (v6list != NULL) {
        while(fgets(addrBuffer,sizeof(addrBuffer),v6list) != NULL){
            addedNets++;
        }
        fclose(v6list);
    }
    numAlocAddr += addedNets;
    event_logii(VERBOSE, "Found additional %d v6 addresses, total now %d\n",addedNets,numAlocAddr);
#endif
    /* now allocate the appropriate memory */
    localAddresses = (union sockunion*)calloc(numAlocAddr,sizeof(union sockunion));

    if(localAddresses == NULL){
        error_log(ERROR_MAJOR, "Out of Memory in adl_gatherLocalAddresses() !");
        return(FALSE);
    }

     pos = 0;
     /* Now we go through and pull each one */

#if defined (LINUX)
    v6list = fopen(LINUX_PROC_IPV6_FILE,"r");
    if(v6list != NULL){
        memset((char *)&sin6,0,sizeof(sin6));
        sin6.sin6_family = AF_INET6;

        while(fgets(addrBuffer,sizeof(addrBuffer),v6list) != NULL){
            if(strncmp(addrBuffer,"00000000000000000000000000000001",32) == 0) {
                event_log(VVERBOSE, "At least I found the local IPV6 address !");
                if(inet_pton(AF_INET6,"::1",(void *)&sin6.sin6_addr) > 0){
                    sin6.sin6_family = AF_INET6;
                    memcpy(&((localAddresses)[*numberOfNets]),&sin6,sizeof(sin6));
                    event_logiiiii(VVERBOSE, "copied the local IPV6 address %x:%x:%x:%x, family %x",
                        sin6.sin6_addr.s6_addr32[3], sin6.sin6_addr.s6_addr32[2], sin6.sin6_addr.s6_addr32[1],
                        sin6.sin6_addr.s6_addr32[0], sin6.sin6_family);
                    (*numberOfNets)++;
                }
                continue;
            }
            memset(addrBuffer2,0,sizeof(addrBuffer2));
            strncpy(addrBuffer2,addrBuffer,4);
            addrBuffer2[4] = ':';
            strncpy(&addrBuffer2[5],&addrBuffer[4],4);
            addrBuffer2[9] = ':';
            strncpy(&addrBuffer2[10],&addrBuffer[8],4);
            addrBuffer2[14] = ':';
            strncpy(&addrBuffer2[15],&addrBuffer[12],4);
            addrBuffer2[19] = ':';
            strncpy(&addrBuffer2[20],&addrBuffer[16],4);
            addrBuffer2[24] = ':';
            strncpy(&addrBuffer2[25],&addrBuffer[20],4);
            addrBuffer2[29] = ':';
            strncpy(&addrBuffer2[30],&addrBuffer[24],4);
            addrBuffer2[34] = ':';
            strncpy(&addrBuffer2[35],&addrBuffer[28],4);

            if(inet_pton(AF_INET6,addrBuffer2,(void *)&sin6.sin6_addr) > 0){
                memcpy(&((localAddresses)[*numberOfNets]),&sin6,sizeof(sin6));
                (*numberOfNets)++;
            }else{
                error_logi(ERROR_FATAL, "Could not translate string %s",addrBuffer2);
            }
        }
        fclose(v6list);
    }
#endif

    /* set to the start, i.e. buffer[0] */
    ifrequest = (struct ifreq *)&buffer[pos];

#if defined (LINUX)
    for(ii=0; ii < numAlocIPv4Addr; ii++,ifrequest=nextif){
#else
    for(ii=0; ii < numAlocAddr; ii++,ifrequest=nextif){
#endif
#ifdef USES_BSD_4_4_SOCKET
        /* use the sa_len to calculate where the next one will be */
#ifdef SOLARIS
      pos += (sizeof(struct sockaddr) + sizeof(ifrequest->ifr_name));
#else
        // amedeo+
        if (ifrequest->ifr_addr.sa_len + IFNAMSIZ > sizeof(struct ifreq))
			pos += ifrequest->ifr_addr.sa_len + IFNAMSIZ;
		else
			pos += sizeof(struct ifreq);

        // amedeo-
        //pos += (ifrequest->ifr_addr.sa_len + sizeof(ifrequest->ifr_name));
        //
        //if (ifrequest->ifr_addr.sa_len == 0){
        //    /* if the interface has no address then you must
        //     * skip at a minium a sockaddr structure
        //     */
        //    pos += sizeof(struct sockaddr);
        //}
#endif
        nextif = (struct ifreq *)&buffer[pos];
#else
        nextif = ifrequest + 1;
#endif

#ifdef _NO_SIOCGIFMTU_
        *max_mtu = DEFAULT_MTU_CEILING;
#else
        memset(&local, 0, sizeof(local));
        memcpy(local.ifr_name,ifrequest->ifr_name,IFNAMSIZ);
        event_logiii(VERBOSE, "Interface %d, NAME %s, Hex: %x",ii,local.ifr_name,local.ifr_name);

        if (ioctl(sctp_fd, SIOCGIFMTU, (char *)&local) == -1) {
            /* cant get the flags? */
            continue;
        }
        saveMTU = local.ifr_mtu;
        event_logii(VERBOSE, "Interface %d, MTU %d",ii,saveMTU);
#endif
        toUse = &ifrequest->ifr_addr;

        adl_sockunion2str((union sockunion*)toUse, (guchar *)addrBuffer2, SCTP_MAX_IP_LEN);
        event_logi(VERBOSE, "we are talking about the address %s", addrBuffer2);


        memset(&local, 0, sizeof(local));
        memcpy(local.ifr_name, ifrequest->ifr_name, IFNAMSIZ);

        if(ioctl(sctp_fd, SIOCGIFFLAGS, (char *)&local) == -1){
            /* can't get the flags, skip this guy */
            continue;
        }
        /* Ok get the address and save the flags */
        /*        intf_flags = local.ifr_flags; */

        if(!(local.ifr_flags & IFF_UP)) {
            /* Interface is down */
            continue;
        }


        if (flags & flag_HideLoopback){
            if (adl_filterInetAddress((union sockunion*)toUse, flag_HideLoopback) == FALSE){
                /* skip the loopback */
                event_logi(VERBOSE, "Interface %d, skipping loopback",ii);
                continue;
            }
        }
        if (adl_filterInetAddress((union sockunion*)toUse, flag_HideReserved) == FALSE) {
            /* skip reserved */
            event_logi(VERBOSE, "Interface %d, skipping reserved",ii);
            continue;
        }

        if(toUse->sa_family== AF_INET){
            copSiz = sizeof(struct sockaddr_in);
        } else if (toUse->sa_family == AF_INET6){
            copSiz = sizeof(struct sockaddr_in6);
        }
        if (*max_mtu < saveMTU) *max_mtu = saveMTU;

         /* Now, we may have already gathered this address, if so skip
          * it
          */
        event_logii(VERBOSE, "Starting checking for duplicates ! MTU = %d, nets: %d",saveMTU, *numberOfNets);

        if(*numberOfNets) {
            tmp = *numberOfNets;
            dup = 0;
            /* scan for the dup */
            for(xxx=0; xxx < tmp; xxx++) {
                event_logi(VERBOSE, "duplicates loop xxx=%d",xxx);
                if(adl_equal_address(&localAddresses[xxx], (union sockunion*)toUse)) {
#ifdef HAVE_IPV6
                   if((localAddresses[xxx].sa.sa_family == AF_INET6) &&
                      (toUse->sa_family == AF_INET) &&
                      (IN6_IS_ADDR_V4MAPPED(&localAddresses[xxx].sin6.sin6_addr) ||
                       IN6_IS_ADDR_V4COMPAT(&localAddresses[xxx].sin6.sin6_addr))) {
                      /* There are multiple interfaces, one has ::ffff:a.b.c.d or
                         ::a.b.c.d address. Use address which is IPv4 native instead. */
                      memcpy(&localAddresses[xxx], toUse, sizeof(localAddresses[xxx]));
                   }
                   else {
#endif
                      event_log(VERBOSE, "Interface %d, found duplicate");
                      dup = 1;
#ifdef HAVE_IPV6
                   }
#endif
                }
            }
            if(dup) {
                /* skip the duplicate name/address we already have it*/
                continue;
            }
        }

        /* copy address */
        event_logi(VVERBOSE, "Copying %d bytes",copSiz);
        memcpy(&localAddresses[*numberOfNets],(char *)toUse,copSiz);
        event_log(VVERBOSE, "Setting Family");
        /* set family */
        (&(localAddresses[*numberOfNets]))->sa.sa_family = toUse->sa_family;

#ifdef USES_BSD_4_4_SOCKET
#ifndef SOLARIS
        /* copy the length */
        (&(localAddresses[*numberOfNets]))->sa.sa_len = toUse->sa_len;
#endif
#endif
        (*numberOfNets)++;
        event_logii(VERBOSE, "Interface %d, Number of Nets: %d",ii, *numberOfNets);
    }

    event_logi(VERBOSE, "adl_gatherLocalAddresses: Found %d addresses", *numberOfNets);
    for(ii = 0; ii < (*numberOfNets); ii++) {
        adl_sockunion2str(&(localAddresses[ii]), (guchar *)addrBuffer2, SCTP_MAX_IP_LEN);
        event_logii(VERBOSE, "adl_gatherAddresses : Address %d: %s",ii, addrBuffer2);

    }
    *addresses = localAddresses;
    return(TRUE);
#endif
}



  • [SCTP-Discussion] sctplib-1.0.8 on QNX Neutrino RTOS 6.4.1: fix to adaptation.c, amedeo bonfiglio, 11/14/2009

Archive powered by MHonArc 2.6.19+.

Top of page