/* 
   Unix SMB/Netbios implementation.
   Version 1.9.
   Copyright (C) Andrew Tridgell 1994-1997

   This file is part of the port to OpenVMS
   TCP/IP specific routines.
   Copyright (C) Eckart Meyer 1996-1997
   
   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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*	tcp.c
 *	V2.0			25-Mar-1997	IfN/Mey
 *
 *	Copyright E. Meyer <meyer@ifn.ing.tu-bs.de>
 *+
 * Samba VMS TCP/IP routines.
 *-
 */

#define const
#include <stdio.h>
#if 0
#include <stdlib.h>
#include <unistd.h>
#if __DECC_VER < 50200000  ||  __VMS_VER < 70000000
#include <unixio.h>
#endif
#endif
/* #include <string.h> /**/
#include <errno.h>
#include <socket.h>
/* #include <in.h> /**/
#include <ioctl.h>

#include <starlet.h>
#include <iodef.h>
#include <lib$routines.h>
#include <descrip.h>

/* SAMBA debugging */
extern int DEBUGLEVEL;
#define DEBUG(level,body) ((DEBUGLEVEL>=(level))?(Debug1 body):0)
int Debug1();

struct itm_list_2 {
	unsigned short len;
	unsigned short code;
	void *bufadr;
};

struct itm_list_3 {
	unsigned short len;
	unsigned short code;
	void *bufadr;
	short int *retadr;
};

/*
 * UCX only.
 */ 

/*
 * get_tcpip_package - NOP
 */

int get_tcpip_package()
{
	return 0;
}

#ifdef __DECC
#define get_sdc decc$get_sdc
#else
#define get_sdc vaxc$get_sdc
#endif

/*
 * UCX definitions
 * from ucx$inetdef.h
 */
#define UCX$C_SOCKOPT 1
#define UCX$C_AUXS 127
#define UCX$C_TCP 6
#define UCX$C_IOCTL 2
#define INET_PROTYP$C_STREAM 1

/*
 * setsockopt
 */
int vms_setsockopt (int sd, int level, int optname, char *optval, int optlen)
{
	return(setsockopt(sd, level, optname, optval, optlen));
}

/*
 * socket
 */
#define TCPSRV 127
int vms_socket (int af, int mess_type, int prot_type)
{
	return(socket(af, mess_type, prot_type));
}

/*
 * getpeername
 */
int vms_getpeername (int sd, struct sockaddr *name, int *namelen)
{
	return(getpeername(sd, name, namelen));
}


#define F_GETFL 3
#define VMSOK(s) (s & 1)

/*
 * fcntl
 *
 * Standard C RTL or UCX does not have fcntl().
 *
 * This one is good for setting blocking state (FIONBIO) only.
 */
int vms_fcntl   (int fd, int cmd, int val)
{
    int argp;
    int ef;			/* Event flag number */
    int sdc;			/* Socket device channel */
    unsigned short fun; 	/* Qiow function code  */
    unsigned short iosb[4];	/* Io status block */
    char *p5, *p6;			/* Args p5 & p6 of qiow */
    struct comm
    {
	int command;
	char *addr;
    } ioctl_comm;		/* Qiow ioctl commands. */
    struct it2 
    {
	unsigned short len;
	unsigned short opt;
	struct comm *addr;
    } ioctl_desc;		/* Qiow ioctl commands descriptor */
    int status;
    int get_sdc(int __fd);
    
    /* 
     * Gets an event flag for qio
     */
    status = lib$get_ef(&ef);
    if (!VMSOK(status))
    {
	/* No ef available. Use 0 */
	ef = 0;
    }

    /* 
     * Get the socket device channel number.
     */
    sdc = get_sdc(fd);
    if (sdc == 0)
    {
	/* Not an open socket descriptor. */
	errno = EBADF;
	status = lib$free_ef(&ef);
	return (-1);
    }
    
    /* 
     * Fill in ioctl descriptor.
     */
    ioctl_desc.opt = UCX$C_IOCTL;
    ioctl_desc.len = sizeof(struct comm);
    ioctl_desc.addr = &ioctl_comm;
    
    /* 
     * Decide qio function code and in/out parameter.
     */
    if (cmd == F_GETFL)
    {
/*
	fun = IO$_SENSEMODE;
	p5 = 0;
	p6 = (char *) &ioctl_desc;
*/
	return(0);
    }
    else
    {
	fun = IO$_SETMODE;
	p5 = (char *) &ioctl_desc;
	p6 = 0;
    }

    /* 
     * Fill in ioctl command.
     */
    ioctl_comm.command = FIONBIO;	/* we only support this call */
    ioctl_comm.addr = (char *)&argp;
    if (val == 0) {
	argp = 0;
    } else {
	argp = 1;
    }
    
    /* 
     * Do ioctl.
     */
    status = sys$qiow(ef, sdc, fun, iosb, 0, 0,
		      0, 0, 0, 0,		/* p1 - p4: not used*/
		      p5, p6);
    
    if (!VMSOK(status))
    {
DEBUG (0,("ioctl failed: status = %d\n", status));
	errno = status;
	status = lib$free_ef(&ef);
	return (-1);
    }
    
    if (!VMSOK(iosb[0]))
    {
DEBUG (0,("ioctl failed: status = %x, %x, %x%x\n", iosb[0], iosb[1],
iosb[3], iosb[2]));
	errno = iosb[0];
    	status = lib$free_ef(&ef);
	return (-1);
    }
    
    status = lib$free_ef(&ef);
    return (0);
}

