#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <cctype>
#include <netinet/in.h>

// from Audit source.
static unsigned char x2c(const unsigned char *buf)
{
        static const char AsciiArray[17] = "0123456789ABCDEF";
        const char *ptr;
        unsigned char total=0;

        ptr = strchr(AsciiArray, (char)toupper(buf[0]));
        if (ptr)
                total = (unsigned char)(((ptr-AsciiArray) & 0x0F)<<4);
        ptr = strchr(AsciiArray, (char)toupper(buf[1]));
        if (ptr)
                total += (unsigned char)((ptr-AsciiArray) & 0x0F);

        return total;
}

// from Audit source.
char *au_unescape(char *buf)                                                                                                                                                                                                    {
        int len, i;
        char saved, *str, *ptr = buf;

        /* Find the end of the name */
        if (*ptr == '(') {
                ptr = strchr(ptr, ')');
                if (ptr == NULL)
                {
                        return NULL;
                }
                else
                        ptr++;
        } else {
                while (isxdigit(*ptr))
                        ptr++;
        }
        saved = *ptr;
        *ptr = 0;
        str = strdup(buf);
        *ptr = saved;

        /* See if its '(null)' from the kernel */
        if (*buf == '(')
                return str;

        /* We can get away with this since the buffer is 2 times
         * bigger than what we are putting there.
         */
        len = strlen(str);
        if (len < 2) {
                free(str);
                return NULL;
        }
        ptr = str;
        for (i=0; i<len; i+=2) {
                *ptr = x2c((unsigned char *)&str[i]);
                ptr++;
        }
        *ptr = 0;
        return str;
}

struct sockaddr* get_au_sockaddr(const char* val, int *ret_len) {
    *ret_len = strlen(val) / 2; /* because audit msg uses hexadecimal to
     represent sock addr */

    // convert hexadecimal sock addr to char string
    return (struct sockaddr *) au_unescape((char *) val);
}

int main(int argc, char* argv[]) {

    if (argc != 2) {
        fprintf(stderr, "<Usage> %s <SOCKSTRING>\n", argv[0]);
        exit(-1);
    }
    int len = 0;
    struct sockaddr* sa = get_au_sockaddr(argv[1], &len);
    int port = ntohs(((struct sockaddr_in *)sa)->sin_port);

    uint32_t addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
    printf("%s: sa_family: %d addr: %u, port: %d (%d)\n",
            argv[1], sa->sa_family, addr, port, ((struct sockaddr_in *)sa)->sin_port);
}
