/*
 * Micro-X -- an X server for DOS
 * Copyright (C) 1994 StarNet Communications Corp.
 *
 * 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 2
 * 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * 
 * StarNet Communications Corp.
 * 550 Lakeside Dr. #3
 * Sunnyvale CA 94086 US
 * http://www.starnet.com
 * x-dos@starnet.com
 */

#include <sys/types.h>
#include <sys/sysent.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include "funcdef.h"
#include "../defs.h"

int _fastcall _near
tcpopen_socket(arg, len, buf)
int arg, _near *len;
void _far *buf;
{
    int fd;
    struct sockaddr_in in;
    int on = 1;
    int type;
    struct net_addr _far *addr = (struct net_addr _far *)buf;

    switch (arg) {
	case NET_TYPE_TCP:
	    type = SOCK_STREAM;
	    break;
	case NET_TYPE_UDP:
	    type = SOCK_DGRAM;
	    break;
	default:
	    printn(arg);
	    dfputs(": unknown socket type\r\n");
	    errno = EPROTOTYPE;
	    return -1;
    }
    fd = socket(AF_INET, type, 0);
    if (fd < 0) {
	net_perror("socket");
	return fd;
    }

    if (ioctl(fd, FIONBIO, (fptr)&on) < 0) {
	net_perror("ioctl");
	sclose(fd);
	return -1;
    }
    if (type == SOCK_DGRAM) {
	if (setsoopt(fd, SOL_SOCKET, SO_BROADCAST, (fptr)&on, sizeof on) < 0)
	    net_perror("SO_BROADCAST");
    }
    (void)setsoopt(fd, SOL_SOCKET, SO_REUSEADDR, (fptr)&on, sizeof on);
    in.sin_family = AF_INET;
    in.sin_port = htons(addr->socket);
    in.sin_addr.s_addr = addr->host;
    memset(in.sin_zero, 0, sizeof in.sin_zero);

    if (bind(fd, (fptr)&in, sizeof in) < 0) {
	net_perror("bind");
	sclose(fd);
	return -1;
    }
    if (type == SOCK_STREAM)
	(void)listen(fd, 5);
    addr->socket = ntohs(in.sin_port);
    addr->host = in.sin_addr.s_addr;
    *len = sizeof (struct net_addr);
    return SD(fd);
}

void _near
net_perror(str)
char _near *str;
{
    dfputs(str);
    dfputs(": Error ");
    printd(errno);
    dfputs("\r\n");
}

int _fastcall _near
tcpopen_accept(arg, len, buf)
int arg, _near *len;
void _far *buf;
{
    struct net_addr _far *addr = (struct net_addr _far *)buf;
    struct sockaddr_in in;
    int ns;

    ns = sizeof in;
    ns = accept(arg | FD_SOCKET, (fptr)&in, &ns);
    if (ns < 0)
	return ns;
    addr->host = in.sin_addr.s_addr;
    addr->socket = ntohs(in.sin_port);
    *len = sizeof (struct net_addr);
    return SD(ns);
}

#include <netinet/if.h>

int _fastcall _near
tcpopen_info(arg, len, buf)
int arg, _near *len;
void _far *buf;
{
    struct net_info _far *ni = (struct net_info _far *)buf;
    struct ifconf ifc;
    char ifbuf[128];

    ifc.ifc_len = sizeof ifbuf;
    ifc.ifc_buf = ifbuf;
    if (ioctl(arg | FD_SOCKET, SIOCGIFCONF, (fptr)&ifc) < 0)
	return -1;
    ni->ip_address = ((struct sockaddr_in far *)&ifc.ifc_req->ifr_addr)->sin_addr.s_addr;
#ifdef notdef
    ni->ip_broadcast = ((struct sockaddr_in far *)&ifc.ifc_req->ifr_broadaddr)->sin_addr.s_addr;
dfputs("broadcast=");
printn((u_short)(ni->ip_broadcast >> 16));
printn((u_short)ni->ip_broadcast);
dfputs("\r\n");
#endif
    ni->ip_broadcast = 0xffffffff;
    *len = sizeof (struct net_info);
    return 0;
}
