/* opensocks.c / openfiles.c */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include "netinet/in.h"
#include "sys/socket.h"
#include "sys/errno.h"
#include "sys/byteorder.h"
#include "arpa/inet.h"
#include "netdb.h"
#include "bind:dnsquery.h"
#include "oslib:osargs.h"

static void strlwr(char *c)
{
        while (*c) {
                *c = tolower(*c); ++c;
        }
}

static void port(char *buffer, int port2, int sock)
{
	struct servent *s;
        char *proto;
        char buf[16];
        int len = 16;
        int res;

        res  = getsockopt(sock, SOL_SOCKET, SO_TYPE, buf, &len);
        if (res != -1) switch (*buf) {
                case SOCK_STREAM: proto="tcp"; break;
                case SOCK_DGRAM: proto="udp"; break;
                case SOCK_RAW: proto="icmp"; break;
                default: proto=""; break;
        }
        else proto = "";

	s = getservbyport(port2, (*proto)?proto:NULL);

	if (s) {
	        strcat(buffer, s->s_name);
		strcat(buffer, "/");
                strcat(buffer, proto);
	}
	else {
	        sprintf(buf, "%d/%s", ntohs(port2),proto);
	        strcat(buffer, buf);
	}

}

static char *ip(int s, struct sockaddr_in *sin)
{
        static char	buffer[256];
        struct hostent *host;

        strcpy(buffer, inet_ntoa(sin->sin_addr));
        if (sin->sin_addr.s_addr == INADDR_ANY) {
                strcpy(buffer, "[INADDR_ANY]");
        } else if ((sin->sin_addr.s_addr & 0xff) == 0x7f) {
                strcpy(buffer, "[localhost]");
        } else {
                dnsquery *q = dnsquery_gethostbyaddr(
                	(char *)&sin->sin_addr, 4, AF_INET);
                if (q) {
                        dns_status s;
                do {
                        s = dnsquery_check(q);
                } while (s != dns_query_complete_success &&
                 s != dns_query_complete_failure);
                if (s == dns_query_complete_success) {
                host = dnsquery_getanswer(q);
                if (host) {
                        buffer[0] = '\0';
                        strncat(buffer, host->h_name, 200);
                }
                }
                dnsquery_dispose(q);
                }
        }

	strcat(buffer, " (");
	port(buffer, sin->sin_port, s);
	return strcat(buffer, ")");
}

static int opensocks(char *flags)
{
        struct sockaddr_in	sin;
        int			size;
        int			s;
	extern int gettsize(void);
	int			maxs = gettsize();
	const int noexist = !!strchr(flags, 'a');
	const int noerror = !!strchr(flags, 'e');

        for (s=0; s<maxs; ++s) {
                size = 16;
                errno = 0;
                if (getsockname(s, (struct sockaddr *)&sin, &size) < 0) {
                        if (((errno==EBADF) && noexist) ||
                             (errno!=EBADF) && noerror) {
                                printf("%8d (errno %d)\n", s, errno);
                        }
                        continue;
                }

                printf("%8d %s", s, ip(s,&sin));
                size = 16;
                if (getpeername(s, (struct sockaddr *)&sin, &size) > -1) {
                        printf(" <---> %s", ip(s,&sin));
                }
                putchar('\n');
        }

        return 0;
}

static int openfiles(void)
{
        int 	t,ptr,ext;
        bits	stream_status, fs_status;
        char	name[256];

	printf("Handle Extent CPointer Name\n");
        for (t=255; t>0; --t) {
                osargs_read_info((os_f) t, &stream_status, &fs_status);
                if (stream_status & osargs_STREAM_UNALLOCATED) continue;
		ext = osargs_read_ext((os_f) t);
		ptr = osargs_read_ptr((os_f) t);
                osargs_read_path((os_f) t, name, 256);
                printf("%4d %8X %8X %s\n", t, ext, ptr, name);
        }
        return 0;
}

int main(int argc, char *argv[])
{
        argc=argc;
        strlwr(argv[0]);
        if (strstr(argv[0],"opensocks")) return opensocks(argv[1]);
        else return openfiles();
}
