mirror of
https://github.com/SDL-Hercules-390/hyperion.git
synced 2026-04-13 15:35:41 +02:00
449 lines
15 KiB
C
449 lines
15 KiB
C
/* W32CTCA.C (c) Copyright "Fish" (David B. Trout), 2002-2014 */
|
|
/* CTCI-WIN (Channel to Channel link to Win32 TCP/IP stack) */
|
|
/* */
|
|
/* Released under "The Q Public License Version 1" */
|
|
/* (http://www.hercules-390.org/herclic.html) as modifications to */
|
|
/* Hercules. */
|
|
|
|
#include "hstdinc.h"
|
|
#include "hercules.h"
|
|
|
|
#if !defined(OPTION_W32_CTCI)
|
|
int w32ctca_dummy = 0;
|
|
#else // defined(OPTION_W32_CTCI)
|
|
|
|
#include "w32ctca.h"
|
|
#include "tt32api.h" // (exported TunTap32.dll functions)
|
|
#ifdef __CYGWIN__
|
|
#include <sys/cygwin.h> // (for cygwin_conv_to_full_win32_path)
|
|
#endif
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
// We prefer the '_ex' variety as they resolve the "no error" errno issue...
|
|
// But if they're not available we'll settle for the older version...
|
|
|
|
#define TT32_PROCADDRS( name ) \
|
|
\
|
|
ptuntap32_ ## name ## _ex g_tt32_pfn_ ## name ## _ex = NULL; \
|
|
ptuntap32_ ## name g_tt32_pfn_ ## name = NULL
|
|
|
|
#define _GET_TT32_PROCADDRS( name ) \
|
|
\
|
|
g_tt32_pfn_ ## name ## _ex = \
|
|
(ptuntap32_ ## name ## _ex ) GetProcAddress( g_tt32_hmoddll, \
|
|
"tuntap32_" # name "_ex" ); \
|
|
g_tt32_pfn_ ## name = \
|
|
(ptuntap32_ ## name ) GetProcAddress( g_tt32_hmoddll, \
|
|
"tuntap32_" # name )
|
|
|
|
#define GET_OPTIONAL_TT32_PROCADDR( name ) \
|
|
\
|
|
_GET_TT32_PROCADDRS( name )
|
|
|
|
#define GET_REQUIRED_TT32_PROCADDR( name ) \
|
|
\
|
|
_GET_TT32_PROCADDRS( name ); \
|
|
if ( !g_tt32_pfn_ ## name ) goto error
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
// Global variables...
|
|
|
|
#define TT32_DEFAULT_IFACE "00-00-5E-80-00-00"
|
|
|
|
CRITICAL_SECTION g_tt32_lock; // (lock for accessing ALL below variables)
|
|
|
|
char g_tt32_dllname [ MAX_TT32_DLLNAMELEN ] = {0};
|
|
HMODULE g_tt32_hmoddll = NULL;
|
|
|
|
TT32_PROCADDRS ( open );
|
|
TT32_PROCADDRS ( close );
|
|
TT32_PROCADDRS ( read );
|
|
TT32_PROCADDRS ( write );
|
|
TT32_PROCADDRS ( ioctl );
|
|
TT32_PROCADDRS ( get_stats );
|
|
TT32_PROCADDRS ( get_default_iface );
|
|
TT32_PROCADDRS ( set_debug_output_func );
|
|
TT32_PROCADDRS ( version_string );
|
|
TT32_PROCADDRS ( version_numbers );
|
|
TT32_PROCADDRS ( copyright_string );
|
|
TT32_PROCADDRS ( build_herc_iface_mac );
|
|
TT32_PROCADDRS ( beg_write_multi );
|
|
TT32_PROCADDRS ( end_write_multi );
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL GetTT32ProcAddrs()
|
|
{
|
|
// (required entry-points...)
|
|
|
|
GET_REQUIRED_TT32_PROCADDR ( open );
|
|
GET_REQUIRED_TT32_PROCADDR ( close );
|
|
GET_REQUIRED_TT32_PROCADDR ( read );
|
|
GET_REQUIRED_TT32_PROCADDR ( write );
|
|
GET_REQUIRED_TT32_PROCADDR ( ioctl );
|
|
GET_REQUIRED_TT32_PROCADDR ( get_stats );
|
|
GET_REQUIRED_TT32_PROCADDR ( get_default_iface );
|
|
GET_REQUIRED_TT32_PROCADDR ( set_debug_output_func );
|
|
GET_REQUIRED_TT32_PROCADDR ( version_string );
|
|
GET_REQUIRED_TT32_PROCADDR ( version_numbers );
|
|
GET_REQUIRED_TT32_PROCADDR ( copyright_string );
|
|
|
|
// (optional entry-points...)
|
|
|
|
GET_OPTIONAL_TT32_PROCADDR ( build_herc_iface_mac );
|
|
GET_OPTIONAL_TT32_PROCADDR ( beg_write_multi );
|
|
GET_OPTIONAL_TT32_PROCADDR ( end_write_multi );
|
|
|
|
LeaveCriticalSection(&g_tt32_lock);
|
|
return TRUE;
|
|
|
|
error:
|
|
|
|
FreeLibrary( g_tt32_hmoddll );
|
|
g_tt32_hmoddll = NULL;
|
|
WRMSG ( HHC04102, "E" );
|
|
LeaveCriticalSection(&g_tt32_lock);
|
|
return FALSE;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
// Debug string output function for use by the TUNTAP32.DLL...
|
|
|
|
void __cdecl tt32_output_debug_string( const char* debug_string )
|
|
{
|
|
// Remove all trailing whitespace to conform to Hercules logmsg format.
|
|
char* p = strdup( debug_string );
|
|
char* nl = p + strlen( p );
|
|
while (--nl > p && isspace(*nl)) *nl = 0;
|
|
WRMSG ( HHC90000, "D", p );
|
|
free(p);
|
|
}
|
|
|
|
void enable_tt32_debug_tracing( int enable )
|
|
{
|
|
// Pass to TunTap32 DLL a pointer to the function it can use to
|
|
// display debug messages with. This function of our's (that we
|
|
// are passing it a pointer to) will then display its debugging
|
|
// message (string) on the Hercules console so we can see it.
|
|
|
|
g_tt32_pfn_set_debug_output_func( enable ? &tt32_output_debug_string : NULL );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
// Load the TUNTAP32.DLL...
|
|
|
|
BOOL tt32_loaddll()
|
|
{
|
|
char* pszDLLName;
|
|
char tt32_dllname_in_buff [ MAX_PATH ];
|
|
char tt32_dllname_out_buff [ MAX_PATH ] = {0};
|
|
static int tt32_init_done = 0;
|
|
|
|
if (!tt32_init_done)
|
|
{
|
|
InitializeCriticalSection( &g_tt32_lock );
|
|
tt32_init_done = 1;
|
|
}
|
|
|
|
EnterCriticalSection(&g_tt32_lock);
|
|
|
|
if (g_tt32_hmoddll)
|
|
{
|
|
LeaveCriticalSection(&g_tt32_lock);
|
|
return TRUE;
|
|
}
|
|
|
|
// First, determine the name of the DLL we should try loading...
|
|
|
|
if ( !( pszDLLName = getenv( "HERCULES_IFC" ) ) )
|
|
pszDLLName = DEF_TT32_DLLNAME;
|
|
|
|
ASSERT( pszDLLName && *pszDLLName );
|
|
|
|
// Then check to see if the "name" contains path information or not...
|
|
|
|
if ( strchr( pszDLLName, '/' ) || strchr( pszDLLName, '\\' ) )
|
|
{
|
|
// It's already a path...
|
|
strlcpy( tt32_dllname_in_buff, pszDLLName, sizeof(tt32_dllname_in_buff) );
|
|
}
|
|
else
|
|
{
|
|
// It's not a path, so make it one, using loadable module path
|
|
|
|
strlcpy( tt32_dllname_in_buff, hdl_setpath(NULL,TRUE), sizeof(tt32_dllname_in_buff) );
|
|
strlcat( tt32_dllname_in_buff, PATHSEPS, sizeof(tt32_dllname_in_buff) );
|
|
strlcat( tt32_dllname_in_buff, pszDLLName, sizeof(tt32_dllname_in_buff) );
|
|
}
|
|
|
|
// Now convert it to a full path...
|
|
|
|
// PROGRAMMING NOTE: It's important here to ensure that our end result is a path
|
|
// with BACKWARD slashes in it and NOT forward slashes! LoadLibrary is one of the
|
|
// few Win32 functions that cannot handle paths with forward slashes in it. For
|
|
// 'open', etc, yeah, forward slashes are fine, but for LoadLibrary they're not!
|
|
|
|
#ifdef _MSVC_
|
|
if ( !_fullpath( tt32_dllname_out_buff, tt32_dllname_in_buff, sizeof(tt32_dllname_out_buff) ) )
|
|
strlcpy( tt32_dllname_out_buff, tt32_dllname_in_buff, sizeof(tt32_dllname_out_buff) );
|
|
#else // (presumed cygwin)
|
|
cygwin_conv_to_full_win32_path( tt32_dllname_in_buff, tt32_dllname_out_buff );
|
|
#endif // _MSVC_
|
|
|
|
tt32_dllname_out_buff[ sizeof(tt32_dllname_out_buff) - 1 ] = 0;
|
|
|
|
// Finally, copy it to our global home for it...
|
|
|
|
strlcpy( g_tt32_dllname, tt32_dllname_out_buff, sizeof(g_tt32_dllname) );
|
|
|
|
ASSERT(g_tt32_dllname[0]);
|
|
|
|
g_tt32_hmoddll = LoadLibraryEx( g_tt32_dllname, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
|
|
|
|
if (!g_tt32_hmoddll)
|
|
{
|
|
// Try again WITHOUT the path this time...
|
|
|
|
strlcpy( g_tt32_dllname, pszDLLName, sizeof(g_tt32_dllname) );
|
|
|
|
g_tt32_hmoddll = LoadLibraryEx( g_tt32_dllname, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
|
|
|
|
if (!g_tt32_hmoddll)
|
|
{
|
|
char str[MAX_TT32_DLLNAMELEN + 32];
|
|
DWORD dwLastError = GetLastError();
|
|
LeaveCriticalSection(&g_tt32_lock);
|
|
sprintf(str, "LoadLibraryEx(%s)", g_tt32_dllname);
|
|
WRMSG ( HHC00161, "E", str, (int)dwLastError, strerror(dwLastError) );
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// Resolve our required DLL entry-point variables...
|
|
|
|
if (!GetTT32ProcAddrs())
|
|
return FALSE;
|
|
|
|
WRMSG ( HHC04100, "I", g_tt32_dllname, g_tt32_pfn_version_string() );
|
|
|
|
#if defined(DEBUG) || defined(_DEBUG)
|
|
enable_tt32_debug_tracing(1); // (enable debug tracing by default for DEBUG builds)
|
|
#endif
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
int tt32_open( char* pszGatewayDevice, int iFlags )
|
|
{
|
|
int rc, errnum;
|
|
if (!tt32_loaddll()) return -1;
|
|
if (! g_tt32_pfn_open_ex )
|
|
return g_tt32_pfn_open ( pszGatewayDevice, iFlags );
|
|
rc = g_tt32_pfn_open_ex ( pszGatewayDevice, iFlags, &errnum );
|
|
errno = errnum;
|
|
return rc;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
int tt32_read( int fd, u_char* buffer, u_long size )
|
|
{
|
|
int rc, errnum;
|
|
if (!tt32_loaddll()) return -1;
|
|
if (! g_tt32_pfn_read_ex )
|
|
return g_tt32_pfn_read ( fd, buffer, size );
|
|
rc = g_tt32_pfn_read_ex ( fd, buffer, size, &errnum );
|
|
errno = errnum;
|
|
return rc;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
int tt32_write( int fd, u_char* buffer, u_long size )
|
|
{
|
|
int rc, errnum;
|
|
if (!tt32_loaddll()) return -1;
|
|
if (! g_tt32_pfn_write_ex )
|
|
return g_tt32_pfn_write ( fd, buffer, size );
|
|
rc = g_tt32_pfn_write_ex ( fd, buffer, size, &errnum );
|
|
errno = errnum;
|
|
return rc;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
int tt32_beg_write_multi( int fd, u_long bufsiz )
|
|
{
|
|
int rc; if (!tt32_loaddll()) return -1;
|
|
|
|
if ( g_tt32_pfn_beg_write_multi_ex ) { int errnum;
|
|
rc = g_tt32_pfn_beg_write_multi_ex ( fd, bufsiz, &errnum );
|
|
errno = errnum;} else
|
|
if ( g_tt32_pfn_beg_write_multi )
|
|
rc = g_tt32_pfn_beg_write_multi ( fd, bufsiz );
|
|
else
|
|
rc = 0; // (don't fail, treat as nop instead)
|
|
return rc;
|
|
}
|
|
|
|
int tt32_end_write_multi( int fd )
|
|
{
|
|
int rc; if (!tt32_loaddll()) return -1;
|
|
|
|
if ( g_tt32_pfn_end_write_multi_ex ) { int errnum;
|
|
rc = g_tt32_pfn_end_write_multi_ex ( fd, &errnum );
|
|
errno = errnum;} else
|
|
if ( g_tt32_pfn_end_write_multi )
|
|
rc = g_tt32_pfn_end_write_multi ( fd );
|
|
else
|
|
rc = 0; // (don't fail, treat as nop instead)
|
|
return rc;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
int tt32_close( int fd )
|
|
{
|
|
int rc, errnum;
|
|
if (!tt32_loaddll()) return -1;
|
|
#if defined(DEBUG) || defined(_DEBUG)
|
|
display_tt32_stats(fd);
|
|
#endif
|
|
if (! g_tt32_pfn_close_ex )
|
|
return g_tt32_pfn_close ( fd );
|
|
rc = g_tt32_pfn_close_ex ( fd, &errnum );
|
|
errno = errnum;
|
|
return rc;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
int tt32_ioctl( int fd, int iRequest, char* argp )
|
|
{
|
|
int rc, errnum;
|
|
if (!tt32_loaddll()) return -1;
|
|
if (! g_tt32_pfn_ioctl_ex )
|
|
return g_tt32_pfn_ioctl ( fd, iRequest, argp );
|
|
rc = g_tt32_pfn_ioctl_ex ( fd, iRequest, argp, &errnum );
|
|
errno = errnum;
|
|
return rc;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
const char* tt32_get_default_iface()
|
|
{
|
|
int errnum;
|
|
const char* pszDefaultIFace = NULL;
|
|
if (tt32_loaddll())
|
|
{
|
|
if (! g_tt32_pfn_get_default_iface_ex )
|
|
pszDefaultIFace = g_tt32_pfn_get_default_iface ();
|
|
else { pszDefaultIFace = g_tt32_pfn_get_default_iface_ex ( &errnum );
|
|
errno = errnum;
|
|
}
|
|
}
|
|
return ( pszDefaultIFace ? pszDefaultIFace : TT32_DEFAULT_IFACE );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
int display_tt32_stats( int fd )
|
|
{
|
|
int errnum;
|
|
TT32STATS stats;
|
|
|
|
if (!tt32_loaddll()) return -1;
|
|
|
|
memset(&stats, 0, sizeof(stats));
|
|
stats.dwStructSize = sizeof(stats);
|
|
|
|
if (! g_tt32_pfn_get_stats_ex )
|
|
g_tt32_pfn_get_stats ( fd, &stats );
|
|
else { g_tt32_pfn_get_stats_ex ( fd, &stats, &errnum );
|
|
errno = errnum;
|
|
}
|
|
|
|
if (stats.dwStructSize >= sizeof(stats))
|
|
{
|
|
// New version 3.3 stats
|
|
|
|
WRMSG (HHC04101, "I"
|
|
,g_tt32_dllname
|
|
|
|
,(stats.dwKernelBuffSize + 1023) / 1024
|
|
,(stats.dwReadBuffSize + 1023) / 1024
|
|
,(stats.dwMaxBytesReceived + 1023) / 1024
|
|
|
|
,stats.n64WriteCalls
|
|
,stats.n64WriteIOs
|
|
,stats.n64ZeroMACPacketsWritten
|
|
,stats.n64PacketsWritten
|
|
,stats.n64BytesWritten
|
|
|
|
,stats.n64ReadCalls
|
|
,stats.n64ReadIOs
|
|
,stats.n64InternalPackets
|
|
,stats.n64OwnPacketsIgnored
|
|
,stats.n64IgnoredPackets
|
|
,stats.n64ZeroMACPacketsRead
|
|
,stats.n64PacketsRead
|
|
,stats.n64BytesRead
|
|
);
|
|
}
|
|
else
|
|
{
|
|
// Old pre version 3.3 stats
|
|
|
|
WRMSG (HHC04101, "I"
|
|
,g_tt32_dllname
|
|
|
|
,(stats.dwKernelBuffSize + 1023) / 1024
|
|
,(stats.dwReadBuffSize + 1023) / 1024
|
|
,(stats.dwMaxBytesReceived + 1023) / 1024
|
|
|
|
,stats.n64WriteCalls
|
|
,stats.n64WriteIOs
|
|
,-1 // indicate n/a
|
|
,stats.n64PacketsWritten
|
|
,stats.n64BytesWritten
|
|
|
|
,stats.n64ReadCalls
|
|
,stats.n64ReadIOs
|
|
,stats.n64InternalPackets
|
|
,-1 // indicate n/a
|
|
,stats.n64IgnoredPackets
|
|
,-1 // indicate n/a
|
|
,stats.n64PacketsRead
|
|
,stats.n64BytesRead
|
|
);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
// BOOLEAN FUNCTION
|
|
|
|
int tt32_build_herc_iface_mac ( BYTE* out_mac, const BYTE* in_ip )
|
|
{
|
|
// We prefer to let TunTap32 do it for us (since IT'S the one
|
|
// that decides what it should really be) but if they're using
|
|
// an older version of TunTap32 that doesn't have the function
|
|
// then we'll do it ourselves just like before...
|
|
|
|
if (!g_tt32_pfn_build_herc_iface_mac)
|
|
return 0; // (FALSE: must do it yourself)
|
|
|
|
g_tt32_pfn_build_herc_iface_mac( out_mac, in_ip );
|
|
return 1; // (TRUE: ok we did it for you)
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#endif // !defined(OPTION_W32_CTCI)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|