/*
 * Copyright (c) 1995 Sun Microsystems, Inc.
 * All rights reserved.
 * 
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the
 * above copyright notice and the following two paragraphs appear in
 * all copies of this software.
 * 
 * IN NO EVENT SHALL SUN MICROSYSTEMS, INC. BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING
 * OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF SUN
 * MICROSYSTEMS, INC. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * SUN MICROSYSTEMS, INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THE SOFTWARE PROVIDED
 * HEREUNDER IS ON AN "AS IS" BASIS, AND SUN MICROSYSTEMS, INC. HAS NO
 * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
 * MODIFICATIONS.
 */

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <thread.h>

#include <tcl.h>
#include <tk.h>
#include "doomarena.h"


int
ServerStartCmd(
     ClientData clientData,
     Tcl_Interp *interp,
     int argc,
     char **argv
)
{
    struct hostent *hostent;
    struct sockaddr_in server_addr;
    int sock, port, rc;
    int one= 1;
    FILE *file;

    if ( argc != 2)  {
	interp->result= "wrong # args; become_server port";
	return TCL_ERROR;
    }

    if ( Tcl_GetInt( interp, argv[1], &port) == TCL_ERROR)
	return TCL_ERROR;

    sock= socket( AF_INET, SOCK_STREAM, 0);
    if ( sock < 0)  {
	interp->result= strerror( errno);
	return TCL_ERROR;
    }

    (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
		(char *)&one, sizeof(int));

    memset( &server_addr, 0, sizeof ( server_addr));
    server_addr.sin_family= AF_INET;
    server_addr.sin_port= htons(port);
    server_addr.sin_addr.s_addr= htonl( INADDR_ANY);

    rc= bind( sock, (struct sockaddr *) &server_addr, sizeof( server_addr));
    if ( rc < 0)  {
	interp->result= strerror( errno);
	close( sock);
	return TCL_ERROR;
    }

    listen( sock, 25);

    file= fdopen( sock, "r+");
    setvbuf( file, NULL, _IOLBF, BUFSIZ);
    Tcl_EnterFile( interp, file, TCL_FILE_READABLE|TCL_FILE_WRITABLE);
    return TCL_OK;
}

int
ServerAcceptCmd(
    ClientData clientData,
    Tcl_Interp *interp,
    int argc,
    char **argv
)
{
    struct sockaddr_in client_addr;
    int addr_len= sizeof ( client_addr);
    int client_sock, server_sock;
    FILE *file;

    if ( argc != 2)  {
	interp->result= "wrong # args; tcp_server_accept sockId";
	return TCL_ERROR;
    }

    if (Tcl_GetOpenFile (interp, argv[1], 0, 0, &file) != TCL_OK)
        return TCL_ERROR;

    server_sock= fileno( file);
    client_sock= accept( server_sock, (struct sockaddr *) &client_addr,
								&addr_len);
    if ( client_sock < 0)  {
	interp->result= strerror( errno);
	return TCL_ERROR;
    }
    
    file= fdopen( client_sock, "r+");
    setvbuf( file, NULL, _IOLBF, BUFSIZ);
    Tcl_EnterFile( interp, file, TCL_FILE_READABLE|TCL_FILE_WRITABLE);
    return TCL_OK;
}

int
ServerConnectCmd(
    ClientData clientData,
    Tcl_Interp *interp,
    int argc,
    char **argv
)
{
    struct sockaddr_in server_addr;
    struct hostent *hostent;
    int addr_len= sizeof ( server_addr);
    int client_sock, rc, port;
    FILE *file;

    if ( argc != 3)  {
	interp->result= "wrong # args; tcp_server_connect host port";
	return TCL_ERROR;
    }

    if ( Tcl_GetInt( interp, argv[2], &port) == TCL_ERROR)
	return TCL_ERROR;
 
    hostent= gethostbyname( argv[1]);
    if ( hostent == NULL)  {
	interp->result= "host not found";
	return TCL_ERROR;
    }

    memset( &server_addr, 0, sizeof ( server_addr));
    server_addr.sin_family= AF_INET;
    server_addr.sin_addr.s_addr= *((unsigned long *)hostent->h_addr_list[0]);
    server_addr.sin_port= port;

    client_sock= socket( AF_INET, SOCK_STREAM, 0);
    if (client_sock < 0)  {
	interp->result= strerror( errno);
	return TCL_ERROR;
    }
 
    rc= connect( client_sock, (struct sockaddr *) &server_addr,
					sizeof( server_addr));
    if (rc < 0)  {
	interp->result= strerror( errno);
	close( client_sock);
	return TCL_ERROR;
    }

    file= fdopen( client_sock, "r+");
    setvbuf( file, NULL, _IOLBF, BUFSIZ);
    Tcl_EnterFile( interp, file, TCL_FILE_READABLE|TCL_FILE_WRITABLE);
    return TCL_OK;
}
