575 lines
13 KiB
C
575 lines
13 KiB
C
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
common.c
|
|
|
|
Abstract:
|
|
|
|
Implements functionality common to both the source and destination side
|
|
|
|
Author:
|
|
|
|
Jim Schmidt (jimschm) 01-Jul-2000
|
|
|
|
Revision History:
|
|
|
|
<alias> <date> <comments>
|
|
|
|
--*/
|
|
|
|
//
|
|
// Includes
|
|
//
|
|
|
|
#include "pch.h"
|
|
#include <winsock.h>
|
|
#include <wsipx.h>
|
|
#include <wsnwlink.h>
|
|
#include <wsnetbs.h>
|
|
#include "homenetp.h"
|
|
|
|
#define DBG_HOMENET "HomeNet"
|
|
|
|
//
|
|
// Strings
|
|
//
|
|
|
|
#define S_TRANSPORT_DIR TEXT("USMT2.HN")
|
|
#define S_TRANSPORT_STATUS_FILE TEXT("status")
|
|
|
|
//
|
|
// Constants
|
|
//
|
|
|
|
// none
|
|
|
|
//
|
|
// Macros
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Types
|
|
//
|
|
|
|
// none
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
|
|
MIG_TRANSPORTSTORAGEID g_TransportId;
|
|
PCTSTR g_TransportTempDir;
|
|
PCTSTR g_StatusFile;
|
|
HANDLE g_StatusFileHandle = INVALID_HANDLE_VALUE;
|
|
UINT g_Platform;
|
|
TRANSFERMETRICS g_Metrics;
|
|
CONNECTIONSOCKET g_Connection;
|
|
BOOL g_CompressData = FALSE;
|
|
MIG_PROGRESSSLICEID g_DatabaseSlice;
|
|
MIG_PROGRESSSLICEID g_PersistentSlice;
|
|
MIG_PROGRESSSLICEID g_DownloadSlice;
|
|
UINT g_DownloadTicks;
|
|
UINT g_DownloadSliceSize;
|
|
HANDLE g_BackgroundThread;
|
|
HANDLE g_BackgroundThreadTerminate;
|
|
|
|
//
|
|
// Macro expansion list
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Private function prototypes
|
|
//
|
|
|
|
// none
|
|
|
|
//
|
|
// Macro expansion definition
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Code
|
|
//
|
|
|
|
VOID
|
|
pStopBackgroundThread (
|
|
VOID
|
|
)
|
|
{
|
|
if (g_BackgroundThread) {
|
|
|
|
DEBUGMSG ((DBG_HOMENET, "Stopping background thread"));
|
|
|
|
SetEvent (g_BackgroundThreadTerminate);
|
|
WaitForSingleObject (g_BackgroundThread, INFINITE);
|
|
|
|
CloseHandle (g_BackgroundThread);
|
|
CloseHandle (g_BackgroundThreadTerminate);
|
|
|
|
g_BackgroundThread = NULL;
|
|
g_BackgroundThreadTerminate = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
HomeNetTransportInitialize (
|
|
IN PMIG_LOGCALLBACK LogCallback
|
|
)
|
|
{
|
|
WSADATA startupData;
|
|
INT result;
|
|
|
|
//
|
|
// Initialize globals
|
|
//
|
|
|
|
LogReInit (NULL, NULL, NULL, (PLOGCALLBACK) LogCallback);
|
|
|
|
//
|
|
// Start sockets
|
|
//
|
|
|
|
result = WSAStartup (0x0101, &startupData);
|
|
|
|
//
|
|
// Register transport
|
|
//
|
|
|
|
if (!result) {
|
|
g_TransportId = IsmRegisterTransport (S_HOME_NETWORK_TRANSPORT);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
HomeNetTransportQueryCapabilities (
|
|
IN MIG_TRANSPORTSTORAGEID TransportStorageId,
|
|
OUT PMIG_TRANSPORTTYPE TransportType,
|
|
OUT PMIG_TRANSPORTCAPABILITIES Capabilities,
|
|
OUT PCTSTR *FriendlyDescription
|
|
)
|
|
{
|
|
if (TransportStorageId != g_TransportId) {
|
|
return FALSE;
|
|
}
|
|
|
|
*TransportType = TRANSPORTTYPE_FULL;
|
|
*Capabilities = CAPABILITY_COMPRESSED|CAPABILITY_AUTOMATED;
|
|
*FriendlyDescription = TEXT("Automatic network transfer");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
WINAPI
|
|
HomeNetTransportEstimateProgressBar (
|
|
MIG_PLATFORMTYPEID PlatformTypeId
|
|
)
|
|
{
|
|
UINT ticks;
|
|
PMIG_OBJECTCOUNT objectCount;
|
|
|
|
if (PlatformTypeId == PLATFORM_SOURCE) {
|
|
|
|
//
|
|
// If saving, we know the number of ticks based on the count of the
|
|
// persistent attribute.
|
|
//
|
|
|
|
objectCount = IsmGetObjectsStatistics (PLATFORM_SOURCE);
|
|
|
|
if (objectCount) {
|
|
ticks = objectCount->PersistentObjects;
|
|
} else {
|
|
ticks = 0;
|
|
}
|
|
|
|
g_PersistentSlice = IsmRegisterProgressSlice (ticks, max (1, ticks / 5));
|
|
|
|
ticks = 0;
|
|
g_DatabaseSlice = IsmRegisterProgressSlice (ticks, ticks * 3);
|
|
|
|
} else {
|
|
//
|
|
// When restoring, we don't know the progress until we connect. We need
|
|
// to set up a scale.
|
|
//
|
|
|
|
g_DownloadTicks = 0;
|
|
g_DownloadSliceSize = 1000;
|
|
g_DownloadSlice = IsmRegisterProgressSlice (g_DownloadSliceSize, 360);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
pResetTempDir (
|
|
VOID
|
|
)
|
|
{
|
|
FreePathString (g_TransportTempDir);
|
|
g_TransportTempDir = NULL;
|
|
|
|
if (g_StatusFileHandle != INVALID_HANDLE_VALUE) {
|
|
CloseHandle (g_StatusFileHandle);
|
|
g_StatusFileHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
FreeStorageFileName (g_StatusFile);
|
|
g_StatusFile = NULL;
|
|
}
|
|
|
|
|
|
DWORD
|
|
GetTransportStatus (
|
|
IN PCTSTR TrJournal,
|
|
OUT PBOOL Compressed OPTIONAL
|
|
)
|
|
{
|
|
HANDLE trJrnHandle;
|
|
BOOL compressed = FALSE;
|
|
DWORD signature = 0;
|
|
DWORD result = 0;
|
|
|
|
if (TrJournal && TrJournal [0]) {
|
|
trJrnHandle = BfOpenReadFile (TrJournal);
|
|
if (trJrnHandle) {
|
|
if (BfSetFilePointer (trJrnHandle, 0)) {
|
|
if (BfReadFile (trJrnHandle, (PBYTE)(&signature), sizeof (DWORD))) {
|
|
if (signature == HOMENETTR_SIG) {
|
|
if (BfReadFile (trJrnHandle, (PBYTE)(&compressed), sizeof (BOOL))) {
|
|
BfReadFile (trJrnHandle, (PBYTE)(&result), sizeof (DWORD));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CloseHandle (trJrnHandle);
|
|
} else {
|
|
if (GetLastError () == ERROR_ACCESS_DENIED) {
|
|
result = TRSTATUS_LOCKED;
|
|
}
|
|
}
|
|
}
|
|
if (Compressed) {
|
|
*Compressed = compressed;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
VOID
|
|
WINAPI
|
|
HomeNetTransportResetStorage (
|
|
IN MIG_TRANSPORTSTORAGEID TransportStorageId
|
|
)
|
|
{
|
|
if (TransportStorageId == g_TransportId) {
|
|
DEBUGMSG ((DBG_HOMENET, "Resetting transport"));
|
|
|
|
pStopBackgroundThread();
|
|
|
|
if (g_TransportTempDir) {
|
|
pResetTempDir();
|
|
MYASSERT (!g_TransportTempDir);
|
|
}
|
|
|
|
DEBUGMSG ((DBG_HOMENET, "Reset complete"));
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
HomeNetTransportSetStorage (
|
|
IN MIG_PLATFORMTYPEID Platform,
|
|
IN MIG_TRANSPORTSTORAGEID TransportStorageId,
|
|
IN MIG_TRANSPORTCAPABILITIES RequiredCapabilities,
|
|
IN PCTSTR StoragePath,
|
|
OUT PBOOL Valid,
|
|
OUT PBOOL ImageExists
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TransportSetStorage tells the transport to be prepared for a future IsmSave
|
|
or IsmLoad, and provides the storage path and capabilities. The StoragePath
|
|
tells the home networking transport where to save its temporary files
|
|
during the transfer. This routine is called when IsmSetTransportStorage is
|
|
called.
|
|
|
|
Arguments:
|
|
|
|
Platform - Specifies the platform of the transport. This is
|
|
potentially different than the current platform.
|
|
Also, it is never PLATFORM_CURRENT.
|
|
TransportStorageId - Specifies the desired storage ID. For this
|
|
transport, it will always be g_TransportId, unless
|
|
the caller passes in garbage.
|
|
RequiredCapabilities - Specifies two optional flags: CAPABILITY_COMPRESSED
|
|
and CAPABILITY_AUTOMATED.
|
|
StoragePath - Specifies the path to the temporary directory, or
|
|
NULL to use the Windows temporary directory.
|
|
Valid - Receives TRUE if the transport storage ID is valid
|
|
and was selected, FALSE otherwise. NOTE: this is not
|
|
an optional parameter.
|
|
ImageExists - Receives TRUE if the platform is PLATFORM_DESTINATION,
|
|
FALSE if the platform is PLATFORM_SOURCE. The value is
|
|
undefined if Valid is FALSE.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the transport is ready for IsmSave or IsmLoad, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCTSTR transportPath = NULL;
|
|
MIG_OBJECTSTRINGHANDLE encodedPath;
|
|
BOOL result = FALSE;
|
|
DWORD attribs;
|
|
TCHAR tempDir[MAX_TCHAR_PATH];
|
|
BOOL startAutoDest = FALSE;
|
|
CONNECTADDRESS connectAddress;
|
|
BOOL capabilitiesValid = TRUE;
|
|
|
|
if (!Valid || !ImageExists) {
|
|
DEBUGMSG ((DBG_ERROR, "TransportSetStorage requires Valid and ImageExists params"));
|
|
return FALSE;
|
|
}
|
|
|
|
*Valid = FALSE;
|
|
*ImageExists = FALSE;
|
|
|
|
if (TransportStorageId == g_TransportId) {
|
|
|
|
//
|
|
// Make sure we support the requested capabilities
|
|
//
|
|
|
|
if (RequiredCapabilities & (~(CAPABILITY_AUTOMATED|CAPABILITY_COMPRESSED))) {
|
|
capabilitiesValid = FALSE;
|
|
} else {
|
|
DEBUGMSG ((DBG_HOMENET, "Accepting a TransportSetStorage request (capabilities: 0%Xh)", RequiredCapabilities));
|
|
}
|
|
|
|
if (capabilitiesValid) {
|
|
|
|
//
|
|
// Validate the inbound args, update the globals
|
|
//
|
|
|
|
if (RequiredCapabilities & CAPABILITY_COMPRESSED) {
|
|
g_CompressData = TRUE;
|
|
} else {
|
|
g_CompressData = FALSE;
|
|
}
|
|
|
|
if (!StoragePath) {
|
|
IsmGetTempStorage (tempDir, ARRAYSIZE(tempDir));
|
|
StoragePath = tempDir;
|
|
}
|
|
|
|
MYASSERT (!g_TransportTempDir);
|
|
|
|
//
|
|
// Compute the transport storage directory, then make sure it is empty.
|
|
// If Storage is NULL, then the storage directory is %temp%\usmtv2.hn
|
|
//
|
|
|
|
transportPath = JoinPaths (StoragePath, S_TRANSPORT_DIR);
|
|
|
|
attribs = GetFileAttributes (transportPath);
|
|
|
|
if (attribs != INVALID_ATTRIBUTES) {
|
|
SetFileAttributes (transportPath, FILE_ATTRIBUTE_NORMAL);
|
|
DeleteFile (transportPath);
|
|
FiRemoveAllFilesInTree (transportPath);
|
|
}
|
|
|
|
//
|
|
// Now esablish the temporary directory and put a status file in it
|
|
// for restartability
|
|
//
|
|
|
|
attribs = GetFileAttributes (transportPath);
|
|
|
|
if (attribs == INVALID_ATTRIBUTES) {
|
|
|
|
if (BfCreateDirectory (transportPath)) {
|
|
*Valid = TRUE;
|
|
|
|
//
|
|
// it exists on the destination because we are going to download it;
|
|
// it does not exist on the source because we always overwrite it
|
|
//
|
|
|
|
*ImageExists = (Platform == PLATFORM_DESTINATION);
|
|
|
|
g_TransportTempDir = DuplicatePathString (transportPath, 0);
|
|
g_StatusFile = AllocStorageFileName (S_TRANSPORT_STATUS_FILE);
|
|
|
|
encodedPath = IsmCreateSimpleObjectPattern (g_TransportTempDir, FALSE, NULL, FALSE);
|
|
if (encodedPath) {
|
|
IsmRegisterStaticExclusion (MIG_FILE_TYPE, encodedPath);
|
|
IsmDestroyObjectHandle (encodedPath);
|
|
}
|
|
}
|
|
} else {
|
|
*ImageExists = TRUE;
|
|
}
|
|
|
|
//
|
|
// If CAPABILITY_AUTOMATED, start the process of looking for a connection now
|
|
//
|
|
|
|
if (*Valid && (RequiredCapabilities & CAPABILITY_AUTOMATED)) {
|
|
|
|
if (Platform == PLATFORM_SOURCE) {
|
|
//
|
|
// Check for a destination
|
|
//
|
|
|
|
DEBUGMSG ((DBG_HOMENET, "Looking for destination broadcasts"));
|
|
*ImageExists = FindDestination (&connectAddress, 5, TRUE);
|
|
if (*ImageExists) {
|
|
*ImageExists = TestConnection (&connectAddress);
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// Launch background thread
|
|
//
|
|
|
|
DEBUGMSG ((DBG_HOMENET, "Launching background broadcast thread"));
|
|
|
|
if (!g_BackgroundThread) {
|
|
g_BackgroundThreadTerminate = CreateEvent (NULL, TRUE, FALSE, NULL);
|
|
g_BackgroundThread = StartThread (DestinationBackgroundThread, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
result = TRUE;
|
|
}
|
|
}
|
|
|
|
FreePathString (transportPath);
|
|
return result;
|
|
}
|
|
|
|
|
|
VOID
|
|
WINAPI
|
|
HomeNetTransportTerminate (
|
|
VOID
|
|
)
|
|
{
|
|
pStopBackgroundThread();
|
|
|
|
//
|
|
// Shut down sockets
|
|
//
|
|
|
|
WSACleanup();
|
|
|
|
//
|
|
// Clean up utils
|
|
//
|
|
|
|
if (g_TransportTempDir) {
|
|
FiRemoveAllFilesInTree (g_TransportTempDir);
|
|
pResetTempDir();
|
|
}
|
|
}
|
|
|
|
|
|
PCTSTR
|
|
BuildDecoratedObject (
|
|
IN MIG_OBJECTTYPEID ObjectTypeId,
|
|
IN ENCODEDSTRHANDLE ObjectName
|
|
)
|
|
{
|
|
TCHAR prefix[32];
|
|
|
|
wsprintf (prefix, TEXT("%u"), ObjectTypeId);
|
|
|
|
return JoinPaths (prefix, ObjectName);
|
|
}
|
|
|
|
VOID
|
|
DestroyDecoratedObject (
|
|
IN PCTSTR String
|
|
)
|
|
{
|
|
FreePathString (String);
|
|
}
|
|
|
|
|
|
PCTSTR
|
|
AllocStorageFileName (
|
|
IN PCTSTR FileName OPTIONAL
|
|
)
|
|
{
|
|
TCHAR buffer[32];
|
|
static UINT sequencer = 0;
|
|
|
|
if (FileName) {
|
|
return JoinPaths (g_TransportTempDir, FileName);
|
|
}
|
|
|
|
sequencer++;
|
|
wsprintf (buffer, TEXT("%08X.DAT"), sequencer);
|
|
|
|
return JoinPaths (g_TransportTempDir, buffer);
|
|
}
|
|
|
|
|
|
VOID
|
|
FreeStorageFileName (
|
|
IN PCTSTR NameToFree
|
|
)
|
|
{
|
|
FreePathString (NameToFree);
|
|
}
|
|
|
|
|
|
PCTSTR
|
|
BuildImageFileName (
|
|
IN UINT ImageIdx
|
|
)
|
|
{
|
|
TCHAR imageFileName [13];
|
|
PCTSTR imageFile = NULL;
|
|
HANDLE imageFileHandle = NULL;
|
|
|
|
wsprintf (imageFileName, S_TRANSPORT_IMG_FILE, ImageIdx);
|
|
return JoinPaths (g_TransportTempDir, imageFileName);
|
|
}
|
|
|
|
|
|
VOID
|
|
FreeImageFileName (
|
|
IN PCTSTR ImageFileName
|
|
)
|
|
{
|
|
FreePathString (ImageFileName);
|
|
}
|