
/*---------------------------------------------------------------------------*/
/* ios_sockets.cpp                                                           */
/* copyright (c) innovaphone 2015                                            */
/*                                                                           */
/*---------------------------------------------------------------------------*/

#include <netdb.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <netinet/in.h>
#include <net/if.h>
#include <ifaddrs.h>
#include <arpa/inet.h>
//#include <stdlib.h>
#include <sys/sysctl.h>

#include "platform/platform.h"
#include "common/os/iomux.h"
#include "common/interface/socket.h"
#include "common/linux/udp/udpsocket.h"
#include "common/linux/tcp/tcpsocket.h"
#include "common/linux/uds/udsocket.h"
#include "client/linux/client_main/client_sockets.h"
#include "ios_sockets.h"

#include "TargetConditionals.h"
#if TARGET_IPHONE_SIMULATOR
    #define TypeEN    "en1"
#else
    #define TypeEN    "en0"
#endif

/*---------------------------------------------------------------------------*/

static bool getIPAddress(struct sockaddr *sock_addr, struct sockaddr *netmask)
{
    struct ifaddrs *interfaces = 0;
    struct ifaddrs *temp_addr = 0;
    bool success;
    int res;

    success = false;
    // retrieve the current interfaces - returns 0 on success
    res = getifaddrs(&interfaces);
    if (res == 0) {
        // Loop through linked list of interfaces
        temp_addr = interfaces;
        while(temp_addr) {
            if(temp_addr->ifa_addr->sa_family == AF_INET) {
                // Check if interface is en0 which is the wifi connection on the iPhone
                if ((strcmp(temp_addr->ifa_name, TypeEN) == 0)
                 && ((temp_addr->ifa_addr->sa_data[2] != 0)
                  || (temp_addr->ifa_addr->sa_data[3] != 0)
                  || (temp_addr->ifa_addr->sa_data[4] != 0)
                  || (temp_addr->ifa_addr->sa_data[5] != 0)))
                {
                    memcpy(sock_addr, temp_addr->ifa_addr, sizeof(struct sockaddr));
                    memset(&(((struct sockaddr *) sock_addr)->sa_data[6]), 0, sizeof(((struct sockaddr *) sock_addr)->sa_data) - 6);
                    memcpy(netmask, temp_addr->ifa_netmask, sizeof(struct sockaddr));
                    memset(&(((struct sockaddr *) netmask)->sa_data[6]), 0, sizeof(((struct sockaddr *) netmask)->sa_data) - 6);
                    success = true;
                }
            }
            temp_addr = temp_addr->ifa_next;
        }
        if (!success) {
            temp_addr = interfaces;
            while(temp_addr) {
                if(temp_addr->ifa_addr->sa_family == AF_INET) {
                    // Check if interface is pdp_ip0 which is the cell connection on the iPhone
                    if ((strcmp(temp_addr->ifa_name, "pdp_ip0") == 0)
                     && ((temp_addr->ifa_addr->sa_data[2] != 0)
                      || (temp_addr->ifa_addr->sa_data[3] != 0)
                      || (temp_addr->ifa_addr->sa_data[4] != 0)
                      || (temp_addr->ifa_addr->sa_data[5] != 0)))
                    {
                        memcpy(sock_addr, temp_addr->ifa_addr, sizeof(struct sockaddr));
                        memset(&(((struct sockaddr *) sock_addr)->sa_data[6]), 0, sizeof(((struct sockaddr *) sock_addr)->sa_data) - 6);
                        memcpy(netmask, temp_addr->ifa_netmask, sizeof(struct sockaddr));
                        memset(&(((struct sockaddr *) netmask)->sa_data[6]), 0, sizeof(((struct sockaddr *) netmask)->sa_data) - 6);
                        success = true;
                    }
                }
                temp_addr = temp_addr->ifa_next;
            }
        }
    }
    // Free memory
    freeifaddrs(interfaces);

    return success;
}

extern "C" dword getIPv4Address()
{
    struct sockaddr sock_addr;
    struct sockaddr netmask;
    dword addr = 0;

    if (getIPAddress(&sock_addr, &netmask)) {
        addr = ((byte)(sock_addr.sa_data[2])) | (((byte)(sock_addr.sa_data[3])) << 8) | (((byte)(sock_addr.sa_data[4])) << 16) | (((byte)(sock_addr.sa_data[5])) << 24);
    }
    return addr;
}

/*---------------------------------------------------------------------------*/
/* IosSockets                                                                */
/*---------------------------------------------------------------------------*/

IClientSockets * IClientSockets::Create(class IIoMux *iomux, UClientSockets * user)
{
    return new IosSockets(iomux, user);
}

IosSockets::IosSockets(class IIoMux *iomux, UClientSockets * user) :
    user_timer(iomux, this)
{
    this->iomux = iomux;
    this->user = user;
}

IosSockets::~IosSockets()
{
}

void IosSockets::StartTimer(unsigned timeoutMs)
{
    user_timer.Start(timeoutMs);
}

void IosSockets::CancelTimer()
{
    user_timer.Cancel();
}

void IosSockets::TimerOnTimeout(ios_sockets_user_timer * timer)
{
    user->ClientSocketsTimeout();
}

void IosSockets::SocketsActive(bool active)
{
    ERR(("Sockets active %i", active));
}

extern "C" void onCommunicationStart();
extern "C" void onCommunicationEnd();

void IosSockets::RtpSocketsActive(bool active)
{
    if (active) {
        onCommunicationStart();
    }
    else {
        onCommunicationEnd();
    }
}

void IosSockets::MulticastReceiveActive(bool active)
{
    ERR(("Multicast receive active %i", active));
/*
    if(active) {
        WifiManager_MulticastLock_acquire(multicast_lock);
    }
    else {
        WifiManager_MulticastLock_release(multicast_lock);
    }
*/
}

/*---------------------------------------------------------------------------*/
