/*
 * Copyright (c) 1999 Erick Engelke
 */

#define ERTOS_NET_CORE 1

#include <tcp.h>
#include <rtos.h>
#include <stdio.h>

static crit_x *tcp_cs = NULL;


int rt_tcp_tick( void *s )
{
    int r;
    cs_enter( tcp_cs );
    r = tcp_tick( s );
    cs_exit( tcp_cs );
    return r;
}

/* low priority network tick function */
static void netthread( DWORD x )
{
    rt_setpriority( NULL, 127 );
    while ( 1 ) {
        rt_tcp_tick( NULL );
        rt_sleep(0);
    }
}

static void knetyield()
{
    /* called inside functions when we have nothing to do */
    cs_exit( tcp_cs );
    rt_sleep( 0 );
    cs_enter( tcp_cs );
}

void rt_sock_init()
{

extern int kctrlbrkhandler( void );

    if ( tcp_cs == NULL )
        tcp_cs = cs_alloc();
    cs_enter( tcp_cs );
    sock_init();
    sock_yield( NULL, knetyield );
    cs_exit( tcp_cs );
    rt_newthread( &netthread, 0, 4096, 0, "network heartbeat");
#if defined(__TURBOC__)||defined(__BORLANDC__)
    ctrlbrk( kctrlbrkhandler );
#endif

}


int rt_sock_fastread(void  *s, byte *dp, int len )
{
    int r;
    cs_enter( tcp_cs );
    r = sock_fastread( s, dp, len );
    cs_exit( tcp_cs );
    return r;
}

int rt_sock_fastwrite( void *s, byte *dp, int len )
{
    int r;
    cs_enter( tcp_cs );
    r = sock_fastwrite( s, dp, len );
    cs_exit( tcp_cs );
    return r;
}

int rt_sock_read(void  *s, byte *dp, int len )
{
    int r;
    cs_enter( tcp_cs );
    /* uses internal yield set up in open */
    r = sock_read( s, dp, len );
    cs_exit( tcp_cs );
    return r;
}

int rt_sock_write(void  *s, byte *dp, int len )
{
    int r;
    cs_enter( tcp_cs );
    /* uses internal yield set up in open */
    r = sock_write( s, dp, len );
    cs_exit( tcp_cs );
    return r;
}

void rt_sock_enqueue(void  *s, byte *dp, int len)
{
    cs_enter( tcp_cs );
    sock_enqueue( s, dp, len );
    cs_exit( tcp_cs );
    return;
}
int rt_sock_flush( void  *s )
{
    int r;
    cs_enter( tcp_cs );
    r = sock_flush( s );
    cs_exit( tcp_cs );
    return r;
}
int rt_sock_flushnext( void  *s)
{
    int r;
    cs_enter( tcp_cs );
    r = sock_flushnext( s );
    cs_exit( tcp_cs );
    return r;
}
int rt_sock_puts( void  *s, byte *dp )
{
    int r;
    cs_enter( tcp_cs );
    r = sock_puts( s, dp );
    cs_exit( tcp_cs );
    return r;
}
word rt_sock_gets( void  *s, byte *dp, int n )
{
    int r;
    cs_enter( tcp_cs );
    r = sock_gets( s, dp, n );
    cs_exit( tcp_cs );
    return r;
}
byte rt_sock_putc( void  *s, byte c )
{
    byte r;
    cs_enter( tcp_cs );
    r = sock_putc( s, c );
    cs_exit( tcp_cs );
    return r;
}


byte rt_sock_getc( void  *s )
{
    byte r;
    cs_enter( tcp_cs );
    r = sock_getc( s );
    cs_exit( tcp_cs );
    return r;
}
word rt_sock_dataready( void  *s )
{
    word r;
    cs_enter( tcp_cs );
    r = sock_dataready( s );
    cs_exit( tcp_cs );
    return r;
}
word rt_sock_close( void *s )
{
    word r;
    cs_enter( tcp_cs );
    r = sock_close( s );
    cs_exit( tcp_cs );
    return r;
}
int rt_sock_abort( void *s )
{
    int r;
    cs_enter( tcp_cs );
    r = sock_abort( s );
    cs_exit( tcp_cs );
    return r;
}
//extern sock_printf( void  *s, char *format, ... );
//extern sock_scanf( void  *s, char *format, ... );
int rt_sock_mode( void *s, word mode )
{
    int r;
    cs_enter( tcp_cs );
    r = sock_mode( s , mode );
    cs_exit( tcp_cs );
    return r;
}

/*
 * TCP or UDP specific stuff, must be used for open's and listens, but
 * sock stuff is used for everything else
 */
int rt_udp_open(void *s, word lport, longword ina, word port, int (*datahandler)())
{
    int r;
    cs_enter( tcp_cs );
    r = udp_open( s , lport, ina, port, datahandler );
    cs_exit( tcp_cs );
    return r;
}

int rt_tcp_open(void *s, word lport, longword ina, word port, int (*datahandler)())
{
    int r;
    cs_enter( tcp_cs );
    r = tcp_open( s , lport, ina, port, datahandler );
    cs_exit( tcp_cs );
    return r;
}

int rt_tcp_listen(void *s, word lport, longword ina, word port, int (*datahandler)(), word timeout)
{
    int r;
    cs_enter( tcp_cs );
    r = tcp_listen( s , lport, ina, port, datahandler, timeout );
    cs_exit( tcp_cs );
    return r;
}

int rt_tcp_established(void *s)
{
    int r;
    cs_enter( tcp_cs );
    r = tcp_established( s );
    cs_exit( tcp_cs );
    return r;
}

longword rt_resolve( char *name)
{
    longword r;
    cs_enter( tcp_cs );
    r = resolve( name );
    cs_exit( tcp_cs );
    return r;
}

#if defined(__TURBOC__)||defined(__BORLANDC__)
extern int reverse_addr_lookup( longword ipaddr, char *name );

int rt_reverse_addr_lookup( longword ipaddr, char *name )
{
    int x;
    cs_enter( tcp_cs );
    x = reverse_addr_lookup( ipaddr, name );
    cs_exit( tcp_cs );
    return x ;
}
#endif

/*
 * sock_wait_... macros
 */
/*
 * sock_wait_established()
 *	- waits then aborts if timeout on s connection
 * sock_wait_input()
 *	- waits for received input on s
 *	- may not be valid input for sock_Gets... check returned length
 * sock_tick()
 *	- do tick and jump on abort
 * sock_wait_closed();
 *	- discards all received data
 *
 * jump to sock_err with contents of *statusptr set to
 *	 1 on closed
 *	-1 on timeout
 *
 */
int _rt_ip_delay0( void *s, int seconds, int (*fn)(), void *statusptr )
{
    int r;
    cs_enter( tcp_cs );
    r = _ip_delay0( s, seconds, fn, statusptr );
    cs_exit( tcp_cs );
    return r;
}
int _rt_ip_delay1( void *s, int seconds, int (*fn)(), void *statusptr )
{
    int r;
    cs_enter( tcp_cs );
    r = _ip_delay1( s, seconds, fn, statusptr );
    cs_exit( tcp_cs );
    return r;
}
int _rt_ip_delay2( void *s, int seconds, int (*fn)(), void *statusptr )
{
    int r;
    cs_enter( tcp_cs );
    r = _ip_delay2( s, seconds, fn, statusptr );
    cs_exit( tcp_cs );
    return r;
}

/*
#define sock_wait_established( s, seconds, fn, statusptr ) \
    if (_rt_ip_delay0( s, seconds, fn, statusptr )) goto sock_err;
#define sock_wait_input( s, seconds, fn , statusptr ) \
    if (_rt_ip_delay1( s, seconds, fn, statusptr )) goto sock_err;
#define sock_tick( s, statusptr ) \
    if ( !rt_tcp_tick(s)) { if (statusptr) *statusptr = 1 ; goto sock_err; }
#define sock_wait_closed(s, seconds, fn, statusptr )\
    if (_rt_ip_delay2( s, seconds, fn, statusptr )) goto sock_err;
*/

extern int _send_ping( longword host, longword countnum, byte ttl, byte tos, longword *theid );

#if defined(__TURBOC__) || defined(__BORLANDC__)
int _rt_ping( longword host , longword countnum, byte ttl, byte tos, longword *theid  )
{
    int r;
    cs_enter( tcp_cs );
    r = _send_ping( host, countnum, ttl, tos, theid );
    cs_exit( tcp_cs );
    return r;
}

longword _rt_chk_ping( longword host , longword *ptr)
{
    longword r;
    cs_enter( tcp_cs );
    r = _chk_ping( host, ptr );
    cs_exit( tcp_cs );
    return r;
}
#endif // BorlandC


/*
 * recv routines -- pcrecv.c
 */
int rt_sock_recv_init( void *s, void *space, word len )
{
    int r;
    cs_enter( tcp_cs );
    r = sock_recv_init( s, space, len );
    cs_exit( tcp_cs );
    return r;
}
int rt_sock_recv_from( void *s, long *hisip, word *hisport, char *buffer, int len, word flags )
{
    int r;
    cs_enter( tcp_cs );
    r = sock_recv_from( s, hisip, hisport, buffer, len, flags );
    cs_exit( tcp_cs );
    return r;
}

int rt_sock_recv( void *s, char *buffer, int len, word flags )
{
    int r;
    cs_enter( tcp_cs );
    r = sock_recv( s, buffer, len, flags );
    cs_exit( tcp_cs );
    return r;
}


/* bsd-similar stuff */
/* .. */

