Uthernet II: add virtual DNS feature (PR #1097)

Uthernet II: add extended feature to virtualise DNS requests.
. This allows pure TCP/UDP sockets to run *without* MACRAW requests (and so without libpcap).
. Raw sockets will not work.
. Add configuration for Virtual DNS.
libpcap: ensure all functions check if the library is loaded before using it.
Uthernet 1: do NOT overwrite tfe_cannot_use as it should only reflect the availability of npcap on *this* system.
Add Copyright notice, and mention Virtual DNS in html.
This commit is contained in:
Andrea 2022-05-08 17:26:01 +02:00 committed by GitHub
parent ccb4582bf9
commit 6a5ea92a4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 539 additions and 226 deletions

View File

@ -114,6 +114,7 @@
<ClInclude Include="source\StrFormat.h" /> <ClInclude Include="source\StrFormat.h" />
<ClInclude Include="source\SynchronousEventManager.h" /> <ClInclude Include="source\SynchronousEventManager.h" />
<ClInclude Include="source\Tape.h" /> <ClInclude Include="source\Tape.h" />
<ClInclude Include="source\Tfe\DNS.h" />
<ClInclude Include="source\Tfe\IPRaw.h" /> <ClInclude Include="source\Tfe\IPRaw.h" />
<ClInclude Include="source\Tfe\NetworkBackend.h" /> <ClInclude Include="source\Tfe\NetworkBackend.h" />
<ClInclude Include="source\Tfe\Bpf.h" /> <ClInclude Include="source\Tfe\Bpf.h" />
@ -157,6 +158,7 @@
<ClCompile Include="source\CardManager.cpp" /> <ClCompile Include="source\CardManager.cpp" />
<ClCompile Include="source\CmdLine.cpp" /> <ClCompile Include="source\CmdLine.cpp" />
<ClCompile Include="source\Configuration\About.cpp" /> <ClCompile Include="source\Configuration\About.cpp" />
<ClCompile Include="source\Configuration\Config.cpp" />
<ClCompile Include="source\Configuration\PageAdvanced.cpp" /> <ClCompile Include="source\Configuration\PageAdvanced.cpp" />
<ClCompile Include="source\Configuration\PageConfig.cpp" /> <ClCompile Include="source\Configuration\PageConfig.cpp" />
<ClCompile Include="source\Configuration\PageConfigTfe.cpp" /> <ClCompile Include="source\Configuration\PageConfigTfe.cpp" />
@ -223,6 +225,7 @@
<ClCompile Include="source\StrFormat.cpp" /> <ClCompile Include="source\StrFormat.cpp" />
<ClCompile Include="source\SynchronousEventManager.cpp" /> <ClCompile Include="source\SynchronousEventManager.cpp" />
<ClCompile Include="source\Tape.cpp" /> <ClCompile Include="source\Tape.cpp" />
<ClCompile Include="source\Tfe\DNS.cpp" />
<ClCompile Include="source\Tfe\IPRaw.cpp" /> <ClCompile Include="source\Tfe\IPRaw.cpp" />
<ClCompile Include="source\Tfe\NetworkBackend.cpp" /> <ClCompile Include="source\Tfe\NetworkBackend.cpp" />
<ClCompile Include="source\Tfe\PCapBackend.cpp" /> <ClCompile Include="source\Tfe\PCapBackend.cpp" />

View File

@ -262,6 +262,12 @@
<ClCompile Include="source\Tfe\IPRaw.cpp"> <ClCompile Include="source\Tfe\IPRaw.cpp">
<Filter>Source Files\Uthernet</Filter> <Filter>Source Files\Uthernet</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="source\Tfe\DNS.cpp">
<Filter>Source Files\Uthernet</Filter>
</ClCompile>
<ClCompile Include="source\Configuration\Config.cpp">
<Filter>Source Files\Configuration</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="source\CommonVICE\6510core.h"> <ClInclude Include="source\CommonVICE\6510core.h">
@ -600,6 +606,9 @@
<ClInclude Include="source\Tfe\IPRaw.h"> <ClInclude Include="source\Tfe\IPRaw.h">
<Filter>Source Files\Uthernet</Filter> <Filter>Source Files\Uthernet</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="source\Tfe\DNS.h">
<Filter>Source Files\Uthernet</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Image Include="resource\Applewin.bmp"> <Image Include="resource\Applewin.bmp">

View File

@ -97,5 +97,8 @@
<li>after loading a save-state file, TCP and UDP sockets are closed</li> <li>after loading a save-state file, TCP and UDP sockets are closed</li>
</ul> </ul>
</P> </P>
<P>The card implements a <A href="https://github.com/a2retrosystems/uthernet2/wiki/Virtual-W5100-with-DNS">Virtual DNS</A>
interface (not found on real hardware) for Apple II software to run without raw sockets:
this allows operation on any type of network.</P>
</body> </body>
</html> </html>

View File

@ -206,19 +206,22 @@ BEGIN
PUSHBUTTON "&Browse...",IDC_CIDERPRESS_BROWSE,161,202,50,14 PUSHBUTTON "&Browse...",IDC_CIDERPRESS_BROWSE,161,202,50,14
END END
IDD_TFE_SETTINGS_DIALOG DIALOGEX 0, 0, 270, 100 IDD_TFE_SETTINGS_DIALOG DIALOGEX 0, 0, 271, 155
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Ethernet Settings" CAPTION "Ethernet Settings"
FONT 8, "MS Shell Dlg", 0, 0, 0x0 FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN BEGIN
LTEXT "Ethernet",IDC_TFE_SETTINGS_ENABLE_T,9,7,30,8 LTEXT "Ethernet",IDC_TFE_SETTINGS_ENABLE_T,9,7,30,8
COMBOBOX IDC_TFE_SETTINGS_ENABLE,45,5,60,80,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_TFE_SETTINGS_ENABLE,45,5,60,80,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
CONTROL "Virtual DNS",IDC_CHECK_TFE_VIRTUAL_DNS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,7,50,8
LTEXT "Interface",IDC_TFE_SETTINGS_INTERFACE_T,9,24,30,8 LTEXT "Interface",IDC_TFE_SETTINGS_INTERFACE_T,9,24,30,8
COMBOBOX IDC_TFE_SETTINGS_INTERFACE,45,22,210,80,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_TFE_SETTINGS_INTERFACE,45,22,210,80,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "",IDC_TFE_SETTINGS_INTERFACE_NAME,9,44,250,8 LTEXT "",IDC_TFE_SETTINGS_INTERFACE_NAME,9,44,250,8
LTEXT "",IDC_TFE_SETTINGS_INTERFACE_DESC,9,60,250,8 LTEXT "",IDC_TFE_SETTINGS_INTERFACE_DESC,9,60,250,8
DEFPUSHBUTTON "Ok",IDOK,20,75,50,14 GROUPBOX "Npcap",IDC_STATIC,5,75,260,55
PUSHBUTTON "Cancel",IDCANCEL,80,75,50,14 LTEXT "",IDC_TFE_NPCAP_INFO,12,86,240,36
DEFPUSHBUTTON "Ok",IDOK,20,135,50,14
PUSHBUTTON "Cancel",IDCANCEL,80,135,50,14
END END
IDD_PROPPAGE_ADVANCED DIALOGEX 0, 0, 210, 217 IDD_PROPPAGE_ADVANCED DIALOGEX 0, 0, 210, 217

View File

@ -119,6 +119,8 @@
#define IDC_FOURPLAY_CONFIG 1087 #define IDC_FOURPLAY_CONFIG 1087
#define IDC_SNESMAX_CONFIG 1088 #define IDC_SNESMAX_CONFIG 1088
#define IDC_CHECK_VIDHD_IN_SLOT3 1089 #define IDC_CHECK_VIDHD_IN_SLOT3 1089
#define IDC_CHECK_TFE_VIRTUAL_DNS 1090
#define IDC_TFE_NPCAP_INFO 1091
#define IDM_EXIT 40001 #define IDM_EXIT 40001
#define IDM_HELP 40002 #define IDM_HELP 40002
#define IDM_ABOUT 40003 #define IDM_ABOUT 40003

View File

@ -108,6 +108,7 @@ enum AppMode_e
#define REGVALUE_WINDOW_SCALE "Window Scale" #define REGVALUE_WINDOW_SCALE "Window Scale"
#define REGVALUE_UTHERNET_ACTIVE "Uthernet Active" // GH#977: Deprecated from 1.30.5 #define REGVALUE_UTHERNET_ACTIVE "Uthernet Active" // GH#977: Deprecated from 1.30.5
#define REGVALUE_UTHERNET_INTERFACE "Uthernet Interface" #define REGVALUE_UTHERNET_INTERFACE "Uthernet Interface"
#define REGVALUE_UTHERNET_VIRTUAL_DNS "Uthernet Virtual DNS"
#define REGVALUE_SLOT4 "Slot 4" // GH#977: Deprecated from 1.30.4 #define REGVALUE_SLOT4 "Slot 4" // GH#977: Deprecated from 1.30.4
#define REGVALUE_SLOT5 "Slot 5" // GH#977: Deprecated from 1.30.4 #define REGVALUE_SLOT5 "Slot 5" // GH#977: Deprecated from 1.30.4
#define REGVALUE_VERSION "Version" #define REGVALUE_VERSION "Version"

View File

@ -0,0 +1,98 @@
/*
AppleWin : An Apple //e emulator for Windows
Copyright (C) 1994-1996, Michael O'Brien
Copyright (C) 1999-2001, Oliver Schmidt
Copyright (C) 2002-2005, Tom Charlesworth
Copyright (C) 2006-2007, Tom Charlesworth, Michael Pohoreski
AppleWin 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.
AppleWin 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 AppleWin; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "StdAfx.h"
#include "Config.h"
#include "../CardManager.h"
#include "../Interface.h" // VideoRefreshRate_e, GetVideoRefreshRate()
#include "../Uthernet2.h"
#include "../Tfe/PCapBackend.h"
// zero initialise
CConfigNeedingRestart::CConfigNeedingRestart()
{
m_Apple2Type = A2TYPE_APPLE2;
m_CpuType = CPU_UNKNOWN;
memset(m_Slot, 0, sizeof(m_Slot));
m_SlotAux = CT_Empty;
m_tfeVirtualDNS = false;
m_bEnableTheFreezesF8Rom = 0;
m_uSaveLoadStateMsg = 0;
m_videoRefreshRate = VR_NONE;
}
// create from current global configuration
CConfigNeedingRestart CConfigNeedingRestart::Create()
{
CConfigNeedingRestart config;
config.Reload();
return config;
}
// update from current global configuration
void CConfigNeedingRestart::Reload()
{
m_Apple2Type = GetApple2Type();
m_CpuType = GetMainCpu();
CardManager& cardManager = GetCardMgr();
for (UINT slot = SLOT0; slot < NUM_SLOTS; slot++)
m_Slot[slot] = cardManager.QuerySlot(slot);
m_SlotAux = cardManager.QueryAux();
m_tfeInterface = PCapBackend::GetRegistryInterface(SLOT3);
m_tfeVirtualDNS = Uthernet2::GetRegistryVirtualDNS(SLOT3);
m_bEnableTheFreezesF8Rom = GetPropertySheet().GetTheFreezesF8Rom();
m_uSaveLoadStateMsg = 0;
m_videoRefreshRate = GetVideo().GetVideoRefreshRate();
}
const CConfigNeedingRestart& CConfigNeedingRestart::operator= (const CConfigNeedingRestart& other)
{
m_Apple2Type = other.m_Apple2Type;
m_CpuType = other.m_CpuType;
memcpy(m_Slot, other.m_Slot, sizeof(m_Slot));
m_SlotAux = other.m_SlotAux;
m_tfeInterface = other.m_tfeInterface;
m_tfeVirtualDNS = other.m_tfeVirtualDNS;
m_bEnableTheFreezesF8Rom = other.m_bEnableTheFreezesF8Rom;
m_uSaveLoadStateMsg = other.m_uSaveLoadStateMsg;
m_videoRefreshRate = other.m_videoRefreshRate;
return *this;
}
bool CConfigNeedingRestart::operator== (const CConfigNeedingRestart& other) const
{
return m_Apple2Type == other.m_Apple2Type &&
m_CpuType == other.m_CpuType &&
memcmp(m_Slot, other.m_Slot, sizeof(m_Slot)) == 0 &&
m_SlotAux == other.m_SlotAux &&
m_tfeInterface == other.m_tfeInterface &&
m_tfeVirtualDNS == other.m_tfeVirtualDNS &&
m_bEnableTheFreezesF8Rom == other.m_bEnableTheFreezesF8Rom &&
m_uSaveLoadStateMsg == other.m_uSaveLoadStateMsg &&
m_videoRefreshRate == other.m_videoRefreshRate;
}
bool CConfigNeedingRestart::operator!= (const CConfigNeedingRestart& other) const
{
return !operator==(other);
}

View File

@ -1,86 +1,33 @@
#pragma once #pragma once
#include "../Core.h" #include "../Core.h"
#include "../CardManager.h"
#include "../CPU.h" #include "../CPU.h"
#include "../DiskImage.h" // Disk_Status_e #include "../Video.h"
#include "../Harddisk.h"
#include "../Interface.h" // VideoRefreshRate_e, GetVideoRefreshRate()
#include "../Tfe/PCapBackend.h"
class CConfigNeedingRestart class CConfigNeedingRestart
{ {
public: public:
// zero initialise // zero initialise
CConfigNeedingRestart() CConfigNeedingRestart();
{
m_Apple2Type = A2TYPE_APPLE2;
m_CpuType = CPU_UNKNOWN;
memset(m_Slot, 0, sizeof(m_Slot));
m_SlotAux = CT_Empty;
m_bEnableTheFreezesF8Rom = 0;
m_uSaveLoadStateMsg = 0;
m_videoRefreshRate = VR_NONE;
}
// create from current global configuration // create from current global configuration
static CConfigNeedingRestart Create() static CConfigNeedingRestart Create();
{
CConfigNeedingRestart config;
config.Reload();
return config;
}
// update from current global configuration // update from current global configuration
void Reload() void Reload();
{
m_Apple2Type = GetApple2Type();
m_CpuType = GetMainCpu();
CardManager& cardManager = GetCardMgr();
for (UINT slot = SLOT0; slot < NUM_SLOTS; slot++)
m_Slot[slot] = cardManager.QuerySlot(slot);
m_SlotAux = cardManager.QueryAux();
m_tfeInterface = PCapBackend::tfe_interface;
m_bEnableTheFreezesF8Rom = GetPropertySheet().GetTheFreezesF8Rom();
m_uSaveLoadStateMsg = 0;
m_videoRefreshRate = GetVideo().GetVideoRefreshRate();
}
const CConfigNeedingRestart& operator= (const CConfigNeedingRestart& other) const CConfigNeedingRestart& operator= (const CConfigNeedingRestart& other);
{
m_Apple2Type = other.m_Apple2Type;
m_CpuType = other.m_CpuType;
memcpy(m_Slot, other.m_Slot, sizeof(m_Slot));
m_SlotAux = other.m_SlotAux;
m_tfeInterface = other.m_tfeInterface;
m_bEnableTheFreezesF8Rom = other.m_bEnableTheFreezesF8Rom;
m_uSaveLoadStateMsg = other.m_uSaveLoadStateMsg;
m_videoRefreshRate = other.m_videoRefreshRate;
return *this;
}
bool operator== (const CConfigNeedingRestart& other) const bool operator== (const CConfigNeedingRestart& other) const;
{
return m_Apple2Type == other.m_Apple2Type &&
m_CpuType == other.m_CpuType &&
memcmp(m_Slot, other.m_Slot, sizeof(m_Slot)) == 0 &&
m_SlotAux == other.m_SlotAux &&
m_tfeInterface == other.m_tfeInterface &&
m_bEnableTheFreezesF8Rom == other.m_bEnableTheFreezesF8Rom &&
m_uSaveLoadStateMsg == other.m_uSaveLoadStateMsg &&
m_videoRefreshRate == other.m_videoRefreshRate;
}
bool operator!= (const CConfigNeedingRestart& other) const bool operator!= (const CConfigNeedingRestart& other) const;
{
return !operator==(other);
}
eApple2Type m_Apple2Type; eApple2Type m_Apple2Type;
eCpuType m_CpuType; eCpuType m_CpuType;
SS_CARDTYPE m_Slot[NUM_SLOTS]; SS_CARDTYPE m_Slot[NUM_SLOTS];
SS_CARDTYPE m_SlotAux; SS_CARDTYPE m_SlotAux;
std::string m_tfeInterface; std::string m_tfeInterface;
bool m_tfeVirtualDNS;
UINT m_bEnableTheFreezesF8Rom; UINT m_bEnableTheFreezesF8Rom;
UINT m_uSaveLoadStateMsg; UINT m_uSaveLoadStateMsg;
VideoRefreshRate_e m_videoRefreshRate; VideoRefreshRate_e m_videoRefreshRate;

View File

@ -30,6 +30,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "../ParallelPrinter.h" #include "../ParallelPrinter.h"
#include "../Registry.h" #include "../Registry.h"
#include "../SaveState.h" #include "../SaveState.h"
#include "../CardManager.h"
#include "../resource/resource.h" #include "../resource/resource.h"
CPageAdvanced* CPageAdvanced::ms_this = 0; // reinit'd in ctor CPageAdvanced* CPageAdvanced::ms_this = 0; // reinit'd in ctor

View File

@ -30,6 +30,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "../Windows/Win32Frame.h" #include "../Windows/Win32Frame.h"
#include "../Registry.h" #include "../Registry.h"
#include "../SerialComms.h" #include "../SerialComms.h"
#include "../CardManager.h"
#include "../Uthernet2.h"
#include "../Tfe/PCapBackend.h"
#include "../Interface.h"
#include "../resource/resource.h" #include "../resource/resource.h"
CPageConfig* CPageConfig::ms_this = 0; // reinit'd in ctor CPageConfig* CPageConfig::ms_this = 0; // reinit'd in ctor
@ -114,6 +118,7 @@ INT_PTR CPageConfig::DlgProcInternal(HWND hWnd, UINT message, WPARAM wparam, LPA
ui_tfe_settings_dialog(hWnd); ui_tfe_settings_dialog(hWnd);
m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT3] = m_PageConfigTfe.m_tfe_selected; m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT3] = m_PageConfigTfe.m_tfe_selected;
m_PropertySheetHelper.GetConfigNew().m_tfeInterface = m_PageConfigTfe.m_tfe_interface_name; m_PropertySheetHelper.GetConfigNew().m_tfeInterface = m_PageConfigTfe.m_tfe_interface_name;
m_PropertySheetHelper.GetConfigNew().m_tfeVirtualDNS = m_PageConfigTfe.m_tfe_virtual_dns;
InitOptions(hWnd); InitOptions(hWnd);
break; break;
@ -261,7 +266,8 @@ INT_PTR CPageConfig::DlgProcInternal(HWND hWnd, UINT message, WPARAM wparam, LPA
break; break;
} }
m_PageConfigTfe.m_tfe_interface_name = PCapBackend::tfe_interface; m_PageConfigTfe.m_tfe_interface_name = PCapBackend::GetRegistryInterface(SLOT3);
m_PageConfigTfe.m_tfe_virtual_dns = Uthernet2::GetRegistryVirtualDNS(SLOT3);
} }
InitOptions(hWnd); InitOptions(hWnd);

View File

@ -135,37 +135,16 @@ BOOL CPageConfigTfe::get_tfename(int number, std::string & name, std::string & d
return FALSE; return FALSE;
} }
int CPageConfigTfe::gray_ungray_items(HWND hwnd) void CPageConfigTfe::gray_ungray_items(HWND hwnd)
{ {
int enable; const int enable = SendMessage(GetDlgItem(hwnd, IDC_TFE_SETTINGS_ENABLE), CB_GETCURSEL, 0, 0);
int number;
int disabled = 0;
PCapBackend::get_disabled_state(&disabled);
if (disabled)
{
EnableWindow(GetDlgItem(hwnd, IDC_TFE_SETTINGS_ENABLE_T), 0);
EnableWindow(GetDlgItem(hwnd, IDC_TFE_SETTINGS_ENABLE), 0);
EnableWindow(GetDlgItem(hwnd, IDOK), 0);
SetWindowText(GetDlgItem(hwnd,IDC_TFE_SETTINGS_INTERFACE_NAME), "");
SetWindowText(GetDlgItem(hwnd,IDC_TFE_SETTINGS_INTERFACE_DESC), "");
enable = 0;
}
else
{
enable = SendMessage(GetDlgItem(hwnd, IDC_TFE_SETTINGS_ENABLE), CB_GETCURSEL, 0, 0) ? 1 : 0;
}
EnableWindow(GetDlgItem(hwnd, IDC_TFE_SETTINGS_INTERFACE_T), enable);
EnableWindow(GetDlgItem(hwnd, IDC_TFE_SETTINGS_INTERFACE), enable);
if (enable) if (enable)
{ {
std::string name; std::string name;
std::string description; std::string description;
number = SendMessage(GetDlgItem(hwnd, IDC_TFE_SETTINGS_INTERFACE), CB_GETCURSEL, 0, 0); const int number = SendMessage(GetDlgItem(hwnd, IDC_TFE_SETTINGS_INTERFACE), CB_GETCURSEL, 0, 0);
if (get_tfename(number, name, description)) if (get_tfename(number, name, description))
{ {
@ -179,7 +158,7 @@ int CPageConfigTfe::gray_ungray_items(HWND hwnd)
SetWindowText(GetDlgItem(hwnd, IDC_TFE_SETTINGS_INTERFACE_DESC), ""); SetWindowText(GetDlgItem(hwnd, IDC_TFE_SETTINGS_INTERFACE_DESC), "");
} }
return disabled ? 1 : 0; EnableWindow(GetDlgItem(hwnd, IDC_CHECK_TFE_VIRTUAL_DNS), enable == 2);
} }
void CPageConfigTfe::init_tfe_dialog(HWND hwnd) void CPageConfigTfe::init_tfe_dialog(HWND hwnd)
@ -193,6 +172,23 @@ void CPageConfigTfe::init_tfe_dialog(HWND hwnd)
uilib_adjust_group_width(hwnd, ms_leftgroup); uilib_adjust_group_width(hwnd, ms_leftgroup);
uilib_move_group(hwnd, ms_rightgroup, xsize + 30); uilib_move_group(hwnd, ms_rightgroup, xsize + 30);
if (PCapBackend::tfe_is_npcap_loaded())
{
const char * version = PCapBackend::tfe_lib_version();
SetWindowText(GetDlgItem(hwnd, IDC_TFE_NPCAP_INFO), version);
}
else
{
EnableWindow(GetDlgItem(hwnd, IDC_TFE_SETTINGS_INTERFACE), 0);
EnableWindow(GetDlgItem(hwnd, IDC_TFE_SETTINGS_INTERFACE_NAME), 0);
EnableWindow(GetDlgItem(hwnd, IDC_TFE_SETTINGS_INTERFACE_DESC), 0);
SetWindowText(GetDlgItem(hwnd, IDC_TFE_NPCAP_INFO),
"Limited Uthernet support is available on your system.\n\n"
"Install Npcap from https://npcap.com\n"
"or select Uthernet II with Virtual DNS.");
}
switch (m_tfe_selected) switch (m_tfe_selected)
{ {
case CT_Uthernet: case CT_Uthernet:
@ -206,6 +202,8 @@ void CPageConfigTfe::init_tfe_dialog(HWND hwnd)
break; break;
} }
CheckDlgButton(hwnd, IDC_CHECK_TFE_VIRTUAL_DNS, m_tfe_virtual_dns ? BST_CHECKED : BST_UNCHECKED);
temp_hwnd=GetDlgItem(hwnd,IDC_TFE_SETTINGS_ENABLE); temp_hwnd=GetDlgItem(hwnd,IDC_TFE_SETTINGS_ENABLE);
SendMessage(temp_hwnd, CB_ADDSTRING, 0, (LPARAM)"Disabled"); SendMessage(temp_hwnd, CB_ADDSTRING, 0, (LPARAM)"Disabled");
SendMessage(temp_hwnd, CB_ADDSTRING, 0, (LPARAM)"Uthernet"); SendMessage(temp_hwnd, CB_ADDSTRING, 0, (LPARAM)"Uthernet");
@ -244,22 +242,7 @@ void CPageConfigTfe::init_tfe_dialog(HWND hwnd)
PCapBackend::tfe_enumadapter_close(); PCapBackend::tfe_enumadapter_close();
} }
if (gray_ungray_items(hwnd)) gray_ungray_items(hwnd);
{
/* we have a problem: TFE is disabled. Give a message to the user */
// TC (18 Dec 2017) this vicekb URL is a broken link now, so I copied it to the AppleWin repo, here:
// . https://github.com/AppleWin/AppleWin/blob/master/docs/VICE%20Knowledge%20Base%20-%20Article%2013-005.htm
MessageBox( hwnd,
"Uthernet support is not available on your system,\n"
"WPCAP.DLL cannot be loaded.\n\n"
"Install Npcap from\n\n"
" https://npcap.com\n\n"
"to activate networking with AppleWin.",
"Uthernet support", MB_ICONINFORMATION|MB_OK);
/* just quit the dialog before it is open */
SendMessage( hwnd, WM_COMMAND, IDCANCEL, 0);
}
} }
void CPageConfigTfe::save_tfe_dialog(HWND hwnd) void CPageConfigTfe::save_tfe_dialog(HWND hwnd)
@ -270,27 +253,21 @@ void CPageConfigTfe::save_tfe_dialog(HWND hwnd)
buffer[255] = 0; buffer[255] = 0;
GetDlgItemText(hwnd, IDC_TFE_SETTINGS_INTERFACE, buffer, sizeof(buffer)-1); GetDlgItemText(hwnd, IDC_TFE_SETTINGS_INTERFACE, buffer, sizeof(buffer)-1);
// RGJ - Added check for NULL interface so we don't set it active without a valid interface selected m_tfe_interface_name = buffer;
if (strlen(buffer) > 0)
{ active_value = SendMessage(GetDlgItem(hwnd, IDC_TFE_SETTINGS_ENABLE), CB_GETCURSEL, 0, 0);
m_tfe_interface_name = buffer; switch (active_value)
active_value = SendMessage(GetDlgItem(hwnd, IDC_TFE_SETTINGS_ENABLE), CB_GETCURSEL, 0, 0);
switch (active_value)
{
case 1:
m_tfe_selected = CT_Uthernet;
break;
case 2:
m_tfe_selected = CT_Uthernet2;
break;
default:
m_tfe_selected = CT_Empty;
break;
}
}
else
{ {
case 1:
m_tfe_selected = CT_Uthernet;
break;
case 2:
m_tfe_selected = CT_Uthernet2;
break;
default:
m_tfe_selected = CT_Empty; m_tfe_selected = CT_Empty;
m_tfe_interface_name.clear(); break;
} }
m_tfe_virtual_dns = IsDlgButtonChecked(hwnd, IDC_CHECK_TFE_VIRTUAL_DNS) ? 1 : 0;
} }

View File

@ -13,6 +13,7 @@ public:
{ {
CPageConfigTfe::ms_this = this; CPageConfigTfe::ms_this = this;
m_tfe_selected = CT_Empty; m_tfe_selected = CT_Empty;
m_tfe_virtual_dns = false;
} }
virtual ~CPageConfigTfe(){} virtual ~CPageConfigTfe(){}
@ -20,6 +21,7 @@ public:
SS_CARDTYPE m_tfe_selected; SS_CARDTYPE m_tfe_selected;
std::string m_tfe_interface_name; std::string m_tfe_interface_name;
bool m_tfe_virtual_dns;
protected: protected:
// IPropertySheetPage // IPropertySheetPage
@ -29,7 +31,7 @@ protected:
private: private:
BOOL get_tfename(int number, std::string & name, std::string & description); BOOL get_tfename(int number, std::string & name, std::string & description);
int gray_ungray_items(HWND hwnd); void gray_ungray_items(HWND hwnd);
void init_tfe_dialog(HWND hwnd); void init_tfe_dialog(HWND hwnd);
void save_tfe_dialog(HWND hwnd); void save_tfe_dialog(HWND hwnd);

View File

@ -29,7 +29,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "../Windows/AppleWin.h" #include "../Windows/AppleWin.h"
#include "../CardManager.h" #include "../CardManager.h"
#include "../Disk.h" // Drive_e, Disk_Status_e #include "../Disk.h" // Drive_e, Disk_Status_e
#include "../HardDisk.h"
#include "../Registry.h" #include "../Registry.h"
#include "../Interface.h"
#include "../resource/resource.h" #include "../resource/resource.h"
CPageDisk* CPageDisk::ms_this = 0; // reinit'd in ctor CPageDisk* CPageDisk::ms_this = 0; // reinit'd in ctor

View File

@ -33,6 +33,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "../Log.h" #include "../Log.h"
#include "../Registry.h" #include "../Registry.h"
#include "../SaveState.h" #include "../SaveState.h"
#include "../Interface.h"
#include "../Uthernet2.h"
#include "../Tfe/PCapBackend.h" #include "../Tfe/PCapBackend.h"
/* /*
@ -336,7 +338,8 @@ void CPropertySheetHelper::ApplyNewConfig(const CConfigNeedingRestart& ConfigNew
SetSlot(slot, ConfigNew.m_Slot[slot]); SetSlot(slot, ConfigNew.m_Slot[slot]);
// unconditionally save it, as the previous SetSlot might have removed the setting // unconditionally save it, as the previous SetSlot might have removed the setting
PCapBackend::tfe_SetRegistryInterface(slot, ConfigNew.m_tfeInterface); PCapBackend::SetRegistryInterface(slot, ConfigNew.m_tfeInterface);
Uthernet2::SetRegistryVirtualDNS(slot, ConfigNew.m_tfeVirtualDNS);
slot = SLOT4; slot = SLOT4;
if (CONFIG_CHANGED_LOCAL(m_Slot[slot])) if (CONFIG_CHANGED_LOCAL(m_Slot[slot]))
@ -455,6 +458,9 @@ bool CPropertySheetHelper::HardwareConfigChanged(HWND hWnd)
if (CONFIG_CHANGED(m_tfeInterface)) if (CONFIG_CHANGED(m_tfeInterface))
strMsgMain += ". Uthernet interface has changed\n"; strMsgMain += ". Uthernet interface has changed\n";
if (CONFIG_CHANGED(m_tfeVirtualDNS))
strMsgMain += ". Uthernet Virtual DNS has changed\n";
if (CONFIG_CHANGED(m_Slot[SLOT4])) if (CONFIG_CHANGED(m_Slot[SLOT4]))
strMsgMain += GetSlot(SLOT4); strMsgMain += GetSlot(SLOT4);

View File

@ -45,7 +45,7 @@ public:
// create the network backed for Uthernet 1 and 2 // create the network backed for Uthernet 1 and 2
// useful to use libslirp in Linux // useful to use libslirp in Linux
virtual std::shared_ptr<NetworkBackend> CreateNetworkBackend() = 0; virtual std::shared_ptr<NetworkBackend> CreateNetworkBackend(const std::string & interfaceName) = 0;
// FindResource, MAKEINTRESOURCE, SizeofResource, LoadResource, LockResource // FindResource, MAKEINTRESOURCE, SizeofResource, LoadResource, LockResource
// Return pointer to resource if size is correct. // Return pointer to resource if size is correct.

View File

@ -41,6 +41,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Pravets.h" #include "Pravets.h"
#include "Speaker.h" #include "Speaker.h"
#include "Speech.h" #include "Speech.h"
#include "HardDisk.h"
#include "Configuration/Config.h" #include "Configuration/Config.h"
#include "Configuration/IPropertySheet.h" #include "Configuration/IPropertySheet.h"

49
source/Tfe/DNS.cpp Normal file
View File

@ -0,0 +1,49 @@
/*
AppleWin : An Apple //e emulator for Windows
Copyright (C) 2022, Andrea Odetti
AppleWin 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.
AppleWin 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 AppleWin; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "StdAfx.h"
#include "DNS.h"
#ifndef _MSC_VER
#include <arpa/inet.h>
#include <netdb.h>
#endif
uint32_t getHostByName(const std::string & name)
{
const hostent * host = gethostbyname(name.c_str());
if (host && host->h_addrtype == AF_INET && host->h_length == sizeof(uint32_t))
{
const in_addr * addr = (const in_addr *)host->h_addr_list[0];
if (addr)
{
return addr->s_addr;
}
}
return 0;
}
const char * formatIP(const uint32_t address)
{
in_addr in;
in.s_addr = address;
return inet_ntoa(in);
}

4
source/Tfe/DNS.h Normal file
View File

@ -0,0 +1,4 @@
#pragma once
uint32_t getHostByName(const std::string & name);
const char * formatIP(const uint32_t address);

View File

@ -39,4 +39,7 @@ public:
// if the backend is usable // if the backend is usable
virtual bool isValid() = 0; virtual bool isValid() = 0;
// get interface name
virtual const std::string & getInterfaceName() = 0;
}; };

View File

@ -29,17 +29,15 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include <iphlpapi.h> #include <iphlpapi.h>
#endif #endif
std::string PCapBackend::tfe_interface; PCapBackend::PCapBackend(const std::string & interfaceName) : m_interfaceName(interfaceName)
PCapBackend::PCapBackend(const std::string & pcapInterface)
{ {
tfePcapFP = TfePcapOpenAdapter(pcapInterface); m_tfePcapFP = TfePcapOpenAdapter(interfaceName);
} }
PCapBackend::~PCapBackend() PCapBackend::~PCapBackend()
{ {
TfePcapCloseAdapter(tfePcapFP); TfePcapCloseAdapter(m_tfePcapFP);
tfePcapFP = NULL; m_tfePcapFP = NULL;
} }
void PCapBackend::transmit( void PCapBackend::transmit(
@ -47,17 +45,17 @@ void PCapBackend::transmit(
uint8_t *txframe /* Pointer to the frame to be transmitted */ uint8_t *txframe /* Pointer to the frame to be transmitted */
) )
{ {
if (tfePcapFP) if (m_tfePcapFP)
{ {
tfe_arch_transmit(tfePcapFP, txlength, txframe); tfe_arch_transmit(m_tfePcapFP, txlength, txframe);
} }
} }
int PCapBackend::receive(const int size, uint8_t * rxframe) int PCapBackend::receive(const int size, uint8_t * rxframe)
{ {
if (tfePcapFP) if (m_tfePcapFP)
{ {
return tfe_arch_receive(tfePcapFP, size, rxframe); return tfe_arch_receive(m_tfePcapFP, size, rxframe);
} }
else else
{ {
@ -67,7 +65,7 @@ int PCapBackend::receive(const int size, uint8_t * rxframe)
bool PCapBackend::isValid() bool PCapBackend::isValid()
{ {
return tfePcapFP; return m_tfePcapFP;
} }
void PCapBackend::update(const ULONG /* nExecutedCycles */) void PCapBackend::update(const ULONG /* nExecutedCycles */)
@ -85,6 +83,11 @@ void PCapBackend::getMACAddress(const uint32_t address, MACAddress & mac)
#endif #endif
} }
const std::string & PCapBackend::getInterfaceName()
{
return m_interfaceName;
}
int PCapBackend::tfe_enumadapter_open(void) int PCapBackend::tfe_enumadapter_open(void)
{ {
return tfe_arch_enumadapter_open(); return tfe_arch_enumadapter_open();
@ -100,13 +103,26 @@ int PCapBackend::tfe_enumadapter_close(void)
return tfe_arch_enumadapter_close(); return tfe_arch_enumadapter_close();
} }
void PCapBackend::tfe_SetRegistryInterface(UINT slot, const std::string& name) const char * PCapBackend::tfe_lib_version(void)
{
return tfe_arch_lib_version();
}
void PCapBackend::SetRegistryInterface(UINT slot, const std::string& name)
{ {
std::string regSection = RegGetConfigSlotSection(slot); std::string regSection = RegGetConfigSlotSection(slot);
RegSaveString(regSection.c_str(), REGVALUE_UTHERNET_INTERFACE, 1, name); RegSaveString(regSection.c_str(), REGVALUE_UTHERNET_INTERFACE, 1, name);
} }
void PCapBackend::get_disabled_state(int * param) std::string PCapBackend::GetRegistryInterface(UINT slot)
{ {
*param = tfe_cannot_use; char interfaceName[MAX_PATH];
std::string regSection = RegGetConfigSlotSection(slot);
RegLoadString(regSection.c_str(), REGVALUE_UTHERNET_INTERFACE, TRUE, interfaceName, sizeof(interfaceName), TEXT(""));
return interfaceName;
}
int PCapBackend::tfe_is_npcap_loaded()
{
return tfe_arch_is_npcap_loaded();
} }

View File

@ -10,7 +10,7 @@ typedef struct pcap pcap_t;
class PCapBackend : public NetworkBackend class PCapBackend : public NetworkBackend
{ {
public: public:
PCapBackend(const std::string & pcapInterface); PCapBackend(const std::string & interfaceName);
virtual ~PCapBackend(); virtual ~PCapBackend();
@ -32,8 +32,12 @@ public:
// get MAC for IPRAW (it is only supposed to handle addresses on the local network) // get MAC for IPRAW (it is only supposed to handle addresses on the local network)
virtual void getMACAddress(const uint32_t address, MACAddress & mac); virtual void getMACAddress(const uint32_t address, MACAddress & mac);
static void tfe_SetRegistryInterface(UINT slot, const std::string& name); // get interface name
static void get_disabled_state(int * param); virtual const std::string & getInterfaceName();
// global registry functions
static void SetRegistryInterface(UINT slot, const std::string& name);
static std::string GetRegistryInterface(UINT slot);
/* /*
These functions let the UI enumerate the available interfaces. These functions let the UI enumerate the available interfaces.
@ -59,9 +63,10 @@ public:
static int tfe_enumadapter_open(void); static int tfe_enumadapter_open(void);
static int tfe_enumadapter(std::string & name, std::string & description); static int tfe_enumadapter(std::string & name, std::string & description);
static int tfe_enumadapter_close(void); static int tfe_enumadapter_close(void);
static const char * tfe_lib_version(void);
static std::string tfe_interface; static int tfe_is_npcap_loaded();
private: private:
pcap_t * tfePcapFP; const std::string m_interfaceName;
pcap_t * m_tfePcapFP;
}; };

View File

@ -28,6 +28,11 @@
/* #define WPCAP */ /* #define WPCAP */
#ifdef _MSC_VER #ifdef _MSC_VER
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include "pcap.h" #include "pcap.h"
#else #else
// on Linux and Mac OS X, we use system's pcap.h, which needs to be included as <> // on Linux and Mac OS X, we use system's pcap.h, which needs to be included as <>
@ -51,7 +56,8 @@
#define TFE_DEBUG_WARN 1 /* this should not be deactivated */ #define TFE_DEBUG_WARN 1 /* this should not be deactivated */
int tfe_cannot_use = 0; // once this is set, no further attempts to load npcap will be made
static int tfe_cannot_use = 0;
#ifdef _MSC_VER #ifdef _MSC_VER
@ -113,36 +119,48 @@ void TfePcapFreeLibrary(void)
static static
BOOL TfePcapLoadLibrary(void) BOOL TfePcapLoadLibrary(void)
{ {
if (!pcap_library) { if (pcap_library)
if (!SetDllDirectory("C:\\Windows\\System32\\Npcap\\")) // Prefer Npcap over WinPcap (GH#822) {
{ // already loaded
const char* error = "Warning: SetDllDirectory() failed for Npcap"; return TRUE;
LogOutput("%s\n", error);
LogFileOutput("%s\n", error);
}
pcap_library = LoadLibrary("wpcap.dll");
if (!pcap_library) {
tfe_cannot_use = 1;
if(g_fh) fprintf(g_fh, "LoadLibrary WPCAP.DLL failed!\n" );
return FALSE;
}
GET_PROC_ADDRESS_AND_TEST(pcap_open_live);
GET_PROC_ADDRESS_AND_TEST(pcap_close);
GET_PROC_ADDRESS_AND_TEST(pcap_dispatch);
GET_PROC_ADDRESS_AND_TEST(pcap_setnonblock);
GET_PROC_ADDRESS_AND_TEST(pcap_findalldevs);
GET_PROC_ADDRESS_AND_TEST(pcap_freealldevs);
GET_PROC_ADDRESS_AND_TEST(pcap_sendpacket);
GET_PROC_ADDRESS_AND_TEST(pcap_datalink);
GET_PROC_ADDRESS_AND_TEST(pcap_lib_version);
GET_PROC_ADDRESS_AND_TEST(pcap_geterr);
LogOutput("%s\n", p_pcap_lib_version());
LogFileOutput("%s\n", p_pcap_lib_version());
} }
if (tfe_cannot_use)
{
// already failed
return FALSE;
}
// try to load
if (!SetDllDirectory("C:\\Windows\\System32\\Npcap\\")) // Prefer Npcap over WinPcap (GH#822)
{
const char* error = "Warning: SetDllDirectory() failed for Npcap";
LogOutput("%s\n", error);
LogFileOutput("%s\n", error);
}
pcap_library = LoadLibrary("wpcap.dll");
if (!pcap_library)
{
tfe_cannot_use = 1;
if(g_fh) fprintf(g_fh, "LoadLibrary WPCAP.DLL failed!\n" );
return FALSE;
}
GET_PROC_ADDRESS_AND_TEST(pcap_open_live);
GET_PROC_ADDRESS_AND_TEST(pcap_close);
GET_PROC_ADDRESS_AND_TEST(pcap_dispatch);
GET_PROC_ADDRESS_AND_TEST(pcap_setnonblock);
GET_PROC_ADDRESS_AND_TEST(pcap_findalldevs);
GET_PROC_ADDRESS_AND_TEST(pcap_freealldevs);
GET_PROC_ADDRESS_AND_TEST(pcap_sendpacket);
GET_PROC_ADDRESS_AND_TEST(pcap_datalink);
GET_PROC_ADDRESS_AND_TEST(pcap_lib_version);
GET_PROC_ADDRESS_AND_TEST(pcap_geterr);
LogOutput("%s\n", p_pcap_lib_version());
LogFileOutput("%s\n", p_pcap_lib_version());
return TRUE; return TRUE;
} }
@ -438,7 +456,7 @@ void TfePcapPacketHandler(u_char *param, const struct pcap_pkthdr *header, const
/* determine the count of bytes which has been returned, /* determine the count of bytes which has been returned,
* but make sure not to overrun the buffer * but make sure not to overrun the buffer
*/ */
pinternal->rxlength = min(pinternal->size, header->caplen); pinternal->rxlength = std::min(pinternal->size, header->caplen);
memcpy(pinternal->buffer, pkt_data, pinternal->rxlength); memcpy(pinternal->buffer, pkt_data, pinternal->rxlength);
} }
@ -551,4 +569,19 @@ int tfe_arch_receive(pcap_t * TfePcapFP,
return -1; return -1;
} }
const char * tfe_arch_lib_version()
{
if (!TfePcapLoadLibrary())
{
return 0;
}
return p_pcap_lib_version();
}
int tfe_arch_is_npcap_loaded()
{
return TfePcapLoadLibrary();
}
//#endif /* #ifdef HAVE_TFE */ //#endif /* #ifdef HAVE_TFE */

View File

@ -34,9 +34,6 @@
extern void tfe_arch_set_mac(const BYTE mac[6]); extern void tfe_arch_set_mac(const BYTE mac[6]);
extern void tfe_arch_set_hashfilter(const DWORD hash_mask[2]); extern void tfe_arch_set_hashfilter(const DWORD hash_mask[2]);
/* Flag: Can we even use TFE, or is the hardware not available? */
extern int tfe_cannot_use;
struct pcap; struct pcap;
typedef struct pcap pcap_t; typedef struct pcap pcap_t;
@ -67,8 +64,11 @@ int tfe_arch_receive(pcap_t * TfePcapFP,
BYTE *pbuffer /* where to store a frame */ BYTE *pbuffer /* where to store a frame */
); );
extern int tfe_arch_is_npcap_loaded();
extern int tfe_arch_enumadapter_open(void); extern int tfe_arch_enumadapter_open(void);
extern int tfe_arch_enumadapter(std::string & name, std::string & description); extern int tfe_arch_enumadapter(std::string & name, std::string & description);
extern int tfe_arch_enumadapter_close(void); extern int tfe_arch_enumadapter_close(void);
extern const char * tfe_arch_lib_version();
#endif #endif

View File

@ -1011,7 +1011,8 @@ static BYTE __stdcall TfeIo (WORD programcounter, WORD address, BYTE write, BYTE
void Uthernet1::InitializeIO(LPBYTE pCxRomPeripheral) void Uthernet1::InitializeIO(LPBYTE pCxRomPeripheral)
{ {
networkBackend = GetFrame().CreateNetworkBackend(); const std::string interfaceName = PCapBackend::GetRegistryInterface(m_slot);
networkBackend = GetFrame().CreateNetworkBackend(interfaceName);
if (networkBackend->isValid()) if (networkBackend->isValid())
{ {
RegisterIoHandler(m_slot, TfeIo, TfeIo, TfeIoCxxx, TfeIoCxxx, this, NULL); RegisterIoHandler(m_slot, TfeIo, TfeIo, TfeIoCxxx, TfeIoCxxx, this, NULL);
@ -1058,10 +1059,10 @@ void Uthernet1::SaveSnapshot(class YamlSaveHelper& yamlSaveHelper)
YamlSaveHelper::Label unit(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); YamlSaveHelper::Label unit(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE);
yamlSaveHelper.SaveBool(SS_YAML_KEY_ENABLED, networkBackend->isValid() ? true : false); yamlSaveHelper.SaveBool(SS_YAML_KEY_ENABLED, networkBackend->isValid() ? true : false);
yamlSaveHelper.SaveString(SS_YAML_KEY_NETWORK_INTERFACE, PCapBackend::tfe_interface); yamlSaveHelper.SaveString(SS_YAML_KEY_NETWORK_INTERFACE, networkBackend->getInterfaceName());
yamlSaveHelper.SaveBool(SS_YAML_KEY_STARTED_TX, tfe_started_tx ? true : false); yamlSaveHelper.SaveBool(SS_YAML_KEY_STARTED_TX, tfe_started_tx ? true : false);
yamlSaveHelper.SaveBool(SS_YAML_KEY_CANNOT_USE, tfe_cannot_use ? true : false); yamlSaveHelper.SaveBool(SS_YAML_KEY_CANNOT_USE, PCapBackend::tfe_is_npcap_loaded() ? false : false);
yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_TXCOLLECT_BUFFER, txcollect_buffer); yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_TXCOLLECT_BUFFER, txcollect_buffer);
yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_RX_BUFFER, rx_buffer); yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_RX_BUFFER, rx_buffer);
@ -1083,10 +1084,13 @@ bool Uthernet1::LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT version)
ThrowErrorInvalidVersion(version); ThrowErrorInvalidVersion(version);
yamlLoadHelper.LoadBool(SS_YAML_KEY_ENABLED); // FIXME: what is the point of this? yamlLoadHelper.LoadBool(SS_YAML_KEY_ENABLED); // FIXME: what is the point of this?
PCapBackend::tfe_interface = yamlLoadHelper.LoadString(SS_YAML_KEY_NETWORK_INTERFACE); PCapBackend::SetRegistryInterface(m_slot, yamlLoadHelper.LoadString(SS_YAML_KEY_NETWORK_INTERFACE));
tfe_started_tx = yamlLoadHelper.LoadBool(SS_YAML_KEY_STARTED_TX) ? true : false; tfe_started_tx = yamlLoadHelper.LoadBool(SS_YAML_KEY_STARTED_TX) ? true : false;
tfe_cannot_use = yamlLoadHelper.LoadBool(SS_YAML_KEY_CANNOT_USE) ? true : false;
// it is meaningless to restore this boolean flag
// as it depends on the availability of npcap on *this* pc
const bool tfe_cannot_use = yamlLoadHelper.LoadBool(SS_YAML_KEY_CANNOT_USE);
txcollect_buffer = yamlLoadHelper.LoadUint(SS_YAML_KEY_TXCOLLECT_BUFFER); txcollect_buffer = yamlLoadHelper.LoadUint(SS_YAML_KEY_TXCOLLECT_BUFFER);
rx_buffer = yamlLoadHelper.LoadUint(SS_YAML_KEY_RX_BUFFER); rx_buffer = yamlLoadHelper.LoadUint(SS_YAML_KEY_RX_BUFFER);
@ -1117,7 +1121,5 @@ bool Uthernet1::LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT version)
for (UINT i = 0; i < 6; i++) for (UINT i = 0; i < 6; i++)
tfe_sideeffects_write_pp((TFE_PP_ADDR_MAC_ADDR + i) & ~1, i & 1); // set tfe_ia_mac tfe_sideeffects_write_pp((TFE_PP_ADDR_MAC_ADDR + i) & ~1, i & 1); // set tfe_ia_mac
PCapBackend::tfe_SetRegistryInterface(m_slot, PCapBackend::tfe_interface);
return true; return true;
} }

View File

@ -25,7 +25,18 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Tfe/NetworkBackend.h" #include "Tfe/NetworkBackend.h"
#include "Tfe/PCapBackend.h" #include "Tfe/PCapBackend.h"
#include "Tfe/IPRaw.h" #include "Tfe/IPRaw.h"
#include "Tfe/DNS.h"
#include "W5100.h" #include "W5100.h"
#include "../Registry.h"
// Virtual DNS
// Virtual DNS is an extension to the W5100
// It enables DNS resolution by setting P3 = 1 for IP / TCP and UDP
// the length-prefixed hostname is in 0x2A-0xFF is each socket memory
// it can be identified with PTIMER = 0.
// this means, one can use TCP & UDP without a NetworkBackend.
// Linux uses EINPROGRESS while Windows returns WSAEWOULDBLOCK // Linux uses EINPROGRESS while Windows returns WSAEWOULDBLOCK
// when the connect() calls is ongoing // when the connect() calls is ongoing
@ -297,7 +308,6 @@ bool Socket::LoadSnapshot(YamlLoadHelper &yamlLoadHelper)
sn_sr = yamlLoadHelper.LoadUint(SS_YAML_KEY_SOCKET_REGISTER); sn_sr = yamlLoadHelper.LoadUint(SS_YAML_KEY_SOCKET_REGISTER);
// transmit and receive sizes are restored from the card common registers // transmit and receive sizes are restored from the card common registers
switch (sn_sr) switch (sn_sr)
{ {
case W5100_SN_SR_SOCK_MACRAW: case W5100_SN_SR_SOCK_MACRAW:
@ -323,9 +333,30 @@ const std::string& Uthernet2::GetSnapshotCardName()
Uthernet2::Uthernet2(UINT slot) : Card(CT_Uthernet2, slot) Uthernet2::Uthernet2(UINT slot) : Card(CT_Uthernet2, slot)
{ {
#ifdef _MSC_VER
WSADATA wsaData;
myWSAStartup = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (myWSAStartup)
{
const int error = sock_error();
LogFileOutput("U2: WSAStartup: error %" ERROR_FMT "\n", STRERROR(error));
}
#endif
myVirtualDNSEnabled = GetRegistryVirtualDNS(slot);
Reset(true); Reset(true);
} }
Uthernet2::~Uthernet2()
{
#ifdef _MSC_VER
if (myWSAStartup == 0)
{
WSACleanup();
}
#endif
}
void Uthernet2::setSocketModeRegister(const size_t i, const uint16_t address, const uint8_t value) void Uthernet2::setSocketModeRegister(const size_t i, const uint16_t address, const uint8_t value)
{ {
myMemory[address] = value; myMemory[address] = value;
@ -338,16 +369,19 @@ void Uthernet2::setSocketModeRegister(const size_t i, const uint16_t address, co
#endif #endif
break; break;
case W5100_SN_MR_TCP: case W5100_SN_MR_TCP:
case W5100_SN_MR_TCP_DNS:
#ifdef U2_LOG_STATE #ifdef U2_LOG_STATE
LogFileOutput("U2: Mode[%" SIZE_T_FMT "]: TCP\n", i); LogFileOutput("U2: Mode[%" SIZE_T_FMT "]: TCP\n", i);
#endif #endif
break; break;
case W5100_SN_MR_UDP: case W5100_SN_MR_UDP:
case W5100_SN_MR_UDP_DNS:
#ifdef U2_LOG_STATE #ifdef U2_LOG_STATE
LogFileOutput("U2: Mode[%" SIZE_T_FMT "]: UDP\n", i); LogFileOutput("U2: Mode[%" SIZE_T_FMT "]: UDP\n", i);
#endif #endif
break; break;
case W5100_SN_MR_IPRAW: case W5100_SN_MR_IPRAW:
case W5100_SN_MR_IPRAW_DNS:
#ifdef U2_LOG_STATE #ifdef U2_LOG_STATE
LogFileOutput("U2: Mode[%" SIZE_T_FMT "]: IPRAW\n", i); LogFileOutput("U2: Mode[%" SIZE_T_FMT "]: IPRAW\n", i);
#endif #endif
@ -698,13 +732,13 @@ void Uthernet2::sendDataIPRaw(const size_t i, std::vector<uint8_t> &payload)
const uint8_t tos = myMemory[socket.registerAddress + W5100_SN_TOS]; const uint8_t tos = myMemory[socket.registerAddress + W5100_SN_TOS];
const uint8_t protocol = myMemory[socket.registerAddress + W5100_SN_PROTO]; const uint8_t protocol = myMemory[socket.registerAddress + W5100_SN_PROTO];
const uint32_t source = readAddress(myMemory.data() + W5100_SIPR0); const uint32_t source = readAddress(myMemory.data() + W5100_SIPR0);
const uint32_t destination = readAddress(myMemory.data() + socket.registerAddress + W5100_SN_DIPR0); const uint32_t dest = readAddress(myMemory.data() + socket.registerAddress + W5100_SN_DIPR0);
const MACAddress * sourceMac = reinterpret_cast<const MACAddress *>(myMemory.data() + W5100_SHAR0); const MACAddress * sourceMac = reinterpret_cast<const MACAddress *>(myMemory.data() + W5100_SHAR0);
const MACAddress * destinationMac; const MACAddress * destinationMac;
getMACAddress(destination, destinationMac); getMACAddress(dest, destinationMac);
std::vector<uint8_t> packet = createETH2Frame(payload, sourceMac, destinationMac, ttl, tos, protocol, source, destination); std::vector<uint8_t> packet = createETH2Frame(payload, sourceMac, destinationMac, ttl, tos, protocol, source, dest);
#ifdef U2_LOG_TRAFFIC #ifdef U2_LOG_TRAFFIC
LogFileOutput("U2: Send IPRAW[%" SIZE_T_FMT "]: %" SIZE_T_FMT " (%" SIZE_T_FMT ") bytes\n", i, payload.size(), packet.size()); LogFileOutput("U2: Send IPRAW[%" SIZE_T_FMT "]: %" SIZE_T_FMT " (%" SIZE_T_FMT ") bytes\n", i, payload.size(), packet.size());
@ -738,10 +772,9 @@ void Uthernet2::sendDataToSocket(const size_t i, std::vector<uint8_t> &data)
sockaddr_in destination = {}; sockaddr_in destination = {};
destination.sin_family = AF_INET; destination.sin_family = AF_INET;
// already in network order
// this seems to be ignored for TCP, and so we reuse the same code // this seems to be ignored for TCP, and so we reuse the same code
const uint8_t *dest = myMemory.data() + socket.registerAddress + W5100_SN_DIPR0; const uint32_t dest = readAddress(myMemory.data() + socket.registerAddress + W5100_SN_DIPR0);
destination.sin_addr.s_addr = *reinterpret_cast<const uint32_t *>(dest); destination.sin_addr.s_addr = dest;
destination.sin_port = *reinterpret_cast<const uint16_t *>(myMemory.data() + socket.registerAddress + W5100_SN_DPORT0); destination.sin_port = *reinterpret_cast<const uint16_t *>(myMemory.data() + socket.registerAddress + W5100_SN_DPORT0);
const ssize_t res = sendto(socket.myFD, reinterpret_cast<const char *>(data.data()), data.size(), 0, (const struct sockaddr *)&destination, sizeof(destination)); const ssize_t res = sendto(socket.myFD, reinterpret_cast<const char *>(data.data()), data.size(), 0, (const struct sockaddr *)&destination, sizeof(destination));
@ -853,21 +886,38 @@ void Uthernet2::openSystemSocket(const size_t i, const int type, const int proto
void Uthernet2::openSocket(const size_t i) void Uthernet2::openSocket(const size_t i)
{ {
Socket &socket = mySockets[i]; Socket &socket = mySockets[i];
socket.clearFD();
const uint8_t mr = myMemory[socket.registerAddress + W5100_SN_MR]; const uint8_t mr = myMemory[socket.registerAddress + W5100_SN_MR];
const uint8_t protocol = mr & W5100_SN_MR_PROTO_MASK; const uint8_t protocol = mr & W5100_SN_MR_PROTO_MASK;
const bool virtual_dns = protocol & W5100_SN_VIRTUAL_DNS;
// if virtual_dns is requested, but not enabled, we cannot handle it here.
if (virtual_dns && !myVirtualDNSEnabled)
{
#ifdef U2_LOG_STATE
LogFileOutput("U2: Open[%" SIZE_T_FMT "]: virtual DNS not supported: %02x\n", i, mr);
#endif
return;
}
uint8_t &sr = socket.sn_sr; uint8_t &sr = socket.sn_sr;
switch (protocol) switch (protocol)
{ {
case W5100_SN_MR_IPRAW: case W5100_SN_MR_IPRAW:
case W5100_SN_MR_IPRAW_DNS:
sr = W5100_SN_SR_SOCK_IPRAW; sr = W5100_SN_SR_SOCK_IPRAW;
break; break;
case W5100_SN_MR_MACRAW: case W5100_SN_MR_MACRAW:
sr = W5100_SN_SR_SOCK_MACRAW; sr = W5100_SN_SR_SOCK_MACRAW;
break; break;
case W5100_SN_MR_TCP: case W5100_SN_MR_TCP:
case W5100_SN_MR_TCP_DNS:
openSystemSocket(i, SOCK_STREAM, IPPROTO_TCP, W5100_SN_SR_SOCK_INIT); openSystemSocket(i, SOCK_STREAM, IPPROTO_TCP, W5100_SN_SR_SOCK_INIT);
break; break;
case W5100_SN_MR_UDP: case W5100_SN_MR_UDP:
case W5100_SN_MR_UDP_DNS:
openSystemSocket(i, SOCK_DGRAM, IPPROTO_UDP, W5100_SN_SR_SOCK_UDP); openSystemSocket(i, SOCK_DGRAM, IPPROTO_UDP, W5100_SN_SR_SOCK_UDP);
break; break;
#ifdef U2_LOG_UNKNOWN #ifdef U2_LOG_UNKNOWN
@ -875,6 +925,16 @@ void Uthernet2::openSocket(const size_t i)
LogFileOutput("U2: Open[%" SIZE_T_FMT "]: unknown mode: %02x\n", i, mr); LogFileOutput("U2: Open[%" SIZE_T_FMT "]: unknown mode: %02x\n", i, mr);
#endif #endif
} }
switch (protocol)
{
case W5100_SN_MR_IPRAW_DNS:
case W5100_SN_MR_TCP_DNS:
case W5100_SN_MR_UDP_DNS:
resolveDNS(i);
break;
}
resetRXTXBuffers(i); // needed? resetRXTXBuffers(i); // needed?
#ifdef U2_LOG_STATE #ifdef U2_LOG_STATE
LogFileOutput("U2: Open[%" SIZE_T_FMT "]: SR = %02x\n", i, sr); LogFileOutput("U2: Open[%" SIZE_T_FMT "]: SR = %02x\n", i, sr);
@ -890,17 +950,44 @@ void Uthernet2::closeSocket(const size_t i)
#endif #endif
} }
void Uthernet2::resolveDNS(const size_t i)
{
Socket &socket = mySockets[i];
uint32_t *dest = reinterpret_cast<uint32_t *>(myMemory.data() + socket.registerAddress + W5100_SN_DIPR0);
*dest = 0; // 0.0.0.0 signals failure by any reason
const uint8_t length = myMemory[socket.registerAddress + W5100_SN_DNS_NAME_LEN];
if (length <= W5100_SN_DNS_NAME_CPTY)
{
const uint8_t * start = myMemory.data() + socket.registerAddress + W5100_SN_DNS_NAME_BEGIN;
const std::string name(start, start + length);
const std::map<std::string, uint32_t>::iterator it = myDNSCache.find(name);
if (it != myDNSCache.end())
{
*dest = it->second;
}
else
{
*dest = getHostByName(name);
myDNSCache[name] = *dest;
#ifdef U2_LOG_STATE
LogFileOutput("U2: DNS[%" SIZE_T_FMT "]: %s = %s\n", i, name.c_str(), formatIP(*dest));
#endif
}
}
}
void Uthernet2::connectSocket(const size_t i) void Uthernet2::connectSocket(const size_t i)
{ {
Socket &socket = mySockets[i]; Socket &socket = mySockets[i];
const uint8_t *dest = myMemory.data() + socket.registerAddress + W5100_SN_DIPR0; const uint32_t dest = readAddress(myMemory.data() + socket.registerAddress + W5100_SN_DIPR0);
sockaddr_in destination = {}; sockaddr_in destination = {};
destination.sin_family = AF_INET; destination.sin_family = AF_INET;
// already in network order // already in network order
destination.sin_port = *reinterpret_cast<const uint16_t *>(myMemory.data() + socket.registerAddress + W5100_SN_DPORT0); destination.sin_port = *reinterpret_cast<const uint16_t *>(myMemory.data() + socket.registerAddress + W5100_SN_DPORT0);
destination.sin_addr.s_addr = *reinterpret_cast<const uint32_t *>(dest); destination.sin_addr.s_addr = dest;
const int res = connect(socket.myFD, (struct sockaddr *)&destination, sizeof(destination)); const int res = connect(socket.myFD, (struct sockaddr *)&destination, sizeof(destination));
@ -910,7 +997,7 @@ void Uthernet2::connectSocket(const size_t i)
socket.myErrno = 0; socket.myErrno = 0;
#ifdef U2_LOG_STATE #ifdef U2_LOG_STATE
const uint16_t port = readNetworkWord(myMemory.data() + socket.registerAddress + W5100_SN_DPORT0); const uint16_t port = readNetworkWord(myMemory.data() + socket.registerAddress + W5100_SN_DPORT0);
LogFileOutput("U2: TCP[%" SIZE_T_FMT "]: CONNECT to %d.%d.%d.%d:%d\n", i, dest[0], dest[1], dest[2], dest[3], port); LogFileOutput("U2: TCP[%" SIZE_T_FMT "]: CONNECT to %s:%d\n", i, formatIP(dest), port);
#endif #endif
} }
else else
@ -1130,11 +1217,18 @@ void Uthernet2::writeSocketRegister(const uint16_t address, const uint8_t value)
case W5100_SN_RX_RD1: case W5100_SN_RX_RD1:
myMemory[address] = value; myMemory[address] = value;
break; break;
#ifdef U2_LOG_UNKNOWN
default: default:
LogFileOutput("U2: Set unknown socket register[%d]: %04x\n", i, address); if (myVirtualDNSEnabled && loc >= W5100_SN_DNS_NAME_LEN)
break; {
myMemory[address] = value;
}
else
{
#ifdef U2_LOG_UNKNOWN
LogFileOutput("U2: Set unknown socket register[%d]: %04x\n", i, address);
#endif #endif
}
break;
}; };
} }
@ -1216,8 +1310,10 @@ void Uthernet2::Reset(const bool powerCycle)
{ {
// dataAddress is NOT reset, see page 10 of Uthernet II // dataAddress is NOT reset, see page 10 of Uthernet II
myDataAddress = 0; myDataAddress = 0;
myNetworkBackend = GetFrame().CreateNetworkBackend(); const std::string interfaceName = PCapBackend::GetRegistryInterface(m_slot);
myNetworkBackend = GetFrame().CreateNetworkBackend(interfaceName);
myARPCache.clear(); myARPCache.clear();
myDNSCache.clear();
} }
mySockets.clear(); mySockets.clear();
@ -1247,7 +1343,11 @@ void Uthernet2::Reset(const bool powerCycle)
myMemory[W5100_RCR] = 0x08; myMemory[W5100_RCR] = 0x08;
setRXSizes(W5100_RMSR, 0x55); setRXSizes(W5100_RMSR, 0x55);
setTXSizes(W5100_TMSR, 0x55); setTXSizes(W5100_TMSR, 0x55);
myMemory[W5100_PTIMER] = 0x28; if (!myVirtualDNSEnabled)
{
// this is 0 if we support Virtual DNS
myMemory[W5100_PTIMER] = 0x28;
}
} }
BYTE Uthernet2::IO_C0(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles) BYTE Uthernet2::IO_C0(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles)
@ -1367,7 +1467,11 @@ void Uthernet2::Update(const ULONG nExecutedCycles)
} }
} }
static const UINT kUNIT_VERSION = 1; // Unit version history:
// 2: Added: Virtual DNS
static const UINT kUNIT_VERSION = 2;
#define SS_YAML_KEY_VIRTUAL_DNS "Virtual DNS"
#define SS_YAML_KEY_NETWORK_INTERFACE "Network Interface" #define SS_YAML_KEY_NETWORK_INTERFACE "Network Interface"
#define SS_YAML_KEY_COMMON_REGISTERS "Common Registers" #define SS_YAML_KEY_COMMON_REGISTERS "Common Registers"
@ -1385,7 +1489,8 @@ void Uthernet2::SaveSnapshot(YamlSaveHelper &yamlSaveHelper)
YamlSaveHelper::Slot slot(yamlSaveHelper, GetSnapshotCardName(), m_slot, kUNIT_VERSION); YamlSaveHelper::Slot slot(yamlSaveHelper, GetSnapshotCardName(), m_slot, kUNIT_VERSION);
YamlSaveHelper::Label unit(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); YamlSaveHelper::Label unit(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE);
yamlSaveHelper.SaveString(SS_YAML_KEY_NETWORK_INTERFACE, PCapBackend::tfe_interface); yamlSaveHelper.SaveString(SS_YAML_KEY_NETWORK_INTERFACE, myNetworkBackend->getInterfaceName());
yamlSaveHelper.SaveBool(SS_YAML_KEY_VIRTUAL_DNS, myVirtualDNSEnabled);
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_MODE_REGISTER, myModeRegister); yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_MODE_REGISTER, myModeRegister);
yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_DATA_ADDRESS, myDataAddress); yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_DATA_ADDRESS, myDataAddress);
@ -1428,10 +1533,19 @@ bool Uthernet2::LoadSnapshot(YamlLoadHelper &yamlLoadHelper, UINT version)
if (version < 1 || version > kUNIT_VERSION) if (version < 1 || version > kUNIT_VERSION)
ThrowErrorInvalidVersion(version); ThrowErrorInvalidVersion(version);
PCapBackend::tfe_interface = yamlLoadHelper.LoadString(SS_YAML_KEY_NETWORK_INTERFACE); PCapBackend::SetRegistryInterface(m_slot, yamlLoadHelper.LoadString(SS_YAML_KEY_NETWORK_INTERFACE));
PCapBackend::tfe_SetRegistryInterface(m_slot, PCapBackend::tfe_interface);
Reset(true); // AFTER the interface name has been restored if (version >= 2)
{
myVirtualDNSEnabled = yamlLoadHelper.LoadBool(SS_YAML_KEY_VIRTUAL_DNS);
}
else
{
myVirtualDNSEnabled = false;
}
SetRegistryVirtualDNS(m_slot, myVirtualDNSEnabled);
Reset(true); // AFTER the parameters have been restored
myModeRegister = yamlLoadHelper.LoadUint(SS_YAML_KEY_MODE_REGISTER); myModeRegister = yamlLoadHelper.LoadUint(SS_YAML_KEY_MODE_REGISTER);
myDataAddress = yamlLoadHelper.LoadUint(SS_YAML_KEY_DATA_ADDRESS); myDataAddress = yamlLoadHelper.LoadUint(SS_YAML_KEY_DATA_ADDRESS);
@ -1475,3 +1589,17 @@ bool Uthernet2::LoadSnapshot(YamlLoadHelper &yamlLoadHelper, UINT version)
return true; return true;
} }
void Uthernet2::SetRegistryVirtualDNS(UINT slot, const bool enabled)
{
const std::string regSection = RegGetConfigSlotSection(slot);
RegSaveValue(regSection.c_str(), REGVALUE_UTHERNET_VIRTUAL_DNS, TRUE, enabled);
}
bool Uthernet2::GetRegistryVirtualDNS(UINT slot)
{
const std::string regSection = RegGetConfigSlotSection(slot);
DWORD enabled = 0;
RegLoadValue(regSection.c_str(), REGVALUE_UTHERNET_VIRTUAL_DNS, TRUE, &enabled, 0);
return enabled != 0;
}

View File

@ -61,6 +61,7 @@ public:
enum PacketDestination { HOST, BROADCAST, OTHER }; enum PacketDestination { HOST, BROADCAST, OTHER };
Uthernet2(UINT slot); Uthernet2(UINT slot);
virtual ~Uthernet2();
virtual void Destroy(void) {} virtual void Destroy(void) {}
virtual void InitializeIO(LPBYTE pCxRomPeripheral); virtual void InitializeIO(LPBYTE pCxRomPeripheral);
@ -71,7 +72,17 @@ public:
BYTE IO_C0(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles); BYTE IO_C0(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles);
// global registry functions
static void SetRegistryVirtualDNS(UINT slot, const bool enabled);
static bool GetRegistryVirtualDNS(UINT slot);
private: private:
bool myVirtualDNSEnabled; // extended virtualisation of DNS (not present in the real U II card)
#ifdef _MSC_VER
int myWSAStartup;
#endif
std::vector<uint8_t> myMemory; std::vector<uint8_t> myMemory;
std::vector<Socket> mySockets; std::vector<Socket> mySockets;
uint8_t myModeRegister; uint8_t myModeRegister;
@ -82,8 +93,10 @@ private:
// but in the interest of speeding up the emulator // but in the interest of speeding up the emulator
// we introduce one // we introduce one
std::map<uint32_t, MACAddress> myARPCache; std::map<uint32_t, MACAddress> myARPCache;
std::map<std::string, uint32_t> myDNSCache;
void getMACAddress(const uint32_t address, const MACAddress * & mac); void getMACAddress(const uint32_t address, const MACAddress * & mac);
void resolveDNS(const size_t i);
void setSocketModeRegister(const size_t i, const uint16_t address, const uint8_t value); void setSocketModeRegister(const size_t i, const uint16_t address, const uint8_t value);
void setTXSizes(const uint16_t address, uint8_t value); void setTXSizes(const uint16_t address, uint8_t value);

View File

@ -239,27 +239,15 @@ void LoadConfiguration(bool loadImages)
if (RegLoadValue(regSection.c_str(), REGVALUE_CARD_TYPE, TRUE, &dwTmp)) if (RegLoadValue(regSection.c_str(), REGVALUE_CARD_TYPE, TRUE, &dwTmp))
{ {
if (slot == SLOT3)
{
// this must happen before the card is instantitated
// TODO move to the card
if ((SS_CARDTYPE)dwTmp == CT_Uthernet || (SS_CARDTYPE)dwTmp == CT_Uthernet2) // TODO: move this to when UthernetCard object is instantiated
{
std::string regSection = RegGetConfigSlotSection(slot);
if (RegLoadString(regSection.c_str(), REGVALUE_UTHERNET_INTERFACE, TRUE, szFilename, MAX_PATH, TEXT("")))
PCapBackend::tfe_interface = szFilename;
}
}
GetCardMgr().Insert(slot, (SS_CARDTYPE)dwTmp, false); GetCardMgr().Insert(slot, (SS_CARDTYPE)dwTmp, false);
} }
else // legacy (AppleWin 1.30.3 or earlier) else // legacy (AppleWin 1.30.3 or earlier)
{ {
if (slot == SLOT3) if (slot == SLOT3)
{ {
// TODO: move this to when UthernetCard object is instantiated
RegLoadString(TEXT(REG_CONFIG), TEXT(REGVALUE_UTHERNET_INTERFACE), 1, szFilename, MAX_PATH, TEXT("")); RegLoadString(TEXT(REG_CONFIG), TEXT(REGVALUE_UTHERNET_INTERFACE), 1, szFilename, MAX_PATH, TEXT(""));
PCapBackend::tfe_interface = szFilename; // copy it to the new location
PCapBackend::SetRegistryInterface(slot, szFilename);
DWORD tfeEnabled; DWORD tfeEnabled;
REGLOAD_DEFAULT(TEXT(REGVALUE_UTHERNET_ACTIVE), &tfeEnabled, 0); REGLOAD_DEFAULT(TEXT(REGVALUE_UTHERNET_ACTIVE), &tfeEnabled, 0);

View File

@ -46,6 +46,10 @@
#define W5100_SN_MR_IPRAW 0x03 #define W5100_SN_MR_IPRAW 0x03
#define W5100_SN_MR_MACRAW 0x04 #define W5100_SN_MR_MACRAW 0x04
#define W5100_SN_MR_PPPOE 0x05 #define W5100_SN_MR_PPPOE 0x05
#define W5100_SN_VIRTUAL_DNS 0x08 // not present on real hardware, see comment in Uthernet2.cpp
#define W5100_SN_MR_TCP_DNS (W5100_SN_VIRTUAL_DNS | W5100_SN_MR_TCP)
#define W5100_SN_MR_UDP_DNS (W5100_SN_VIRTUAL_DNS | W5100_SN_MR_UDP)
#define W5100_SN_MR_IPRAW_DNS (W5100_SN_VIRTUAL_DNS | W5100_SN_MR_IPRAW)
#define W5100_SN_CR_OPEN 0x01 #define W5100_SN_CR_OPEN 0x01
#define W5100_SN_CR_LISTENT 0x02 #define W5100_SN_CR_LISTENT 0x02
@ -88,6 +92,11 @@
#define W5100_SN_RX_RD0 0x28 // RX Read Pointer #define W5100_SN_RX_RD0 0x28 // RX Read Pointer
#define W5100_SN_RX_RD1 0x29 // RX Read Pointer #define W5100_SN_RX_RD1 0x29 // RX Read Pointer
#define W5100_SN_DNS_NAME_LEN 0x2A // these are not present on real hardware, see comment in Uthernet2.cpp
#define W5100_SN_DNS_NAME_BEGIN 0x2B
#define W5100_SN_DNS_NAME_END 0xFF
#define W5100_SN_DNS_NAME_CPTY (W5100_SN_DNS_NAME_END - W5100_SN_DNS_NAME_BEGIN)
#define W5100_SN_SR_CLOSED 0x00 #define W5100_SN_SR_CLOSED 0x00
#define W5100_SN_SR_SOCK_INIT 0x13 #define W5100_SN_SR_SOCK_INIT 0x13
#define W5100_SN_SR_ESTABLISHED 0x17 #define W5100_SN_SR_ESTABLISHED 0x17

View File

@ -46,6 +46,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "SoundCore.h" #include "SoundCore.h"
#include "Speaker.h" #include "Speaker.h"
#include "LanguageCard.h" #include "LanguageCard.h"
#include "CardManager.h"
#ifdef USE_SPEECH_API #ifdef USE_SPEECH_API
#include "Speech.h" #include "Speech.h"
#endif #endif

View File

@ -625,8 +625,8 @@ std::string Win32Frame::Video_GetScreenShotFolder() const
return std::string(); return std::string();
} }
std::shared_ptr<NetworkBackend> Win32Frame::CreateNetworkBackend() std::shared_ptr<NetworkBackend> Win32Frame::CreateNetworkBackend(const std::string & interfaceName)
{ {
std::shared_ptr<NetworkBackend> backend(new PCapBackend(PCapBackend::tfe_interface)); std::shared_ptr<NetworkBackend> backend(new PCapBackend(interfaceName));
return backend; return backend;
} }

View File

@ -57,7 +57,7 @@ public:
virtual std::string Video_GetScreenShotFolder() const; virtual std::string Video_GetScreenShotFolder() const;
virtual std::shared_ptr<NetworkBackend> CreateNetworkBackend(); virtual std::shared_ptr<NetworkBackend> CreateNetworkBackend(const std::string & interfaceName);
bool GetFullScreenShowSubunitStatus(void); bool GetFullScreenShowSubunitStatus(void);
int GetFullScreenOffsetX(void); int GetFullScreenOffsetX(void);

View File

@ -48,6 +48,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Uthernet2.h" #include "Uthernet2.h"
#include "Speaker.h" #include "Speaker.h"
#include "Utilities.h" #include "Utilities.h"
#include "CardManager.h"
#include "../resource/resource.h" #include "../resource/resource.h"
#include "Configuration/PropertySheet.h" #include "Configuration/PropertySheet.h"
#include "Debugger/Debug.h" #include "Debugger/Debug.h"