|
|
//--------------------------------------------------------------------
// Copyright (C)1998 Microsoft Corporation, All Rights Reserved.
//
// bftp.cpp
//
// Author
//
// Edward Reus (EdwardR) 02-26-98 Initial Coding.
//
//--------------------------------------------------------------------
#include "precomp.h"
#include <stdlib.h>
static BFTP_ATTRIBUTE_MAP_ENTRY Attributes[] = { //Attr Name Type
{ FIL0, "FIL0", ATTR_TYPE_CHAR }, // ASCII 8.3 File Name.
{ LFL0, "LFL0", ATTR_TYPE_CHAR }, // SJIS or ISO8859-1 Long File Name.
{ TIM0, "TIM0", ATTR_TYPE_TIME }, // File create/modify time.
{ TYP0, "TYP0", ATTR_TYPE_BINARY }, // File or Thumbnail Information.
{ TMB0, "TMB0", ATTR_TYPE_BINARY }, // The scaled down image.
{ BDY0, "BDY0", ATTR_TYPE_BINARY }, // (?).
{ CMD0, "CMD0", ATTR_TYPE_BINARY }, // Command Name (?).
{ WHT0, "WHT0", ATTR_TYPE_CHAR }, // Category Data.
{ ERR0, "ERR0", ATTR_TYPE_BINARY }, // Error code.
{ RPL0, "RPL0", ATTR_TYPE_CHAR }, // Result: Stored File Name.
{ INVALID_ATTR, 0, 0 } };
//
// This is the bFTP for an RIMG query by the camera:
//
#define BFTP_RIMG_ATTR_VALUE_SIZE 14
#define BFTP_RIMG_RESP_SIZE 12 + BFTP_RIMG_ATTR_VALUE_SIZE
static UCHAR BftpRimgRespAttrValue[BFTP_RIMG_ATTR_VALUE_SIZE] = { 0x00, 0xff, 0xff, // Pixel aspect ratio (any).
0x02, 0x01, 0xff, 0xff, 0xff, 0xff, // Accept image size (any).
0x05, 0xff, 0xff, 0xff, 0xff // Accept file size (any).
};
//
// This is the bFTP for an RINF query by the camera:
//
#define BFTP_RINF_ATTR_VALUE_SIZE 3
#define BFTP_RINF_RESP_SIZE 12 + BFTP_RINF_ATTR_VALUE_SIZE
static UCHAR BftpRinfRespAttrValue[BFTP_RINF_ATTR_VALUE_SIZE] = { 0x10, 0xff, 0xff // Memory available (lots).
};
//
// This is the bFTP for an RCMD query by the camera:
//
#define BFTP_RCMD_ATTR_VALUE_SIZE 5
#define BFTP_RCMD_RESP_SIZE 12 + BFTP_RCMD_ATTR_VALUE_SIZE
static UCHAR BftpRcmdRespAttrValue[BFTP_RCMD_ATTR_VALUE_SIZE] = { 0x20, 0x00, 0xff, 0x00, 0x01 // Accept up to 255 puts/connect.
};
//
// Map bFTP error codes:
static DWORD dwBftpErrorCodeMap[][2] = { { ERROR_PUT_UNDEFINED_ERROR, ERROR_BFTP_INVALID_PROTOCOL }, { ERROR_PUT_ILLEGAL_DATA, ERROR_BFTP_INVALID_PROTOCOL }, { ERROR_PUT_UNSUPPORTED_PID, ERROR_BFTP_INVALID_PROTOCOL }, { ERROR_PUT_ILLEGAL_ATTRIBUTE, ERROR_BFTP_INVALID_PROTOCOL }, { ERROR_PUT_UNSUPPORTED_CMD, ERROR_BFTP_INVALID_PROTOCOL }, { ERROR_PUT_FILE_SYSTEM_FULL, ERROR_IRTRANP_DISK_FULL }, { ERROR_PUT_NO_FILE_OR_DIR, ERROR_BFTP_INVALID_PROTOCOL }, { ERROR_PUT_LOW_BATTERY, ERROR_BFTP_INVALID_PROTOCOL }, { ERROR_PUT_ABORT_EXECUTION, ERROR_SCEP_ABORT }, { ERROR_PUT_NO_ERROR, NO_ERROR } };
//--------------------------------------------------------------------
// CharToValue()
//
// Used in parsing the bFTP date string. In this case the maximum
// value to parse is the year (YYYY).
//--------------------------------------------------------------------
static WORD CharToValue( IN UCHAR *pValue, IN DWORD dwLength ) { #define MAX_VALUE_STR_LEN 4
WORD wValue = 0; CHAR szTemp[MAX_VALUE_STR_LEN];
if (dwLength < MAX_VALUE_STR_LEN) { memcpy(szTemp,pValue,dwLength); szTemp[dwLength] = 0; wValue = (WORD)atoi(szTemp); }
return wValue; }
//--------------------------------------------------------------------
// MapBftpErrorCode()
//
//--------------------------------------------------------------------
DWORD MapBftpErrorCode( IN DWORD dwBftpErrorCode ) { DWORD dwErrorCode = NO_ERROR; DWORD dwNumCodes = sizeof(dwBftpErrorCodeMap)/(2*sizeof(DWORD));
for (DWORD i=0; i<dwNumCodes; i++) { if (dwBftpErrorCode == dwBftpErrorCodeMap[i][0]) { dwErrorCode = dwBftpErrorCodeMap[i][1]; break; } }
return dwErrorCode; }
//--------------------------------------------------------------------
// CSCEP_CONNECTION::ParseBftpAttributeName()
//
//--------------------------------------------------------------------
BFTP_ATTRIBUTE *CSCEP_CONNECTION::ParseBftpAttributeName( IN BFTP_ATTRIBUTE *pAttr, IN OUT DWORD *pdwSize, OUT DWORD *pdwWhichAttr ) { BFTP_ATTRIBUTE_MAP_ENTRY *pAttrMapEntry = Attributes;
*pdwWhichAttr = INVALID_ATTR;
#ifdef DBG_IO
DbgPrint("ParseBftpAttributeName(): pAttr->Name: %c%c%c%c\n", pAttr->Name[0], pAttr->Name[1], pAttr->Name[2], pAttr->Name[3] ); #endif
while (pAttrMapEntry->pName) { if (Match4(pAttr->Name,pAttrMapEntry->pName)) { *pdwWhichAttr = pAttrMapEntry->dwWhichAttr;
break; }
pAttrMapEntry++; }
// Note: that the Length paramter is 8 bytes in from the start
// of pAttr, hence the extra 8 (bytes) below:
*pdwSize = *pdwSize - 8UL - pAttr->Length; pAttr = (BFTP_ATTRIBUTE*)( 8UL + pAttr->Length + (UCHAR*)pAttr );
return pAttr; }
//--------------------------------------------------------------------
// CSCEP_CONNECTION::SaveBftpCreateDate()
//
// The bFTP create date/time is a character array of the form:
// YYYYMMDDHHMMSS (not zero terminated).
//
// If it was specifed then we want to use it as the create date
// of the picture file that we save the JPEG to.
//--------------------------------------------------------------------
DWORD CSCEP_CONNECTION::SaveBftpCreateDate( IN UCHAR *pDate, IN DWORD dwDateLength ) { DWORD dwStatus = NO_ERROR; SYSTEMTIME SystemTime; FILETIME LocalTime; FILETIME FileTime;
memset(&SystemTime,0,sizeof(SystemTime));
if (dwDateLength == BFTP_DATE_TIME_SIZE) { //
// Note that system time is in UTC, we will need to convert
// this to local time...
//
SystemTime.wYear = CharToValue( pDate, 4 ); SystemTime.wMonth = CharToValue( &(pDate[4]), 2 ); SystemTime.wDay = CharToValue( &(pDate[6]), 2 ); SystemTime.wHour = CharToValue( &(pDate[8]), 2 ); SystemTime.wMinute = CharToValue( &(pDate[10]), 2 ); SystemTime.wSecond = CharToValue( &(pDate[12]), 2 );
if (SystemTimeToFileTime(&SystemTime,&LocalTime)) { //
// Before we use the time zone, we need to convert it to
// UTC (its currently in "local time". Note that:
//
if (LocalFileTimeToFileTime(&LocalTime,&FileTime)) { m_CreateTime = FileTime;
#ifdef DBG_DATE
DbgPrint("IrTranP: SaveBftpCreateDate: Date: %d/%d/%d %d:%d:%d\n", SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond ); #endif
} else { #ifdef DBG_DATE
DbgPrint("IrTranP: SaveBftpCreateDate(): LocalFileTimeToFileTime() Failed: %d\n",GetLastError()); #endif
} } else { dwStatus = GetLastError(); #ifdef DBG_ERROR
DbgPrint("IrTranP: SaveBftpCreateDate(): SystemTimeToFileTime(): Failed: %d\n", dwStatus ); #endif
} }
return dwStatus; }
//--------------------------------------------------------------------
// CSCEP_CONNECTION::ParseBftp()
//
//--------------------------------------------------------------------
DWORD CSCEP_CONNECTION::ParseBftp( IN UCHAR *pBftpData, IN DWORD dwBftpDataSize, IN BOOL fSaveAsUPF, OUT DWORD *pdwBftpOp, OUT UCHAR **ppPutData, OUT DWORD *pdwPutDataSize ) { DWORD i; DWORD dwStatus = NO_ERROR; DWORD dwAttrSize; DWORD dwWhichAttr; DWORD dwLength; DWORD dwWcLength; USHORT usNumAttr; char *pszTemp; BFTP_ATTRIBUTE *pAttr; BFTP_ATTRIBUTE *pNextAttr;
*ppPutData = 0; *pdwPutDataSize = 0;
#ifdef LITTLE_ENDIAN
usNumAttr = ByteSwapShort( *((USHORT*)pBftpData) ); #endif
pAttr = (BFTP_ATTRIBUTE*)(pBftpData + sizeof(USHORT)); dwAttrSize = dwBftpDataSize - sizeof(USHORT);
for (i=0; i<usNumAttr; i++) { #ifdef LITTLE_ENDIAN
pAttr->Length = ByteSwapLong( pAttr->Length ); #endif
pNextAttr = ParseBftpAttributeName( pAttr, &dwAttrSize, &dwWhichAttr );
if (dwWhichAttr == INVALID_ATTR) { return ERROR_BFTP_INVALID_PROTOCOL; }
if (dwWhichAttr == CMD0) { if (pAttr->Length == 2+sizeof(DWORD)) { #ifdef LITTLE_ENDIAN
*((DWORD*)(pAttr->Value)) = ByteSwapLong( *((DWORD*)(pAttr->Value)) ); #endif
}
// Expect Value == 0x00010040 for a Query "WHT0" Request.
// Value == 0x00000000 for a Put Request.
if ( *((DWORD*)(pAttr->Value)) == 0x00010040 ) { *pdwBftpOp = BFTP_QUERY_RIMG; } else if ( *((DWORD*)(pAttr->Value)) == 0 ) { *pdwBftpOp = BFTP_PUT; } else { *pdwBftpOp = BFTP_UNKNOWN; } } else if (dwWhichAttr == WHT0) { if (Match4("RIMG",pAttr->Value)) { dwWhichAttr = RIMG; *pdwBftpOp = BFTP_QUERY_RIMG; } else if (Match4("RINF",pAttr->Value)) { dwWhichAttr = RINF; *pdwBftpOp = BFTP_QUERY_RINF; } else if (Match4("RCMD",pAttr->Value)) { dwWhichAttr = RCMD; *pdwBftpOp = BFTP_QUERY_RCMD; } else { dwWhichAttr = INVALID_ATTR; *pdwBftpOp = BFTP_UNKNOWN; return ERROR_BFTP_INVALID_PROTOCOL; } } //
// Short (8.3) file name:
//
else if (dwWhichAttr == FIL0) { // Note: That the specification limits the file
// name to 8.3...
dwLength = BftpValueLength(pAttr->Length); if (dwLength > FILE_NAME_SIZE) { dwLength = FILE_NAME_SIZE; }
if (m_pszFileName) { FreeMemory(m_pszFileName); }
m_pszFileName = (CHAR*)AllocateMemory(1+dwLength); if (!m_pszFileName) { return ERROR_IRTRANP_OUT_OF_MEMORY; }
memcpy(m_pszFileName,pAttr->Value,dwLength); m_pszFileName[dwLength] = 0;
if (m_pwszFileName) { FreeMemory(m_pwszFileName); }
dwWcLength = sizeof(WCHAR)*(1+dwLength) + sizeof(WSZ_JPEG); m_pwszFileName = (WCHAR*)AllocateMemory(dwWcLength); if (!m_pwszFileName) { return ERROR_IRTRANP_OUT_OF_MEMORY; }
//
// Convert file name (~\XXXXXX.JPG) to unicode.
//
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, m_pszFileName, 1+dwLength, m_pwszFileName, dwWcLength );
// File name is now XXXXXX.UPF. Change to
// XXXXXX.JPG or XXXXXX.UPF as appropriate:
WCHAR *pwsz = wcsrchr(m_pwszFileName,PERIOD); if (pwsz) { *pwsz = 0; // Remove old suffix.
if (fSaveAsUPF) { wcscat(m_pwszFileName,WSZ_UPF); // UPF file.
} else { wcscat(m_pwszFileName,WSZ_JPEG); // JPG file.
} } } //
// UPF body: headers + thumbnail + jpeg image ...
//
else if (dwWhichAttr == BDY0) { // This is a PUT.
ASSERT(*pdwBftpOp == BFTP_PUT); *ppPutData = pAttr->Value; *pdwPutDataSize = dwBftpDataSize - (DWORD)(pAttr->Value - pBftpData); } //
// Long file name:
//
else if (dwWhichAttr == LFL0) { if (m_pszLongFileName) { FreeMemory(m_pszLongFileName); }
dwLength = BftpValueLength(pAttr->Length); m_pszLongFileName = (CHAR*)AllocateMemory(1+dwLength); if (!m_pszLongFileName) { return ERROR_IRTRANP_OUT_OF_MEMORY; }
memcpy(m_pszLongFileName,pAttr->Value,dwLength); m_pszLongFileName[dwLength] = 0;
#ifdef DBG
DbgPrint("CSCEP_CONNECTION::ParseBftp(): LFL0: %s\n", m_pszLongFileName); #endif
CHAR *pszLongFileName = strrchr(m_pszLongFileName,'\\'); if (pszLongFileName) { pszLongFileName++; // Skip over the file separator...
} else { pszLongFileName = m_pszLongFileName; }
dwLength = strlen(pszLongFileName);
if (m_pwszFileName) { FreeMemory(m_pwszFileName); }
dwWcLength = sizeof(WCHAR)*(1+dwLength) + sizeof(WSZ_JPEG); m_pwszFileName = (WCHAR*)AllocateMemory(dwWcLength); if (!m_pwszFileName) { return ERROR_IRTRANP_OUT_OF_MEMORY; }
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, pszLongFileName, 1+dwLength, m_pwszFileName, dwWcLength );
// File name is now XXXXXX.JPG. Change to
// XXXXXX.JPEG or XXXXXX.UPF as appropriate:
WCHAR *pwsz = wcsrchr(m_pwszFileName,PERIOD); if (pwsz) { *pwsz = 0;
if (fSaveAsUPF) { wcscat(m_pwszFileName,WSZ_UPF); } else { wcscat(m_pwszFileName,WSZ_JPEG); } }
#ifdef DBG_IO
DbgPrint("CSCEP_CONNECTION::ParseBftp(): File: %S\n", m_pwszFileName); #endif
} //
// Create Date/Time:
//
else if (dwWhichAttr == TIM0) { dwLength = BftpValueLength(pAttr->Length);
SaveBftpCreateDate(pAttr->Value,dwLength);
#ifdef DBG_DATE
pszTemp = (char*)AllocateMemory(1+dwLength); if (pszTemp) { memcpy(pszTemp,pAttr->Value,dwLength); pszTemp[dwLength] = 0; DbgPrint("CSCEP_CONNECTION::ParseBftp(): TIM0: %s\n",pszTemp); FreeMemory(pszTemp); } #endif
} //
// Camera sent back a bFTP error code:
//
else if (dwWhichAttr == ERR0) { *pdwBftpOp = BFTP_ERROR;
*ppPutData = pAttr->Value; *pdwPutDataSize = BftpValueLength(pAttr->Length);
dwStatus = ByteSwapShort( *((USHORT*)(pAttr->Value)) );
#ifdef DBG_ERROR
DbgPrint("CSCEP_CONNECTION::ParseBftp(): ERR0: %d\n",dwStatus); #endif
}
// Note: We may need to byte swap other attributes as well if/when
// the protocol is extended...
pAttr = pNextAttr; }
return dwStatus; }
//--------------------------------------------------------------------
// CSCEP_CONNECTION::ParseUpfHeaders()
//
//--------------------------------------------------------------------
DWORD CSCEP_CONNECTION::ParseUpfHeaders( IN UCHAR *pPutData, IN DWORD dwPutDataSize, OUT DWORD *pdwJpegOffset, OUT DWORD *pdwJpegSize ) { DWORD dwStatus = NO_ERROR; DWORD dwStartAddress; DWORD dwDataSize; INT iGmtOffset = 0; WORD wYear; WORD wMonth; WORD wDay; SYSTEMTIME SystemTime; FILETIME LocalTime; FILETIME FileTime; UPF_HEADER *pUpfHeader; UPF_ENTRY *pUpfEntry1; UPF_ENTRY *pUpfEntry2; PICTURE_INFORMATION_DATA *pThumbnailInfo = 0; PICTURE_INFORMATION_DATA *pPictureInfo = 0;
ASSERT(dwPutDataSize >= UPF_TOTAL_HEADER_SIZE);
pUpfHeader = (UPF_HEADER*)pPutData;
pUpfEntry1 = (UPF_ENTRY*)(UPF_HEADER_SIZE + (UCHAR*)pUpfHeader); pUpfEntry2 = (UPF_ENTRY*)(UPF_ENTRY_SIZE + (UCHAR*)pUpfEntry1);
dwStartAddress = ByteSwapLong(pUpfEntry2->dwStartAddress);
dwDataSize = ByteSwapLong(pUpfEntry2->dwDataSize);
#ifdef DBG_PROPERTIES
DbgPrint("CSCEP_CONNECTION::ParseUpfHeaders(): NumTables: %d\n", pUpfHeader->NumTables );
pPictureInfo = (PICTURE_INFORMATION_DATA*)pUpfEntry2->InformationData;
DbgPrint("CSCEP_CONNECTION::ParseUpfHeaders(): Rotation: %d\n", pPictureInfo->RotationSet ); #endif
#ifdef DBG_IO
DbgPrint("CSCEP_CONNECTION::ParseUpfHeaders(): StartAddress: %d Size: %d\n", dwStartAddress, dwDataSize ); #endif
*pdwJpegOffset = UPF_HEADER_SIZE + 4*UPF_ENTRY_SIZE + dwStartAddress; *pdwJpegSize = dwDataSize;
#ifdef UPF_FILES
*pdwJpegOffset = 0; *pdwJpegSize = 0; #endif
// Ok, now parse the picture creation date/time, if one is
// defined.
//
// Note that the date/time is local time, with a GMT offset.
// Since we will use local system time conversions, we will
// not need the GMT offset.
if (pUpfHeader->CreateDate[UPF_GMT_OFFSET] != 0x80) { iGmtOffset = (pUpfHeader->CreateDate[UPF_GMT_OFFSET])/4; #ifdef DBG_DATE
DbgPrint("IrTranP: ParseUpfHeaders: GMT Offset: %d (0x%x)\n", iGmtOffset, pUpfHeader->CreateDate[UPF_GMT_OFFSET] ); #endif
}
memcpy(&wYear,&(pUpfHeader->CreateDate[UPF_YEAR]),sizeof(SHORT) ); wYear = ByteSwapShort(wYear);
wMonth = pUpfHeader->CreateDate[UPF_MONTH]; wDay = pUpfHeader->CreateDate[UPF_DAY];
// At least the Year/Month/Day must be specified, else we
// won't use the date. If the Hour/Minute/Second are known,
// then we will use them as well.
if ((wYear != 0xffff) && (wMonth != 0xff) && (wDay != 0xff)) { memset(&SystemTime,0,sizeof(SystemTime)); SystemTime.wYear = wYear; SystemTime.wMonth = wMonth; SystemTime.wDay = wDay; if (pUpfHeader->CreateDate[UPF_HOUR] != 0xff) { SystemTime.wHour = pUpfHeader->CreateDate[UPF_HOUR];
if (pUpfHeader->CreateDate[UPF_MINUTE] != 0xff) { SystemTime.wMinute = pUpfHeader->CreateDate[UPF_MINUTE];
if (pUpfHeader->CreateDate[UPF_SECOND] != 0xff) { SystemTime.wSecond = pUpfHeader->CreateDate[UPF_SECOND]; } } }
if (SystemTimeToFileTime(&SystemTime,&LocalTime)) { //
// Before we save the date/time, we need to convert it to
// UTC (its currently in "local time". Note that:
//
if (LocalFileTimeToFileTime(&LocalTime,&FileTime)) { m_CreateTime = FileTime;
#ifdef DBG_DATE
DbgPrint("IrTranP: ParseUpfHeaders: Date/Time: %d/%d/%d %d:%d:%d\n", SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond ); #endif
} else { #ifdef DBG_DATE
DbgPrint("IrTranP: SaveBftpCreateDate(): LocalFileTimeToFileTime() Failed: %d\n",GetLastError()); #endif
} } else { #ifdef DBG_ERROR
dwStatus = GetLastError(); DbgPrint("IrTranP: ParseUpfHeaders(): Invalid Picture Create Date/Time. Status: %d\n", dwStatus ); DbgPrint(" Date: 0x%2.2x %2.2x%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", pUpfHeader->CreateDate[UPF_GMT_OFFSET], pUpfHeader->CreateDate[UPF_YEAR], pUpfHeader->CreateDate[UPF_YEAR+1], pUpfHeader->CreateDate[UPF_MONTH], pUpfHeader->CreateDate[UPF_DAY], pUpfHeader->CreateDate[UPF_HOUR], pUpfHeader->CreateDate[UPF_MINUTE], pUpfHeader->CreateDate[UPF_SECOND] ); dwStatus = NO_ERROR; #endif
} } else { #ifdef DBG_DATE
DbgPrint("IrTranP: ParseUpfHeaders(): No Picture Create Date/Time.\n"); #endif
}
return dwStatus; }
//--------------------------------------------------------------------
// CSCEP_CONNECTION::BuildBftpWht0RinfPdu()
//
//--------------------------------------------------------------------
DWORD CSCEP_CONNECTION::BuildBftpWht0RinfPdu( OUT SCEP_HEADER **ppPdu, OUT DWORD *pdwPduSize, OUT SCEP_REQ_HEADER_LONG **ppCommand, OUT COMMAND_HEADER **ppCommandHeader ) { DWORD dwStatus = NO_ERROR; SCEP_HEADER *pHeader; SCEP_REQ_HEADER_LONG *pCommand; COMMAND_HEADER *pCommandHeader; UCHAR *pUserData; USHORT *pwNumAttributes; BFTP_ATTRIBUTE *pAttrib;
*ppPdu = 0; *pdwPduSize = 0; *ppCommand = 0; *ppCommandHeader = 0;
pHeader = NewPdu(); // Size is MAX_PDU_SIZE by default...
if (!pHeader) { return ERROR_IRTRANP_OUT_OF_MEMORY; }
memset(pHeader,0,MAX_PDU_SIZE);
// This is the total size of the PDU that we will construct:
DWORD dwPduSize = sizeof(SCEP_HEADER) + sizeof(SCEP_REQ_HEADER_LONG) + sizeof(USHORT) // Num Attributes
+ sizeof(BFTP_ATTRIBUTE) + sizeof(DWORD) + sizeof(BFTP_ATTRIBUTE) + WHT0_ATTRIB_SIZE;
// Length2 is the total size of the PDU minus the offset+size
// of Length2:
USHORT wLength2 = (USHORT)dwPduSize - 6;
pHeader->Null = 0; pHeader->MsgType = MSG_TYPE_DATA;
pCommand = (SCEP_REQ_HEADER_LONG*)(pHeader->Rest); pCommand->InfType = INF_TYPE_USER_DATA; pCommand->Length1 = USE_LENGTH2; // 0xff
pCommand->Length2 = wLength2; pCommand->InfVersion = INF_VERSION; pCommand->DFlag = DFLAG_SINGLE_PDU; pCommand->Length3 = pCommand->Length2 - 4; //
pCommandHeader = (COMMAND_HEADER*)(pCommand->CommandHeader); pCommandHeader->Marker58h = 0x58; pCommandHeader->PduType = PDU_TYPE_REQUEST; pCommandHeader->Length4 = pCommand->Length2 - 10; pCommandHeader->DestPid = m_SrcPid; pCommandHeader->SrcPid = m_DestPid; pCommandHeader->CommandId = (USHORT)m_dwCommandId;
memcpy( pCommandHeader->DestMachineId, m_pPrimaryMachineId, MACHINE_ID_SIZE );
memcpy( pCommandHeader->SrcMachineId, m_pSecondaryMachineId, MACHINE_ID_SIZE );
#ifdef LITTLE_ENDIAN
pCommand->Length2 = ByteSwapShort(pCommand->Length2); pCommand->Length3 = ByteSwapShort(pCommand->Length3); ByteSwapCommandHeader(pCommandHeader); #endif
// Setup the bFTP:
pUserData = pCommand->UserData; pwNumAttributes = (USHORT*)pUserData;
*pwNumAttributes = 2; // Two bFTP attributes.
#ifdef LITTLE_ENDIAN
*pwNumAttributes = ByteSwapShort(*pwNumAttributes); #endif
pUserData += sizeof(*pwNumAttributes);
// First attribute is CMD0:
DWORD dwCmd0AttrValue = CMD0_ATTR_VALUE; // Fixed constant!
pAttrib = (BFTP_ATTRIBUTE*)pUserData; memcpy( pAttrib->Name, Attributes[CMD0].pName, BFTP_NAME_SIZE ); pAttrib->Length = sizeof(pAttrib->Type) + sizeof(pAttrib->Flag) + sizeof(dwCmd0AttrValue); pAttrib->Type = ATTR_TYPE_BINARY; // 0x00
pAttrib->Flag = ATTR_FLAG_DEFAULT; // 0x00
memcpy( pAttrib->Value, &dwCmd0AttrValue, sizeof(dwCmd0AttrValue) );
#ifdef LITTLE_ENDIAN
pAttrib->Length = ByteSwapLong(pAttrib->Length); #endif
// Second attribute is WHT0:RINF
pAttrib = (BFTP_ATTRIBUTE*)(pUserData + sizeof(BFTP_ATTRIBUTE) + sizeof(dwCmd0AttrValue)); memcpy( pAttrib->Name, Attributes[WHT0].pName, BFTP_NAME_SIZE ); pAttrib->Length = sizeof(pAttrib->Type) + sizeof(pAttrib->Flag) + WHT0_ATTRIB_SIZE; pAttrib->Type = ATTR_TYPE_CHAR; // 0x00
pAttrib->Flag = ATTR_FLAG_DEFAULT; // 0x00
memcpy( pAttrib->Value, SZ_RINF, WHT0_ATTRIB_SIZE );
#ifdef LITTLE_ENDIAN
pAttrib->Length = ByteSwapLong(pAttrib->Length); #endif
// Done.
*ppPdu = pHeader; *pdwPduSize = dwPduSize; *ppCommand = pCommand; *ppCommandHeader = pCommandHeader;
return dwStatus; }
//--------------------------------------------------------------------
// CSCEP_CONNECTION::BuildBftpPutPdu()
//
// The PUT command will span multiple PDUs, this function builds the
// Nth fragment. Note that the first will also hold the attributes
// for the UPF file to be sent (in addition to the SCEP header stuff).
//
// Each PDU will also contain (MAX_PDU_SIZE - *pdwPduSize) bytes
// of the UPF file, but that isn't added in here. You add that
// yourself in the PDU starting at *ppCommand->UserData[].
//
// On success, return NO_ERROR, else return a non-zero error code.
//
// dwUpfFileSize -- The total UPF file size.
//
// pszUpfFile -- The 8.3 name of the UPF file.
//
// pdwFragNo -- The fragment number that was built, cycle this
// back into each successive call to BuildBftpPutPdu().
// Initialize *pdwFragNo to zero before the first
// iteration, then leave it alone.
//--------------------------------------------------------------------
DWORD CSCEP_CONNECTION::BuildBftpPutPdu( IN DWORD dwUpfFileSize, IN CHAR *pszUpfFileName, IN OUT DWORD *pdwFragNo, OUT SCEP_HEADER **ppPdu, OUT DWORD *pdwHeaderSize, OUT SCEP_REQ_HEADER_LONG_FRAG **ppCommand ) { DWORD dwStatus = NO_ERROR; SCEP_HEADER *pHeader; SCEP_REQ_HEADER_LONG_FRAG *pCommand; COMMAND_HEADER *pCommandHeader; UCHAR *pUserData; USHORT *pwNumAttributes; BFTP_ATTRIBUTE *pAttrib; DWORD dwUpfFileNameLength = strlen(pszUpfFileName);
*ppPdu = 0; *pdwHeaderSize = 0; *ppCommand = 0;
pHeader = NewPdu(); // Size is MAX_PDU_SIZE by default...
if (!pHeader) { return ERROR_IRTRANP_OUT_OF_MEMORY; }
memset(pHeader,0,MAX_PDU_SIZE);
// This is the size of the SCEP (and bFTP) headers part of the
// PDU that we will construct. dwHeaderSize1 is the header size for
// the first PDU, dwHeaderSizeN is the header size for the rest of
// the PDUs. Note that the Nth (N>1) header does not include the
// COMMAN_HEADER (28 bytes).
DWORD dwHeaderSize; DWORD dwHeaderSize1 = sizeof(SCEP_HEADER) + sizeof(SCEP_REQ_HEADER_LONG_FRAG) + sizeof(USHORT) // Num Attributes
+ sizeof(BFTP_ATTRIBUTE) // For CMD0
+ sizeof(DWORD) + sizeof(BFTP_ATTRIBUTE) // For FIL0
+ dwUpfFileNameLength + sizeof(BFTP_ATTRIBUTE); // For BDY0
DWORD dwHeaderSizeN = sizeof(SCEP_HEADER) + FIELD_OFFSET(SCEP_REQ_HEADER_LONG_FRAG,CommandHeader);
DWORD dwSpace1; // Space left after the header in PDU #1.
DWORD dwSpaceN; // Space left after the header in the Nth PDU.
DWORD dwFileSizeLeft; // File Size minus what will fit in the
// first PDU.
DWORD dwNumFullPdus; // Number of "full" PDUs after PDU #1.
DWORD dwLastPdu; // = 1 iff the last PDU is partially full.
DWORD dwNumPdus; // Total number of fragments to hold the file.
// Figure out which fragment we are on:
if (*pdwFragNo == 0) { dwHeaderSize = dwHeaderSize1; m_Fragmented = TRUE; m_DFlag = DFLAG_FIRST_FRAGMENT;
// The space in the PDU left after the first and Nth headers:
dwSpace1 = MAX_PDU_SIZE - dwHeaderSize1; dwSpaceN = MAX_PDU_SIZE - dwHeaderSizeN;
// The number of full PDUs following the first PDU:
dwFileSizeLeft = dwUpfFileSize - dwSpace1; dwNumFullPdus = dwFileSizeLeft / dwSpaceN;
// See if there is a trailer PDU with remaining data:
dwLastPdu = ((dwFileSizeLeft % dwSpaceN) > 0)? 1 : 0;
dwNumPdus = 1 + dwNumFullPdus + dwLastPdu;
*pdwFragNo = 1; m_dwSequenceNo = 0; // First Seq.No. is 0.
m_dwRestNo = dwNumPdus; // Rest starts at Total Num. Fragments.
} else { dwHeaderSize = dwHeaderSizeN;
*pdwFragNo++; m_dwSequenceNo++; m_dwRestNo--;
if (m_dwRestNo == 0) { return ERROR_BFTP_NO_MORE_FRAGMENTS; // Called to many times...
} else if (m_dwRestNo == 1) { m_DFlag = DFLAG_LAST_FRAGMENT; } else { m_DFlag = DFLAG_FRAGMENT; } }
// Length2 is the total size of the PDU minus the offset+size
// of Length2:
USHORT wLength2 = (USHORT)(MAX_PDU_SIZE - 6); DWORD dwLength4 = dwUpfFileSize + 22 + 48; DWORD dwBdy0Length = dwUpfFileSize + 2;
pHeader->Null = 0; pHeader->MsgType = MSG_TYPE_DATA;
pCommand = (SCEP_REQ_HEADER_LONG_FRAG*)(pHeader->Rest); pCommand->InfType = INF_TYPE_USER_DATA; pCommand->Length1 = USE_LENGTH2; // 0xff
pCommand->Length2 = wLength2; pCommand->InfVersion = INF_VERSION; pCommand->DFlag = m_DFlag; pCommand->Length3 = pCommand->Length2 - 12; //
pCommand->SequenceNo = m_dwSequenceNo; pCommand->RestNo = m_dwRestNo;
#ifdef LITTLE_ENDIAN
pCommand->Length2 = ByteSwapShort(pCommand->Length2); pCommand->Length3 = ByteSwapShort(pCommand->Length3); pCommand->SequenceNo = ByteSwapLong(pCommand->SequenceNo); pCommand->RestNo = ByteSwapLong(pCommand->RestNo); #endif
// Note that there is a COMMAND_HEADER in the SCEP header only
// for the first fragment.
if (m_DFlag == DFLAG_FIRST_FRAGMENT) { pCommandHeader = (COMMAND_HEADER*)(pCommand->CommandHeader); pCommandHeader->Marker58h = 0x58; pCommandHeader->PduType = PDU_TYPE_REQUEST; pCommandHeader->Length4 = dwLength4; pCommandHeader->DestPid = m_SrcPid; pCommandHeader->SrcPid = m_DestPid; pCommandHeader->CommandId = (USHORT)m_dwCommandId;
memcpy( pCommandHeader->DestMachineId, m_pPrimaryMachineId, MACHINE_ID_SIZE );
memcpy( pCommandHeader->SrcMachineId, m_pSecondaryMachineId, MACHINE_ID_SIZE );
#ifdef LITTLE_ENDIAN
ByteSwapCommandHeader(pCommandHeader); #endif
// Setup the bFTP:
pUserData = pCommand->UserData; pwNumAttributes = (USHORT*)pUserData;
*pwNumAttributes = 3; // Three bFTP attributes.
#ifdef LITTLE_ENDIAN
*pwNumAttributes = ByteSwapShort(*pwNumAttributes); #endif
pUserData += sizeof(*pwNumAttributes);
// First attribute is CMD0:
DWORD dwCmd0AttrValue = 0x00000000; pAttrib = (BFTP_ATTRIBUTE*)pUserData; memcpy( pAttrib->Name, Attributes[CMD0].pName, BFTP_NAME_SIZE ); pAttrib->Length = sizeof(pAttrib->Type) + sizeof(pAttrib->Flag) + sizeof(ULONG); pAttrib->Type = ATTR_TYPE_BINARY; // 0x00
pAttrib->Flag = ATTR_FLAG_DEFAULT; // 0x00
memcpy( pAttrib->Value, &dwCmd0AttrValue, sizeof(dwCmd0AttrValue) );
#ifdef LITTLE_ENDIAN
pAttrib->Length = ByteSwapLong(pAttrib->Length); #endif
// Second attribute is FIL0 (with the 8.3 UPF file name):
pAttrib = (BFTP_ATTRIBUTE*)(pUserData + sizeof(BFTP_ATTRIBUTE) + sizeof(dwCmd0AttrValue)); memcpy( pAttrib->Name, Attributes[FIL0].pName, BFTP_NAME_SIZE ); pAttrib->Length = sizeof(pAttrib->Type) + sizeof(pAttrib->Flag) + dwUpfFileNameLength; pAttrib->Type = ATTR_TYPE_CHAR; // 0x01
pAttrib->Flag = ATTR_FLAG_DEFAULT; // 0x00
memcpy( pAttrib->Value, pszUpfFileName, dwUpfFileNameLength );
#ifdef LITTLE_ENDIAN
pAttrib->Length = ByteSwapLong(pAttrib->Length); #endif
// Third attribute is BDY0 (with the value being the whole UPF file):
pAttrib = (BFTP_ATTRIBUTE*)( (char*)pAttrib + sizeof(BFTP_ATTRIBUTE) + dwUpfFileNameLength ); memcpy( pAttrib->Name, Attributes[BDY0].pName, BFTP_NAME_SIZE ); pAttrib->Length = dwBdy0Length; pAttrib->Type = ATTR_TYPE_BINARY; // 0x00
pAttrib->Flag = ATTR_FLAG_DEFAULT; // 0x00
// pAttrib->Value is not copied in (its the entire UPF file).
#ifdef LITTLE_ENDIAN
pAttrib->Length = ByteSwapLong(pAttrib->Length); #endif
}
// Done.
*ppPdu = pHeader; *pdwHeaderSize = dwHeaderSize; *ppCommand = pCommand;
return dwStatus; }
//--------------------------------------------------------------------
// CSCEP_CONNECTION::BuildBftpRespPdu()
//
//--------------------------------------------------------------------
DWORD CSCEP_CONNECTION::BuildBftpRespPdu( IN DWORD dwPduSize, OUT SCEP_HEADER **ppPdu, OUT SCEP_REQ_HEADER_SHORT **ppCommand, OUT COMMAND_HEADER **ppCommandHeader ) { DWORD dwStatus = NO_ERROR; SCEP_HEADER *pHeader; SCEP_REQ_HEADER_SHORT *pCommand; COMMAND_HEADER *pCommandHeader;
*ppPdu = 0; *ppCommand = 0; *ppCommandHeader = 0;
pHeader = NewPdu(); // Defaulting dwPduSize.
if (!pHeader) { return ERROR_IRTRANP_OUT_OF_MEMORY; }
memset(pHeader,0,MAX_PDU_SIZE); // MAX_PDU_SIZE since dwPduSize is defaulted above.
pHeader->Null = 0; pHeader->MsgType = MSG_TYPE_DATA;
pCommand = (SCEP_REQ_HEADER_SHORT*)(pHeader->Rest); pCommand->InfType = INF_TYPE_USER_DATA; pCommand->Length1 = (UCHAR)dwPduSize - 4; // Four bytes from the start.
pCommand->InfVersion = INF_VERSION; pCommand->DFlag = DFLAG_SINGLE_PDU; pCommand->Length3 = (USHORT)dwPduSize - 8; // Eight bytes from the start.
#ifdef LITTLE_ENDIAN
pCommand->Length3 = ByteSwapShort(pCommand->Length3); #endif
pCommandHeader = (COMMAND_HEADER*)(pCommand->CommandHeader); pCommandHeader->Marker58h = 0x58; pCommandHeader->PduType = PDU_TYPE_REPLY_ACK; pCommandHeader->Length4 = dwPduSize - 14; // Twelve bytes from the start.
pCommandHeader->DestPid = m_SrcPid; pCommandHeader->SrcPid = m_DestPid; pCommandHeader->CommandId = (USHORT)m_dwCommandId;
memcpy( pCommandHeader->DestMachineId, m_pPrimaryMachineId, MACHINE_ID_SIZE );
memcpy( pCommandHeader->SrcMachineId, m_pSecondaryMachineId, MACHINE_ID_SIZE );
#ifdef LITTLE_ENDIAN
ByteSwapCommandHeader(pCommandHeader); #endif
*ppPdu = pHeader; *ppCommand = pCommand; *ppCommandHeader = pCommandHeader;
return dwStatus; }
//--------------------------------------------------------------------
// CSCEP_CONNECTION::BuildWht0RespPdu()
//
//--------------------------------------------------------------------
DWORD CSCEP_CONNECTION::BuildWht0RespPdu( IN DWORD dwWht0Type, OUT SCEP_HEADER **ppPdu, OUT DWORD *pdwPduSize ) { DWORD dwStatus = NO_ERROR; DWORD dwPduSize; DWORD dwRespSize; DWORD dwAttrValueSize; SCEP_HEADER *pHeader; SCEP_REQ_HEADER_SHORT *pCommand; COMMAND_HEADER *pCommandHeader; UCHAR *pQueryResp; USHORT *pUShort; BFTP_ATTRIBUTE *pAttr; UCHAR *pAttrValue;
*ppPdu = 0; *pdwPduSize = 0;
if (dwWht0Type == BFTP_QUERY_RIMG) { dwRespSize = BFTP_RIMG_RESP_SIZE; dwAttrValueSize = BFTP_RIMG_ATTR_VALUE_SIZE; pAttrValue = BftpRimgRespAttrValue; #ifdef DBG_IO
DbgPrint("BuildWht0RespPdu(): RIMG Response\n"); #endif
} else if (dwWht0Type == BFTP_QUERY_RINF) { dwRespSize = BFTP_RINF_RESP_SIZE; dwAttrValueSize = BFTP_RINF_ATTR_VALUE_SIZE; pAttrValue = BftpRinfRespAttrValue; #ifdef DBG_IO
DbgPrint("BuildWht0RespPdu(): RINF Response\n"); #endif
} else if (dwWht0Type == BFTP_QUERY_RCMD) { dwRespSize = BFTP_RCMD_RESP_SIZE; dwAttrValueSize = BFTP_RCMD_ATTR_VALUE_SIZE; pAttrValue = BftpRcmdRespAttrValue; #ifdef DBG_IO
DbgPrint("BuildWht0RespPdu(): RCMD Response\n"); #endif
} else { return ERROR_BFTP_INVALID_PROTOCOL; }
dwPduSize = SCEP_HEADER_SIZE + SCEP_REQ_HEADER_SHORT_SIZE + dwRespSize;
dwStatus = BuildBftpRespPdu( dwPduSize, &pHeader, &pCommand, &pCommandHeader );
if (dwStatus == NO_ERROR) { pQueryResp = pCommand->UserData;
// Set the number of bFTP attributes:
pUShort = (USHORT*)pQueryResp; *pUShort = 1; #ifdef LITTLE_ENDIAN
*pUShort = ByteSwapShort(*pUShort); #endif
// Set the BDY0 for the query response:
pAttr = (BFTP_ATTRIBUTE*)(sizeof(USHORT)+pQueryResp); memcpy(pAttr->Name,Attributes[BDY0].pName,BFTP_NAME_SIZE); pAttr->Length = 2 + dwAttrValueSize; pAttr->Type = ATTR_TYPE_BINARY; pAttr->Flag = ATTR_FLAG_DEFAULT; memcpy(pAttr->Value,pAttrValue,dwAttrValueSize);
#ifdef LITTLE_ENDIAN
pAttr->Length = ByteSwapLong(pAttr->Length); #endif
*ppPdu = pHeader; *pdwPduSize = dwPduSize; }
return dwStatus; }
//--------------------------------------------------------------------
// CSCEP_CONNECTION::BuildPutRespPdu()
//
//--------------------------------------------------------------------
DWORD CSCEP_CONNECTION::BuildPutRespPdu( IN DWORD dwPduAckOrNack, IN USHORT usErrorCode, OUT SCEP_HEADER **ppPdu, OUT DWORD *pdwPduSize ) { DWORD dwStatus = NO_ERROR; DWORD dwPduSize; DWORD dwRespSize; DWORD dwFileNameLen; SCEP_HEADER *pHeader; SCEP_REQ_HEADER_SHORT *pCommand; COMMAND_HEADER *pCommandHeader; UCHAR *pQueryResp; USHORT *pUShort; BFTP_ATTRIBUTE *pAttr; UCHAR *pAttrValue;
*ppPdu = 0; *pdwPduSize = 0;
if (dwPduAckOrNack == PDU_TYPE_REPLY_ACK) { if (!m_pszFileName) { return ERROR_BFTP_INVALID_PROTOCOL; }
dwFileNameLen = strlen( (const char *)m_pszFileName ); dwRespSize = sizeof(USHORT) + sizeof(BFTP_ATTRIBUTE) + dwFileNameLen; } else { dwRespSize = sizeof(USHORT) + sizeof(BFTP_ATTRIBUTE) + sizeof(USHORT); }
dwPduSize = SCEP_HEADER_SIZE + SCEP_REQ_HEADER_SHORT_SIZE + dwRespSize;
dwStatus = BuildBftpRespPdu( dwPduSize, &pHeader, &pCommand, &pCommandHeader );
if (dwStatus == NO_ERROR) { pQueryResp = pCommand->UserData;
// Set the number of bFTP attributes:
pUShort = (USHORT*)pQueryResp; *pUShort = 1; #ifdef LITTLE_ENDIAN
*pUShort = ByteSwapShort(*pUShort); #endif
pAttr = (BFTP_ATTRIBUTE*)(sizeof(USHORT)+pQueryResp);
if (dwPduAckOrNack == PDU_TYPE_REPLY_ACK) { // Set the RPL0 for the put response (ACK):
memcpy(pAttr->Name,Attributes[RPL0].pName,BFTP_NAME_SIZE); pAttr->Length = 2 + dwFileNameLen; pAttr->Type = ATTR_TYPE_CHAR; pAttr->Flag = ATTR_FLAG_DEFAULT; memcpy(pAttr->Value,m_pszFileName,dwFileNameLen); } else { // Nack the PUT:
pCommandHeader->PduType = PDU_TYPE_REPLY_NACK;
// Set the ERR0 for the put response (NACK):
memcpy(pAttr->Name,Attributes[RPL0].pName,BFTP_NAME_SIZE); pAttr->Length = 2 + sizeof(USHORT); pAttr->Type = ATTR_TYPE_BINARY; pAttr->Flag = ATTR_FLAG_DEFAULT;
#ifdef LITTLE_ENDIAN
usErrorCode = ByteSwapShort(usErrorCode); #endif
memcpy(pAttr->Value,&usErrorCode,sizeof(USHORT)); }
#ifdef LITTLE_ENDIAN
pAttr->Length = ByteSwapLong(pAttr->Length); #endif
*ppPdu = pHeader; *pdwPduSize = dwPduSize; }
return dwStatus; }
|