C/C++开发,根据磁盘或网卡创建软件License约束(c++)

目录

一、软件版权保护

二、硬件信息绑定License软件保护策略

三、License接口调用策略

四、完整源码及工程配置补充资料


一、软件版权保护

        为了保护软件成果,通常会设置在使用软件时需要进行认证、鉴权、有效期的识别:

(1)对于在线系统通常的做法是设计与部署一个认证服务,软件链接登陆服务获得认证信息(License)实现,当然也可以一旦通过验证,将License本地存储使用。

(2)离线系统一般是通过绑定软件安装的机器或者发放序列号的方式控制。如果是绑定软件安装的机器需要在license申请前采集机器指纹(含CPU、硬盘、MAC地址等一种或者几种信息的加密数据)。机器指纹的加密算法一般是采用不可逆的加密算法,如MD5等。

        另外更复杂的License创建策略会将控制的功能项编码、受限使用的控制信息、使用期限等信息加密放到license中,在软件运行过程中实时检测。大多商业系统或软件会采用license发放的时候用公钥加密,软件运行时通过私钥解密等方式实现。而很多为项目或某特定行业服务的工具软件大多使用机器指纹进行私钥加密/解密实现。

二、硬件信息绑定License软件保护策略

        下面讲述根据磁盘或网卡创建软件License的方法,其采用对称式加密,即加密和解密使用同一个密钥,加密算法是自定义的,绝大多数个人工具、项目工具的开发都可以采用,对软件工具起到一定的保护作用。

(1)获取网卡或磁盘信息

bool CLicense::Create()
{
	source_flag = false;

#ifdef _WIN32
if (m_nMacType == 0) // 取网卡地址 
{
	DWORD m_dwNetCardCount = 0;
	PIP_ADAPTER_INFO m_pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
	ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);

	DWORD dwRetVal = GetAdaptersInfo(m_pAdapterInfo, &ulOutBufLen);
	if (dwRetVal == ERROR_BUFFER_OVERFLOW)
	{
		free(m_pAdapterInfo);
		m_pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
		dwRetVal = GetAdaptersInfo(m_pAdapterInfo, &ulOutBufLen);
	}

	if (dwRetVal == NO_ERROR)
	{
		PIP_ADAPTER_INFO pAdapter = m_pAdapterInfo;
		while (pAdapter)
		{
			TRACE("\tAdapter Name: \t%s\n", pAdapter->AdapterName);
			TRACE("\tAdapter Desc: \t%s\n", pAdapter->Description);
			TRACE("\tAdapter Addr: \t%ld\n", pAdapter->Address);
			TRACE("\tIP Address: \t%s\n", pAdapter->IpAddressList.IpAddress.String);
			TRACE("\tIP Mask: \t%s\n", pAdapter->IpAddressList.IpMask.String);

			TRACE("\tGateway: \t%s\n", pAdapter->GatewayList.IpAddress.String);
			TRACE("\t***\n");
			if (pAdapter->DhcpEnabled)
			{
				TRACE("\tDHCP Enabled: Yes\n");
				TRACE("\t\tDHCP Server: \t%s\n", pAdapter->DhcpServer.IpAddress.String);
				TRACE("\tLease Obtained: %ld\n", pAdapter->LeaseObtained);
			}
			else
				TRACE("\tDHCP Enabled: No\n");

			if (pAdapter->HaveWins)
			{
				TRACE("\tHave Wins: Yes\n");
				TRACE("\t\tPrimary Wins Server: \t%s\n", pAdapter->PrimaryWinsServer.IpAddress.String);
				TRACE("\t\tSecondary Wins Server: \t%s\n", pAdapter->SecondaryWinsServer.IpAddress.String);
			}
			else
				TRACE("\tHave Wins: No\n");

			pAdapter = pAdapter->Next;
			m_dwNetCardCount++;
		}
	}
	else
	{
		free(m_pAdapterInfo);
		m_pAdapterInfo = NULL;
	}

	PIP_ADAPTER_INFO pAdapter = m_pAdapterInfo;
	while (pAdapter)
	{
		sprintf(szMacAddress, "%02X-%02X-%02X-%02X-%02X-%02X", 
			pAdapter->Address[0], pAdapter->Address[1], pAdapter->Address[2], 
			pAdapter->Address[3], pAdapter->Address[4], pAdapter->Address[5]);

		addr[0] = pAdapter->Address[0];
		addr[1] = pAdapter->Address[1];
		addr[2] = pAdapter->Address[2];
		addr[3] = pAdapter->Address[3];
		addr[4] = pAdapter->Address[4];
		addr[5] = pAdapter->Address[5];

		pAdapter = pAdapter->Next;

		source_flag = true;
		break;
	}
}
else // 取磁盘码 
{
	for (int i=0; i<5; i++)
	{
		memset(szMacAddress,0x00,sizeof(szMacAddress));
		if ((byMacAddrLen=GetHDSN(szMacAddress,i))>0)
		{
			source_flag = true;
			break;
		}
	}
}
#else
	/* implementation for Linux */
	int fd;
	if (m_nMacType == 0)	// 取网卡序列号
	{
		fd = socket(AF_INET, SOCK_DGRAM, 0);
		printf("socket fd is %d!\n",fd);
		if (fd == -1) {
			return source_flag;
		}

		char buf[1024];
		struct ifconf ifc;
		int ok = 0;
		ifc.ifc_len = sizeof(buf);
		ifc.ifc_buf = buf;
		ioctl(fd, SIOCGIFCONF, &ifc);

		struct ifreq *IFR = ifc.ifc_req;
		struct ifreq ifr;

		for (int i = ifc.ifc_len/sizeof(struct ifreq); --i >= 0; IFR++)
		{
			strcpy(ifr.ifr_name, IFR->ifr_name);
			if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0) 
			{
				if (!(ifr.ifr_flags & IFF_LOOPBACK) && (ioctl(fd, SIOCGIFHWADDR, &ifr) == 0))
				{
					ok = 1;
					break;
				}
			}
		}
		close(fd);
		if (ok)
		{
			bcopy(ifr.ifr_hwaddr.sa_data, addr, 6);
			source_flag = true;
		}else{
			printf("ifr.ifr_hwaddr.sa_data is NULL!\n");
		}
	}
	else	// 取磁盘码 added 2017.01.20
	{
		struct hd_driveid hd;
		int ok = 0;
		memset(szMacAddress,0x00,sizeof(szMacAddress));
		bool openf = true;
		if ((fd = open("/dev/hdc", O_RDONLY|O_NONBLOCK)) < 0
			&& (fd = open("/dev/hdb", O_RDONLY|O_NONBLOCK)) < 0
			&& (fd = open("/dev/sda", O_RDONLY|O_NONBLOCK)) < 0
			&& (fd = open("/dev/sdb", O_RDONLY|O_NONBLOCK)) < 0) 
		{
			printf("open /dev/hdc fail!\n");
			return source_flag;
		}
		
		if (!ioctl(fd, HDIO_GET_IDENTITY, &hd)) {
			//printf("Hard Disk Model: %.40s\n", hd.model);
			//printf("  Serial Number: %.20s\n", hd.serial_no);
			ok = 1;
		}
		if (ok)
		{
			sprintf(szMacAddress,"%.20s",hd.serial_no);
			byMacAddrLen = strlen(szMacAddress);
			source_flag = true;
		}else{
			printf("szMacAddress is NULL!\n");
		}
	}
#endif
	return source_flag;
}

// **********************************************************************************************************
// 取硬盘序列码
// **********************************************************************************************************
int CLicense::GetHDSN(char * szSN, int n) 
{
	//int done = -1;
	int ret = 0;
#ifdef _WIN32
	{
		char szHDName[512];
		sprintf_s(szHDName, "\\\\.\\PhysicalDrive%d", n);
		HANDLE hPhysicalDriveIOCTL = 0;
		hPhysicalDriveIOCTL = CreateFile (szHDName,
			GENERIC_READ | GENERIC_WRITE, 
			FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 
			NULL, OPEN_EXISTING, 0, NULL);
		if (hPhysicalDriveIOCTL == INVALID_HANDLE_VALUE)
		{
			TRACE("\tCreateFile Ret : INVALID_HANDLE_VALUE\n");
			printf("CreateFile Return(INVALID_HANDLE_VALUE) and error(%d)\n", GetLastError());
		}
		else
		{
			GETVERSIONINPARAMS GetVersionParams;
			DWORD cbBytesReturned = 0;
			memset ((void*) & GetVersionParams, 0, sizeof(GetVersionParams));
			if ( ! DeviceIoControl (hPhysicalDriveIOCTL, SMART_GET_VERSION,
				NULL, 
				0,
				&GetVersionParams, sizeof (GETVERSIONINPARAMS),
				&cbBytesReturned, NULL) )
			{         
				;
			}
			else
			{
				ULONG CommandSize = sizeof(SENDCMDINPARAMS) + IDENTIFY_BUFFER_SIZE;
				PSENDCMDINPARAMS Command = (PSENDCMDINPARAMS) malloc (CommandSize);
				//#define ID_CMD          0xEC            // Returns ID sector for ATA
				Command -> irDriveRegs.bCommandReg = 0xEC; //ID_CMD;
				DWORD BytesReturned = 0;
				if ( ! DeviceIoControl (hPhysicalDriveIOCTL,
					SMART_RCV_DRIVE_DATA, Command, sizeof(SENDCMDINPARAMS),
					Command, CommandSize,
					&BytesReturned, NULL) )
				{
					;
				} 
				else
				{
					DWORD diskdata [256];
					USHORT *pIdSector = (USHORT *)
						/*(PIDENTIFY_DATA)*/ ((PSENDCMDOUTPARAMS) Command) -> bBuffer;
					//printf("diskdata:\n");
					for (int ijk = 0; ijk < 256; ijk++) {
						diskdata[ijk] = pIdSector[ijk];
						//printf("%ld ", diskdata[ijk]);
					}
					//printf("\n");
					if(szSN)
					{
						int index = 0;
						int position = 0;
						for (index = 10; index <= 19; index++)
						{
							szSN [position++] = (char) (diskdata [index] / 256);
							szSN [position++] = (char) (diskdata [index] % 256);
						}
						szSN[position] = '\0';
						for (index = position - 1; index > 0 && isspace(szSN [index]); index--)
							szSN [index] = '\0';
					}
					//done = TRUE;
				}
				CloseHandle (hPhysicalDriveIOCTL);
				free (Command);
				Command = NULL;
			}
		}
	}
	ret = static_cast<int>(strlen(szSN));
#else
	;
#endif
	return ret;
}

(2)根据网卡或磁盘信息进行加密,加密算法可以自行根据需要调整,最好是不可逆的加密算法

bool CLicense::encrypt()
{
	if (!source_flag)
		return false;
	if (m_nMacType == 0) // 网卡地址加密
	{
		sprintf(szMacAddress, "%0X-%0X-%0X-%0X-%0X-%0X\n"
			, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
		for (unsigned char b = 0; b < 6; b++) {
			addr[b] ^= 2 * (b + 1) + 0x88;
		}

		unsigned long dwCRC = GetLicense(&addr[0], 2) + (GetLicense(&addr[2], 4) << 16);
		sprintf(m_szLicense, "%u", dwCRC);
		for (unsigned int i = 0; i < strlen(m_szLicense); i++)
		{
			if (m_szLicense[i] <= '5') 
				m_szLicense[i] = m_szLicense[i] - '0' + 'A';
			else 
				m_szLicense[i] = m_szLicense[i] - '6' + '0';
		}
	}
	else // 硬盘序列码加密 
	{
		char buf[128] = { '\0' };
		for (int i = 0; i < byMacAddrLen && i < sizeof(m_szLicense); i++)
		{
			m_szLicense[i] = (u_char)GetLicense((u_char *)&szMacAddress[i], byMacAddrLen - i);
			if (m_szLicense[i] <= '5') 
				m_szLicense[i] = m_szLicense[i] - '0' + 'A';
			else 
				m_szLicense[i] = m_szLicense[i] - '6' + '0';
			char tmp[3] = { '\0' };
			sprintf(tmp, "%02X", (u_char)m_szLicense[i]);
			strncat(buf, tmp, strlen(tmp));
		}
		strncpy(m_szLicense, buf, (strlen(buf) >= MAX_LICENSE_SIZE) ? (MAX_LICENSE_SIZE - 1) : strlen(buf));
	}
	//printf("mac address %s ==> %s\n", szMacAddress, m_szLicense);
	return true;
};

三、License接口调用策略

        (3)编程实现License工具,调用函数生成机器指纹(网卡信息或磁盘信息),根据机器指纹生成License

#include "License.h"
//软件License测试
int main(int argc, char *argv[])
{
	printf("Run ...\n");
	int license_mode=0;
	int encrypt_mode = 0;
	if (argc > 1)
	{
		sscanf(argv[1],"%d",&license_mode);
	}
	if (argc > 2)
	{
		sscanf(argv[2], "%d", &encrypt_mode);
	}
	printf("License mode is %s\n",(license_mode==0)?"NetCard":"Disk");
	
	CLicense sn;
	sn.SetMacAddrType(license_mode);
	switch (encrypt_mode)
	{
	case 0: //获取硬件信息
	{
		//获取
		if(!sn.Create())
			printf("CLicense Create fail!\n");
		//打印输出
		std::string strSn = sn.ToStringS();
		printf("strSn:%s\n", strSn.c_str());
		//向文件写入硬件信息
		sn.SerializeSource("sc.txt", true);
	}
		break;
	case 11: //根据硬件信息生成License
	{
		//从文件读取硬件信息
		sn.SerializeSource("sc.txt", false);
		//生成算法
		sn.encrypt();
		//打印输出
		std::string strSn = sn.ToString();
		printf("strSn:%s\n", strSn.c_str());
		//向文件写入License
		sn.Serialize("sn.txt", true);
	}
		break;
	default:
		printf("encrypt_mode is NULL\n");
		break;
	}
	return 0;
}

        (4)在软件工具上进行验证,先读取License工具生成的License文件,与软件工具创建的License做校对

bool LicenseCheck()
{
	bool license_check = false;
#ifdef DEBUG //不做校对
	license_check = false;
#else
	license_check = true;
#endif
	bool bRet = !license_check;
	if (!bRet)
	{
		CLicense sn1;
		if (sn1.Serialize("sn.txt", false))
		{
			CLogger::createInstance()->Log(eTipMessage
				, "license:%s", sn1.ToString().c_str());
			CLicense sn;	// used netcard serial first
			if (sn.Create()&&sn.encrypt())
				bRet = (sn1 == sn);
			if (!bRet)
			{
				sn.SetMacAddrType(1); // used HD serial second
				if (sn.Create()&&sn.encrypt())
					bRet = (sn1 == sn);
			}
		}
	}

	return bRet;
};

int main(int argc, char* argv[])
{
   if (!LicenseCheck()) {
		printf("license is error, please make sure software instance is right first!");
		exit(true);
	}
   //your code
}

        总的来说,软件License创建就是根据机器指纹(磁盘、网卡、CPU等一种或多种信息),这些机器指纹信息具有惟一性和确定性,很好作为软件使用约束的依据,通过机器指纹生成License实现软件工具与机器绑定。如果是商用软件,最好采用不可逆的非对称式加密算法实现,即“公钥”和“私钥”配对使用。

四、完整源码及工程配置补充资料

        附件给出本实例中软件License工具的全部代码,关于License的头文件及源码有些复杂,是因我还有兼顾其他用途,大家可以自行简化,希望能帮助到有需要的小伙伴。

CMakeLists.txt

# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (SoftWareLicense)
#
if(WIN32)
    message(STATUS "windows compiling...")
    add_definitions(-D_PLATFORM_IS_WINDOWS_)
	set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
	set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
else(WIN32)
    message(STATUS "linux compiling...")
    add_definitions( -D_PLATFORM_IS_LINUX_)
endif(WIN32)
#
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
# 指定源文件的目录,并将名称保存到变量
SET(source_h
    ${PROJECT_SOURCE_DIR}/common/License.h
	${PROJECT_SOURCE_DIR}/common/ostype.h
  )
  
SET(source_cpp
    ${PROJECT_SOURCE_DIR}/common/License.cpp
	${PROJECT_SOURCE_DIR}/src/main.cpp
  )
  
#头文件目录
include_directories(${PROJECT_SOURCE_DIR}/common)
# 指定生成目标
add_executable(SWL ${source_h} ${source_cpp})

src/main.cpp

#include "License.h"

int main(int argc, char *argv[])
{
	printf("Run ...\n");
	int license_mode=0;
	int encrypt_mode = 0;
	if (argc > 1)
	{
		sscanf(argv[1],"%d",&license_mode);
	}
	if (argc > 2)
	{
		sscanf(argv[2], "%d", &encrypt_mode);
	}
	printf("License mode is %s\n",(license_mode==0)?"NetCard":"Disk");
	
	CLicense sn;
	sn.SetMacAddrType(license_mode);
	switch (encrypt_mode)
	{
	case 0: //获取硬件信息
	{
		//获取
		if(!sn.Create())
			printf("CLicense Create fail!\n");
		//打印输出
		std::string strSn = sn.ToStringS();
		printf("strSn:%s\n", strSn.c_str());
		//向文件写入硬件信息
		sn.SerializeSource("sc.txt", true);
	}
		break;
	case 11: //根据硬件信息生成License
	{
		//从文件读取硬件信息
		sn.SerializeSource("sc.txt", false);
		//生成算法
		sn.encrypt();
		//打印输出
		std::string strSn = sn.ToString();
		printf("strSn:%s\n", strSn.c_str());
		//向文件写入License
		sn.Serialize("sn.txt", true);
	}
		break;
	default:
		printf("encrypt_mode is NULL\n");
		break;
	}
	return 0;
}

common/License.h

#ifndef __SNFACTORY_H__
#define __SNFACTORY_H__

// ANSC C/C++
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <cassert>
#include <vector>

#define MAX_LICENSE_SIZE 32

class CLicense
{
public:
	CLicense();
	CLicense(const CLicense& other);
	bool operator !=(const CLicense& other);
	bool operator ==(const CLicense& other);

	bool Create();
	bool encrypt();
	bool SerializeSource(const char* strFile, bool bStoring);
	std::string ToStringS() const;
	bool Serialize(const char* strFile, bool bStoring);
	std::string ToString() const;
	// added 2010.11.15
	void SetMacAddrType(int mMacType){m_nMacType = mMacType;} // 设置取物理地址类型
private:
	bool string_divide(std::vector<std::string> &_strlist, const std::string src, const std::string div);
protected:
	bool source_flag;
	char szMacAddress[128];
	unsigned char addr[6];
	unsigned char byMacAddrLen;
	//
	char m_szLicense[MAX_LICENSE_SIZE];
	int GetHDSN(char * szSN, int n);
	int m_nMacType;
};

#endif  /*__SNFACTORY_H__*/

common/License.cpp

#include "License.h"

#include "ostype.h"

#ifdef _WIN32
// === 增加硬盘序列码 ===
#include <Windows.h>
#include <winioctl.h>
#define SMART_GET_VERSION       CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS)
// ==================================
#include <Iphlpapi.h>
#pragma comment(lib, "Iphlpapi.lib")
#else
// linux
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>

#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>  // socket
#include <arpa/inet.h>
#include <sys/times.h>  // time
#include <sys/select.h> 
#include <sys/ioctl.h>
#include <net/if.h>
//#include <net/if_arp.h>
#include <linux/hdreg.h> //Drive specific defs
#include <sys/wait.h>
#include <sys/stat.h>
#include <stdexcept>
#endif

//******************************************************************************************************
static unsigned short GetLicense(unsigned char* byData,unsigned short wLen)
{
	static const unsigned short crctable[256] = 
	{
		0x0000,0x365e,0x6cbc,0x5ae2,0xd978,0xef26,0xb5c4,0x839a,0xff89,0xc9d7,0x9335,0xa56b,0x26f1,0x10af,0x4a4d,0x7c13,
		0xb26b,0x8435,0xded7,0xe889,0x6b13,0x5d4d,0x07af,0x31f1,0x4de2,0x7bbc,0x215e,0x1700,0x949a,0xa2c4,0xf826,0xce78,
		0x29af,0x1ff1,0x4513,0x734d,0xf0d7,0xc689,0x9c6b,0xaa35,0xd626,0xe078,0xba9a,0x8cc4,0x0f5e,0x3900,0x63e2,0x55bc,
		0x9bc4,0xad9a,0xf778,0xc126,0x42bc,0x74e2,0x2e00,0x185e,0x644d,0x5213,0x08f1,0x3eaf,0xbd35,0x8b6b,0xd189,0xe7d7,
		0x535e,0x6500,0x3fe2,0x09bc,0x8a26,0xbc78,0xe69a,0xd0c4,0xacd7,0x9a89,0xc06b,0xf635,0x75af,0x43f1,0x1913,0x2f4d,
		0xe135,0xd76b,0x8d89,0xbbd7,0x384d,0x0e13,0x54f1,0x62af,0x1ebc,0x28e2,0x7200,0x445e,0xc7c4,0xf19a,0xab78,0x9d26,
		0x7af1,0x4caf,0x164d,0x2013,0xa389,0x95d7,0xcf35,0xf96b,0x8578,0xb326,0xe9c4,0xdf9a,0x5c00,0x6a5e,0x30bc,0x06e2,
		0xc89a,0xfec4,0xa426,0x9278,0x11e2,0x27bc,0x7d5e,0x4b00,0x3713,0x014d,0x5baf,0x6df1,0xee6b,0xd835,0x82d7,0xb489,
		0xa6bc,0x90e2,0xca00,0xfc5e,0x7fc4,0x499a,0x1378,0x2526,0x5935,0x6f6b,0x3589,0x03d7,0x804d,0xb613,0xecf1,0xdaaf,
		0x14d7,0x2289,0x786b,0x4e35,0xcdaf,0xfbf1,0xa113,0x974d,0xeb5e,0xdd00,0x87e2,0xb1bc,0x3226,0x0478,0x5e9a,0x68C4,
		0x8f13,0xb94d,0xe3af,0xd5f1,0x566b,0x6035,0x3ad7,0x0c89,0x709a,0x46c4,0x1c26,0x2a78,0xa9e2,0x9fbc,0xc55e,0xf300,
		0x3d78,0x0b26,0x51c4,0x679a,0xe400,0xd25e,0x88bc,0xbee2,0xc2f1,0xf4af,0xae4d,0x9813,0x1b89,0x2dd7,0x7735,0x416b,
		0xf5e2,0xc3bc,0x995e,0xaf00,0x2c9a,0x1ac4,0x4026,0x7678,0x0a6b,0x3c35,0x66d7,0x5089,0xd313,0xe54d,0xbfaf,0x89f1,
		0x4789,0x71d7,0x2b35,0x1d6b,0x9ef1,0xa8af,0xf24d,0xc413,0xb800,0x8e5e,0xd4bc,0xe2e2,0x6178,0x5726,0x0dc4,0x3b9a,
		0xdc4d,0xea13,0xb0f1,0x86af,0x0535,0x336b,0x6989,0x5fd7,0x23c4,0x159a,0x4f78,0x7926,0xfabc,0xcce2,0x9600,0xa05e,
		0x6e26,0x5878,0x029a,0x34c4,0xb75e,0x8100,0xdbe2,0xedbc,0x91af,0xa7f1,0xfd13,0xcb4d,0x48d7,0x7e89,0x246b,0x1235
	};

	unsigned short X = 0;
	for (unsigned short i = 0; i < wLen; i++)
		X = (X / 256) ^ (crctable[(X % 256) ^ byData[i]]) ;
	return (X ^ 0xffff);
}

//**********************************************************************************************************
CLicense::CLicense()
{
	source_flag = false;
	memset(szMacAddress, '\0', 128);
	memset(addr, '\0', 6);
	byMacAddrLen = 0;
	memset(m_szLicense, '\0', MAX_LICENSE_SIZE);
	m_nMacType = 0; // 缺省为取网卡地址
}

//**********************************************************************************************************
CLicense::CLicense(const CLicense& other)
{

}

//**********************************************************************************************************
bool CLicense::operator !=(const CLicense& other)
{
	bool b = strcmp(m_szLicense, other.m_szLicense) != 0;
	return b;
}

//**********************************************************************************************************
bool CLicense::operator ==(const CLicense& other)
{
	//printf("%s==%s\n", m_szLicense, other.m_szLicense);
	bool b = strcmp(m_szLicense, other.m_szLicense) == 0;
	return b;
}

//**********************************************************************************************************
bool CLicense::Create()
{
	source_flag = false;

#ifdef _WIN32
if (m_nMacType == 0) // 取网卡地址 
{
	DWORD m_dwNetCardCount = 0;
	PIP_ADAPTER_INFO m_pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
	ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);

	DWORD dwRetVal = GetAdaptersInfo(m_pAdapterInfo, &ulOutBufLen);
	if (dwRetVal == ERROR_BUFFER_OVERFLOW)
	{
		free(m_pAdapterInfo);
		m_pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
		dwRetVal = GetAdaptersInfo(m_pAdapterInfo, &ulOutBufLen);
	}

	if (dwRetVal == NO_ERROR)
	{
		PIP_ADAPTER_INFO pAdapter = m_pAdapterInfo;
		while (pAdapter)
		{
			TRACE("\tAdapter Name: \t%s\n", pAdapter->AdapterName);
			TRACE("\tAdapter Desc: \t%s\n", pAdapter->Description);
			TRACE("\tAdapter Addr: \t%ld\n", pAdapter->Address);
			TRACE("\tIP Address: \t%s\n", pAdapter->IpAddressList.IpAddress.String);
			TRACE("\tIP Mask: \t%s\n", pAdapter->IpAddressList.IpMask.String);

			TRACE("\tGateway: \t%s\n", pAdapter->GatewayList.IpAddress.String);
			TRACE("\t***\n");
			if (pAdapter->DhcpEnabled)
			{
				TRACE("\tDHCP Enabled: Yes\n");
				TRACE("\t\tDHCP Server: \t%s\n", pAdapter->DhcpServer.IpAddress.String);
				TRACE("\tLease Obtained: %ld\n", pAdapter->LeaseObtained);
			}
			else
				TRACE("\tDHCP Enabled: No\n");

			if (pAdapter->HaveWins)
			{
				TRACE("\tHave Wins: Yes\n");
				TRACE("\t\tPrimary Wins Server: \t%s\n", pAdapter->PrimaryWinsServer.IpAddress.String);
				TRACE("\t\tSecondary Wins Server: \t%s\n", pAdapter->SecondaryWinsServer.IpAddress.String);
			}
			else
				TRACE("\tHave Wins: No\n");

			pAdapter = pAdapter->Next;
			m_dwNetCardCount++;
		}
	}
	else
	{
		free(m_pAdapterInfo);
		m_pAdapterInfo = NULL;
	}

	PIP_ADAPTER_INFO pAdapter = m_pAdapterInfo;
	while (pAdapter)
	{
		sprintf(szMacAddress, "%02X-%02X-%02X-%02X-%02X-%02X", 
			pAdapter->Address[0], pAdapter->Address[1], pAdapter->Address[2], 
			pAdapter->Address[3], pAdapter->Address[4], pAdapter->Address[5]);

		addr[0] = pAdapter->Address[0];
		addr[1] = pAdapter->Address[1];
		addr[2] = pAdapter->Address[2];
		addr[3] = pAdapter->Address[3];
		addr[4] = pAdapter->Address[4];
		addr[5] = pAdapter->Address[5];

		pAdapter = pAdapter->Next;

		source_flag = true;
		break;
	}
}
else // 取磁盘码 
{
	for (int i=0; i<5; i++)
	{
		memset(szMacAddress,0x00,sizeof(szMacAddress));
		if ((byMacAddrLen=GetHDSN(szMacAddress,i))>0)
		{
			source_flag = true;
			break;
		}
	}
}
#else
	/* implementation for Linux */
	int fd;
	if (m_nMacType == 0)	// 取网卡序列号
	{
		fd = socket(AF_INET, SOCK_DGRAM, 0);
		printf("socket fd is %d!\n",fd);
		if (fd == -1) {
			return source_flag;
		}

		char buf[1024];
		struct ifconf ifc;
		int ok = 0;
		ifc.ifc_len = sizeof(buf);
		ifc.ifc_buf = buf;
		ioctl(fd, SIOCGIFCONF, &ifc);

		struct ifreq *IFR = ifc.ifc_req;
		struct ifreq ifr;

		for (int i = ifc.ifc_len/sizeof(struct ifreq); --i >= 0; IFR++)
		{
			strcpy(ifr.ifr_name, IFR->ifr_name);
			if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0) 
			{
				if (!(ifr.ifr_flags & IFF_LOOPBACK) && (ioctl(fd, SIOCGIFHWADDR, &ifr) == 0))
				{
					ok = 1;
					break;
				}
			}
		}
		close(fd);
		if (ok)
		{
			bcopy(ifr.ifr_hwaddr.sa_data, addr, 6);
			source_flag = true;
		}else{
			printf("ifr.ifr_hwaddr.sa_data is NULL!\n");
		}
	}
	else	// 取磁盘码
	{
		struct hd_driveid hd;
		int ok = 0;
		memset(szMacAddress,0x00,sizeof(szMacAddress));
		bool openf = true;
		if ((fd = open("/dev/hdc", O_RDONLY|O_NONBLOCK)) < 0
			&& (fd = open("/dev/hdb", O_RDONLY|O_NONBLOCK)) < 0
			&& (fd = open("/dev/sda", O_RDONLY|O_NONBLOCK)) < 0
			&& (fd = open("/dev/sdb", O_RDONLY|O_NONBLOCK)) < 0) 
		{
			printf("open /dev/hdc fail!\n");
			return source_flag;
		}
		
		if (!ioctl(fd, HDIO_GET_IDENTITY, &hd)) {
			//printf("Hard Disk Model: %.40s\n", hd.model);
			//printf("  Serial Number: %.20s\n", hd.serial_no);
			ok = 1;
		}
		if (ok)
		{
			sprintf(szMacAddress,"%.20s",hd.serial_no);
			byMacAddrLen = strlen(szMacAddress);
			source_flag = true;
		}else{
			printf("szMacAddress is NULL!\n");
		}
	}
#endif
	return source_flag;
}

bool CLicense::encrypt()
{
	if (!source_flag)
		return false;
	if (m_nMacType == 0) // 网卡地址加密
	{
		sprintf(szMacAddress, "%0X-%0X-%0X-%0X-%0X-%0X\n"
			, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
		for (unsigned char b = 0; b < 6; b++) {
			addr[b] ^= 2 * (b + 1) + 0x88;
		}

		unsigned long dwCRC = GetLicense(&addr[0], 2) + (GetLicense(&addr[2], 4) << 16);
		sprintf(m_szLicense, "%u", dwCRC);
		for (unsigned int i = 0; i < strlen(m_szLicense); i++)
		{
			if (m_szLicense[i] <= '5') 
				m_szLicense[i] = m_szLicense[i] - '0' + 'A';
			else 
				m_szLicense[i] = m_szLicense[i] - '6' + '0';
		}
	}
	else // 硬盘序列码加密
	{
		char buf[128] = { '\0' };
		for (int i = 0; i < byMacAddrLen && i < sizeof(m_szLicense); i++)
		{
			m_szLicense[i] = (u_char)GetLicense((u_char *)&szMacAddress[i], byMacAddrLen - i);
			if (m_szLicense[i] <= '5') 
				m_szLicense[i] = m_szLicense[i] - '0' + 'A';
			else 
				m_szLicense[i] = m_szLicense[i] - '6' + '0';
			char tmp[3] = { '\0' };
			sprintf(tmp, "%02X", (u_char)m_szLicense[i]);
			strncat(buf, tmp, strlen(tmp));
		}
		strncpy(m_szLicense, buf, (strlen(buf) >= MAX_LICENSE_SIZE) ? (MAX_LICENSE_SIZE - 1) : strlen(buf));
	}
	//printf("mac address %s ==> %s\n", szMacAddress, m_szLicense);
	return true;
};

bool CLicense::string_divide(std::vector<std::string> &_strlist, const std::string src, const std::string div)
{
	std::string _src = src;
	std::string::size_type _pos = _src.find(div);
	while (std::string::npos != _pos)
	{
		std::string _buf = "";
		_buf = _src.substr(0, _pos);
		_strlist.push_back(_buf);
		_src = _src.erase(0, _pos + div.size());
		_pos = _src.find(div.c_str());
	}
	if (!_src.empty()) {
		_strlist.push_back(_src);
	}
	return true;
};

bool CLicense::SerializeSource(const char* strFile, bool bStoring)
{
	if (bStoring)
	{
		// Save
		if (strlen(szMacAddress) > 0)
		{
			std::ofstream fLincese(strFile);
			fLincese.write(szMacAddress, strlen(szMacAddress));
			return true;
		}
	}
	else
	{
		// Read
		std::ifstream fLincese(strFile);
		fLincese.read(szMacAddress, MAX_LICENSE_SIZE);
		byMacAddrLen = static_cast<unsigned char>(strlen(szMacAddress));
		bool read_flag = byMacAddrLen > 0 ? true : false;
		bool map_flag = false;
		if (0 == m_nMacType) {
			std::vector<std::string> _strlist;
			if (string_divide(_strlist,std::string(szMacAddress),"-"))
			{
				try
				{
					if (6 == _strlist.size()) {
						for (int index = 0; index < 6; index++)
						{
							int n = 0;
							for (int i = 0; i < 2; i++)
							{
								if (_strlist.at(index)[i] >= 'A'&&_strlist.at(index)[i] <= 'F')//十六进制还要判断他是不是在A-F或者a-f之间a=10。。
									n = _strlist.at(index)[i] - 'A' + 10;
								else if (_strlist.at(index)[i] >= 'a'&&_strlist.at(index)[i] <= 'f')
									n = _strlist.at(index)[i] - 'a' + 10;
								else
									n = _strlist.at(index)[i] - '0';
								addr[index] = addr[index] * 16 + n;
							}
						}
						map_flag = true;
					}
					else {
						#ifdef WIN32
						throw std::exception("MacAddress be split by \'-\' and size isn't 6");
						#else
						throw std::logic_error("MacAddress be split by \'-\' and size isn't 6");
						#endif
					}
				}
				catch (const std::exception& e)
				{
					printf("error(%s) for SerializeSource\r\n",e.what());
				}
			}
		}
		else {
			map_flag = true;
		}
		source_flag = read_flag&&map_flag;
		return read_flag;
	}

	return false;
};
std::string CLicense::ToStringS() const
{
	std::string strName = szMacAddress;
	return strName;
};

//**********************************************************************************************************
bool CLicense::Serialize(const char* strFile, bool bStoring)
{
	if (bStoring)
	{
		// Save
		if (strlen(m_szLicense) > 0)
		{
			std::ofstream fLincese(strFile);
			fLincese.write(m_szLicense, strlen(m_szLicense));
			return true;
		}
	}
	else
	{
		// Read
		std::ifstream fLincese(strFile);
		fLincese.read(m_szLicense, MAX_LICENSE_SIZE);
		return strlen(m_szLicense) > 0;
	}

	return false;
}

//**********************************************************************************************************
std::string CLicense::ToString() const
{
	std::string strName = m_szLicense;
	return strName;
}

// **********************************************************************************************************
// 取硬盘序列码
// **********************************************************************************************************
int CLicense::GetHDSN(char * szSN, int n) 
{
	//int done = -1;
	int ret = 0;
#ifdef _WIN32
	{
		char szHDName[512];
		sprintf_s(szHDName, "\\\\.\\PhysicalDrive%d", n);
		HANDLE hPhysicalDriveIOCTL = 0;
		hPhysicalDriveIOCTL = CreateFile (szHDName,
			GENERIC_READ | GENERIC_WRITE, 
			FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 
			NULL, OPEN_EXISTING, 0, NULL);
		if (hPhysicalDriveIOCTL == INVALID_HANDLE_VALUE)
		{
			TRACE("\tCreateFile Ret : INVALID_HANDLE_VALUE\n");
			printf("CreateFile Return(INVALID_HANDLE_VALUE) and error(%d)\n", GetLastError());
		}
		else
		{
			GETVERSIONINPARAMS GetVersionParams;
			DWORD cbBytesReturned = 0;
			memset ((void*) & GetVersionParams, 0, sizeof(GetVersionParams));
			if ( ! DeviceIoControl (hPhysicalDriveIOCTL, SMART_GET_VERSION,
				NULL, 
				0,
				&GetVersionParams, sizeof (GETVERSIONINPARAMS),
				&cbBytesReturned, NULL) )
			{         
				;
			}
			else
			{
				ULONG CommandSize = sizeof(SENDCMDINPARAMS) + IDENTIFY_BUFFER_SIZE;
				PSENDCMDINPARAMS Command = (PSENDCMDINPARAMS) malloc (CommandSize);
				//#define ID_CMD          0xEC            // Returns ID sector for ATA
				Command -> irDriveRegs.bCommandReg = 0xEC; //ID_CMD;
				DWORD BytesReturned = 0;
				if ( ! DeviceIoControl (hPhysicalDriveIOCTL,
					SMART_RCV_DRIVE_DATA, Command, sizeof(SENDCMDINPARAMS),
					Command, CommandSize,
					&BytesReturned, NULL) )
				{
					;
				} 
				else
				{
					DWORD diskdata [256];
					USHORT *pIdSector = (USHORT *)
						/*(PIDENTIFY_DATA)*/ ((PSENDCMDOUTPARAMS) Command) -> bBuffer;
					//printf("diskdata:\n");
					for (int ijk = 0; ijk < 256; ijk++) {
						diskdata[ijk] = pIdSector[ijk];
						//printf("%ld ", diskdata[ijk]);
					}
					//printf("\n");
					if(szSN)
					{
						int index = 0;
						int position = 0;
						for (index = 10; index <= 19; index++)
						{
							szSN [position++] = (char) (diskdata [index] / 256);
							szSN [position++] = (char) (diskdata [index] % 256);
						}
						szSN[position] = '\0';
						for (index = position - 1; index > 0 && isspace(szSN [index]); index--)
							szSN [index] = '\0';
					}
					//done = TRUE;
				}
				CloseHandle (hPhysicalDriveIOCTL);
				free (Command);
				Command = NULL;
			}
		}
	}
	ret = static_cast<int>(strlen(szSN));
#else
	;
#endif
	return ret;
}

common/ostype.h

#ifndef __OSTYPE_HH__
#define __OSTYPE_HH__

#ifdef _WIN32
#include <afx.h>
#define __WINDOWS__
#else
#define __LINUX__
#endif

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <string>
#include <list>
#include <vector>
#include <queue>
#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <set>
#include <sstream>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <string.h>
#include <time.h>
#include <assert.h>

#ifdef __WINDOWS__
#include <sys/timeb.h>
#include <WinSock2.h>
#endif

#ifdef __LINUX__
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <fcntl.h>
#include <termios.h>
#include <signal.h>

#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
//#include <sys/io.h>
#include <errno.h>
//#include <linux/if.h>
#include <net/if.h>
#define _atoi64(val) strtoll(val, NULL, 10)
#endif

#define _COMMONITOR
#define _BACK

typedef long long				INT64;
typedef unsigned long long		UINT64;
typedef unsigned char			BYTE;
typedef unsigned short			WORD;
typedef long					LONG;
typedef unsigned long			DWORD;
typedef int						BOOL;
typedef unsigned int			UINT;

#ifndef NULL
#define NULL 0
#endif

#ifndef TRUE
#define TRUE true
#endif

#ifndef FALSE
#define FALSE false
#endif

#ifdef UNICODE
typedef std::wstring XString;
#else
typedef std::string XString;
#endif

using namespace std;

#endif  /* __EXX_HH__ */
  • 11
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论
要实现一个停车场模拟管理程序,可以采用队列数据结构来管理停车场内的车辆。以下是简单的 C 代码实现: ```c #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #define MAX_SPACE 10 // 停车场最大容量 typedef struct car { char license[10]; // 车牌号 struct car *next; // 指向下一节点的指针 } Car; Car *head = NULL; // 停车场队列头指针 Car *tail = NULL; // 停车场队列尾指针 int count = 0; // 当前停车场内车辆数量 // 进入停车场 void in() { if (count >= MAX_SPACE) { printf("停车场已满,无法进入!\n"); return; } char license[10]; printf("请输入车牌号:"); scanf("%s", license); Car *car = (Car*)malloc(sizeof(Car)); strcpy(car->license, license); car->next = NULL; if (head == NULL) { head = car; } else { tail->next = car; } tail = car; count++; printf("车辆 %s 进入停车场,当前车辆数:%d\n", license, count); } // 离开停车场 void out() { if (count <= 0) { printf("停车场内无车辆!\n"); return; } char license[10]; printf("请输入车牌号:"); scanf("%s", license); Car *prev = NULL; Car *cur = head; while (cur != NULL) { if (strcmp(cur->license, license) == 0) { if (cur == head) { head = cur->next; } else if (cur == tail) { tail = prev; } else { prev->next = cur->next; } free(cur); count--; printf("车辆 %s 离开停车场,当前车辆数:%d\n", license, count); return; } prev = cur; cur = cur->next; } printf("停车场内无此车辆!\n"); } // 显示停车场内车辆信息 void show() { if (count <= 0) { printf("停车场内无车辆!\n"); return; } printf("停车场内车辆信息如下:\n"); Car *cur = head; while (cur != NULL) { printf("%s\n", cur->license); cur = cur->next; } } int main() { while (true) { printf("请选择操作:\n"); printf("1. 进入停车场\n"); printf("2. 离开停车场\n"); printf("3. 显示停车场内车辆信息\n"); printf("4. 退出程序\n"); int choice; scanf("%d", &choice); switch (choice) { case 1: in(); break; case 2: out(); break; case 3: show(); break; case 4: return 0; default: printf("输入有误,请重新选择操作!\n"); break; } } } ``` 该程序采用了简单的命令行交互方式,可以通过菜单选择进入停车场、离开停车场或查看停车场内车辆信息。停车场内车辆数量达到最大容量时,无法再进入车辆;停车场内无车辆时,无法离开车辆或查看车辆信息

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

py_free-物联智能

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值