From: longinus Date: Sun, 6 Dec 2009 16:22:57 +0000 (+0000) Subject: add b25-remote X-Git-Url: http://git.osdn.net/view?p=rec10%2Frec10-git.git;a=commitdiff_plain;h=7868a1563cc62577db56b634e7505107559dbc62 add b25-remote git-svn-id: svn+ssh://svn.sourceforge.jp/svnroot/rec10@303 4e526526-5e11-4fc0-8910-f8fd03428081 --- diff --git a/b25-remote/BCasCard.cpp b/b25-remote/BCasCard.cpp new file mode 100755 index 0000000..7d8387f --- /dev/null +++ b/b25-remote/BCasCard.cpp @@ -0,0 +1,361 @@ +// BcasCard.cpp: CBcasCard ƒNƒ‰ƒX‚̃Cƒ“ƒvƒŠƒƒ“ƒe[ƒVƒ‡ƒ“ +// +////////////////////////////////////////////////////////////////////// + +#include "W2L.h" +#include "BCasCard.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + + +//#pragma comment(lib, "WinScard.lib") + + +using std::auto_ptr; + + +CBcasCard::CBcasCard() + : m_hBcasCard(NULL) + , m_bIsEstablish(false) + , m_dwLastError(BCEC_NOERROR) +{ + // “à•”ó‘ԏ‰Šú‰» + memset(&m_BcasCardInfo, 0, sizeof(m_BcasCardInfo)); + memset(&m_EcmStatus, 0, sizeof(m_EcmStatus)); + + // ƒŠƒ\[ƒXƒ}ƒl[ƒWƒƒƒRƒ“ƒeƒLƒXƒgŠm—§ + if(::SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &m_ScardContext) != SCARD_S_SUCCESS){ + m_dwLastError = BCEC_NOTESTABLISHED; + } + else{ + m_bIsEstablish = true; + + // ƒJ[ƒhƒŠ[ƒ_—ñ‹“ + EnumCardReader(); + } +} + +CBcasCard::~CBcasCard() +{ + CloseCard(); + + // ƒŠƒ\[ƒXƒ}ƒl[ƒWƒƒƒRƒ“ƒeƒLƒXƒg‚ÌŠJ•ú + if(m_bIsEstablish)::SCardReleaseContext(m_ScardContext); +} + +const DWORD CBcasCard::GetCardReaderNum(void) const +{ + // ƒJ[ƒhƒŠ[ƒ_[”‚ð•Ô‚· + return m_CardReaderArray.size(); +} + +LPCTSTR CBcasCard::GetCardReaderName(const DWORD dwIndex) const +{ + // ƒJ[ƒhƒŠ[ƒ_[–¼‚ð•Ô‚· + return (dwIndex < GetCardReaderNum())? m_CardReaderArray[dwIndex].c_str() : NULL; +} + +const bool CBcasCard::OpenCard(LPCTSTR lpszReader) +{ + // ƒŠƒ\[ƒXƒ}ƒl[ƒWƒƒƒRƒ“ƒeƒLƒXƒg‚ÌŠm—§ + if(!m_bIsEstablish){ + m_dwLastError = BCEC_NOTESTABLISHED; + return false; + } + + // ˆê’UƒNƒ[ƒY‚·‚é + CloseCard(); + + + if(lpszReader){ + // Žw’肳‚ꂽƒJ[ƒhƒŠ[ƒ_‚ɑ΂µ‚ăI[ƒvƒ“‚ðŽŽ‚Ý‚é + DWORD dwActiveProtocol = SCARD_PROTOCOL_UNDEFINED; + + if(::SCardConnect(m_ScardContext, lpszReader, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1, &m_hBcasCard, &dwActiveProtocol) != SCARD_S_SUCCESS){ + m_dwLastError = BCEC_CARDOPENERROR; + return false; + } + + if(dwActiveProtocol != SCARD_PROTOCOL_T1){ + CloseCard(); + m_dwLastError = BCEC_CARDOPENERROR; + return false; + } + } + else{ + // ‘S‚ẴJ[ƒhƒŠ[ƒ_‚ɑ΂µ‚ăI[ƒvƒ“‚ðŽŽ‚Ý‚é + DWORD dwIndex = 0UL; + + while(GetCardReaderName(dwIndex)){ + if(OpenCard(GetCardReaderName(dwIndex++)))return true; + } + + return false; + } + + // ƒJ[ƒh‰Šú‰» + if(!InitialSetting())return false; + + m_dwLastError = BCEC_NOERROR; + + return true; +} + +void CBcasCard::CloseCard(void) +{ + // ƒJ[ƒh‚ðƒNƒ[ƒY‚·‚é + if(m_hBcasCard){ + ::SCardDisconnect(m_hBcasCard, SCARD_LEAVE_CARD); + m_hBcasCard = NULL; + } +} + +const DWORD CBcasCard::GetLastError(void) const +{ + // ÅŒã‚É”­¶‚µ‚½ƒGƒ‰[‚ð•Ô‚· + return m_dwLastError; +} + +const bool CBcasCard::EnumCardReader(void) +{ + // ƒJ[ƒhƒŠ[ƒ_‚ð—ñ‹“‚·‚é + DWORD dwBuffSize = 0UL; + + switch(::SCardListReaders(m_ScardContext, NULL, NULL, &dwBuffSize)){ + case SCARD_E_NO_READERS_AVAILABLE : + // ƒJ[ƒhƒŠ[ƒ_‚ªŒ©‚‚©‚ç‚È‚¢ + m_dwLastError = BCEC_NOCARDREADERS; + return false; + + case SCARD_S_SUCCESS : + // ƒoƒbƒtƒ@ƒTƒCƒYŽæ“¾¬Œ÷ + break; + + default: + // ƒGƒ‰[ + m_dwLastError = BCEC_INTERNALERROR; + return false; + } + + // ƒoƒbƒtƒ@Šm•Û + auto_ptr szReaders(new TCHAR[dwBuffSize]); + + switch(::SCardListReaders(m_ScardContext, NULL, szReaders.get(), &dwBuffSize)){ + case SCARD_E_NO_READERS_AVAILABLE : + // ƒJ[ƒhƒŠ[ƒ_‚ªŒ©‚‚©‚ç‚È‚¢ + m_dwLastError = BCEC_NOCARDREADERS; + return false; + + case SCARD_S_SUCCESS : { + // ƒJ[ƒhƒŠ[ƒ_–¼•Û‘¶ + LPTSTR lpszCurReader = szReaders.get(); + m_CardReaderArray.clear(); + + while(*lpszCurReader){ + m_CardReaderArray.push_back(lpszCurReader); + lpszCurReader += m_CardReaderArray.back().length() + 1UL; + } + + break; + } + + default: + // ƒGƒ‰[ + m_dwLastError = BCEC_INTERNALERROR; + return false; + } + + m_dwLastError = BCEC_NOERROR; + + return true; +} + +const bool CBcasCard::TransmitCommand(const BYTE *pSendData, const DWORD dwSendSize, BYTE *pRecvData, const DWORD dwMaxRecv, DWORD *pdwRecvSize) +{ + DWORD dwRecvSize = dwMaxRecv; + + // ƒf[ƒ^‘—ŽóM + DWORD dwReturn = ::SCardTransmit(m_hBcasCard, SCARD_PCI_T1, pSendData, dwSendSize, NULL, pRecvData, &dwRecvSize); + + // ŽóMƒTƒCƒYŠi”[ + if(pdwRecvSize)*pdwRecvSize = dwRecvSize; + + return (dwReturn == SCARD_S_SUCCESS)? true : false; +} + +const bool CBcasCard::InitialSetting(void) +{ + static const BYTE InitSettingCmd[] = {0x90U, 0x30U, 0x00U, 0x00U, 0x00U}; + + // uInitial Setting Conditions Commandv‚ðˆ—‚·‚é + if(!m_hBcasCard){ + m_dwLastError = BCEC_CARDNOTOPEN; + return false; + } + + // ƒoƒbƒtƒ@€”õ + DWORD dwRecvSize = 0UL; + BYTE RecvData[1024]; + memset(RecvData, 0, sizeof(RecvData)); + + // ƒRƒ}ƒ“ƒh‘—M + if(!TransmitCommand(InitSettingCmd, sizeof(InitSettingCmd), RecvData, sizeof(RecvData), &dwRecvSize)){ + m_dwLastError = BCEC_TRANSMITERROR; + return false; + } + + if(dwRecvSize < 57UL){ + m_dwLastError = BCEC_TRANSMITERROR; + return false; + } + + // ƒŒƒXƒ|ƒ“ƒX‰ðÍ + memcpy(m_BcasCardInfo.BcasCardID, &RecvData[8], 6UL); // +8 Card ID + memcpy(m_BcasCardInfo.SystemKey, &RecvData[16], 32UL); // +16 Descrambling system key + memcpy(m_BcasCardInfo.InitialCbc, &RecvData[48], 8UL); // +48 Descrambler CBC initial value + + // ECMƒXƒe[ƒ^ƒX‰Šú‰» + memset(&m_EcmStatus, 0, sizeof(m_EcmStatus)); + + return true; +} + +const BYTE * CBcasCard::GetBcasCardID(void) +{ + // Card ID ‚ð•Ô‚· + if(!m_hBcasCard){ + m_dwLastError = BCEC_CARDNOTOPEN; + return NULL; + } + + m_dwLastError = BCEC_NOERROR; + + return m_BcasCardInfo.BcasCardID; +} + +const BYTE * CBcasCard::GetInitialCbc(void) +{ + // Descrambler CBC Initial Value ‚ð•Ô‚· + if(!m_hBcasCard){ + m_dwLastError = BCEC_CARDNOTOPEN; + return NULL; + } + + m_dwLastError = BCEC_NOERROR; + + return m_BcasCardInfo.InitialCbc; +} + +const BYTE * CBcasCard::GetSystemKey(void) +{ + // Descrambling System Key ‚ð•Ô‚· + if(!m_hBcasCard){ + m_dwLastError = BCEC_CARDNOTOPEN; + return NULL; + } + + m_dwLastError = BCEC_NOERROR; + + return m_BcasCardInfo.SystemKey; +} + +const BYTE * CBcasCard::GetKsFromEcm(const BYTE *pEcmData, const DWORD dwEcmSize) +{ + static const BYTE EcmReceiveCmd[] = {0x90U, 0x34U, 0x00U, 0x00U}; + + // uECM Receive Commandv‚ðˆ—‚·‚é + if(!m_hBcasCard){ + m_dwLastError = BCEC_CARDNOTOPEN; + return NULL; + } + + // ECMƒTƒCƒY‚ðƒ`ƒFƒbƒN + if(!pEcmData || (dwEcmSize < 30UL) || (dwEcmSize > 256UL)){ + m_dwLastError = BCEC_BADARGUMENT; + return NULL; + } + + // ƒLƒƒƒbƒVƒ…‚ðƒ`ƒFƒbƒN‚·‚é + if(!StoreEcmData(pEcmData, dwEcmSize)){ + // ECM‚ª“¯ˆê‚̏ꍇ‚̓LƒƒƒbƒVƒ…Ï‚ÝKs‚ð•Ô‚· + m_dwLastError = BCEC_NOERROR; + return m_EcmStatus.KsData; + } + + // ƒoƒbƒtƒ@€”õ + DWORD dwRecvSize = 0UL; + BYTE SendData[1024]; + BYTE RecvData[1024]; + memset(RecvData, 0, sizeof(RecvData)); + + // ƒRƒ}ƒ“ƒh\’z + memcpy(SendData, EcmReceiveCmd, sizeof(EcmReceiveCmd)); // CLA, INS, P1, P2 + SendData[sizeof(EcmReceiveCmd)] = (BYTE)dwEcmSize; // COMMAND DATA LENGTH + memcpy(&SendData[sizeof(EcmReceiveCmd) + 1], pEcmData, dwEcmSize); // ECM + SendData[sizeof(EcmReceiveCmd) + dwEcmSize + 1] = 0x00U; // RESPONSE DATA LENGTH + + // ƒRƒ}ƒ“ƒh‘—M + if(!TransmitCommand(SendData, sizeof(EcmReceiveCmd) + dwEcmSize + 2UL, RecvData, sizeof(RecvData), &dwRecvSize)){ + memset(&m_EcmStatus, 0, sizeof(m_EcmStatus)); + m_dwLastError = BCEC_TRANSMITERROR; + return NULL; + } + + // ƒTƒCƒYƒ`ƒFƒbƒN + if(dwRecvSize != 25UL){ + memset(&m_EcmStatus, 0, sizeof(m_EcmStatus)); + m_dwLastError = BCEC_TRANSMITERROR; + return NULL; + } + + // ƒŒƒXƒ|ƒ“ƒX‰ðÍ + memcpy(m_EcmStatus.KsData, &RecvData[6], sizeof(m_EcmStatus.KsData)); + + // ƒŠƒ^[ƒ“ƒR[ƒh‰ðÍ + switch(((WORD)RecvData[4] << 8) | (WORD)RecvData[5]){ + // Purchased: Viewing + case 0x0200U : // Payment-deferred PPV + case 0x0400U : // Prepaid PPV + case 0x0800U : // Tier + m_dwLastError = BCEC_NOERROR; + return m_EcmStatus.KsData; + + // ã‹LˆÈŠO(Ž‹’®•s‰Â) + default : + m_dwLastError = BCEC_ECMREFUSED; + return NULL; + } +} + +const bool CBcasCard::StoreEcmData(const BYTE *pEcmData, const DWORD dwEcmSize) +{ + bool bUpdate = false; + + // ECMƒf[ƒ^”äŠr + if(m_EcmStatus.dwLastEcmSize != dwEcmSize){ + // ƒTƒCƒY‚ª•Ï‰»‚µ‚½ + bUpdate = true; + } + else{ + // ƒTƒCƒY‚ª“¯‚¶ê‡‚̓f[ƒ^‚ðƒ`ƒFƒbƒN‚·‚é + for(DWORD dwPos = 0UL ; dwPos < dwEcmSize ; dwPos++){ + if(pEcmData[dwPos] != m_EcmStatus.LastEcmData[dwPos]){ + // ƒf[ƒ^‚ª•sˆê’v + bUpdate = true; + break; + } + } + } + + // ECMƒf[ƒ^‚ð•Û‘¶‚·‚é + if(bUpdate){ + m_EcmStatus.dwLastEcmSize = dwEcmSize; + memcpy(m_EcmStatus.LastEcmData, pEcmData, dwEcmSize); + } + + return bUpdate; +} diff --git a/b25-remote/BCasCard.h b/b25-remote/BCasCard.h new file mode 100755 index 0000000..e793203 --- /dev/null +++ b/b25-remote/BCasCard.h @@ -0,0 +1,85 @@ +// BcasCard.h: CBcasCard ƒNƒ‰ƒX‚̃Cƒ“ƒ^[ƒtƒFƒCƒX +// +////////////////////////////////////////////////////////////////////// + +#pragma once + + +#include +#include +#include +#include + + +using std::vector; +using std::wstring; +using std::string; + + +// ƒGƒ‰[ƒR[ƒh +#define BCEC_NOERROR 0x00000000UL // ƒGƒ‰[‚È‚µ +#define BCEC_INTERNALERROR 0x00000001UL // “à•”ƒGƒ‰[ +#define BCEC_NOTESTABLISHED 0x00000002UL // ƒRƒ“ƒeƒLƒXƒgŠm—§Ž¸”s +#define BCEC_NOCARDREADERS 0x00000003UL // ƒJ[ƒhƒŠ[ƒ_‚ª‚È‚¢ +#define BCEC_ALREADYOPEN 0x00000004UL // Šù‚ɃI[ƒvƒ“Ï‚Ý +#define BCEC_CARDOPENERROR 0x00000005UL // ƒJ[ƒhƒI[ƒvƒ“Ž¸”s +#define BCEC_CARDNOTOPEN 0x00000006UL // ƒJ[ƒh–¢ƒI[ƒvƒ“ +#define BCEC_TRANSMITERROR 0x00000007UL // ’ʐMƒGƒ‰[ +#define BCEC_BADARGUMENT 0x00000008UL // ˆø”‚ª•s³ +#define BCEC_ECMREFUSED 0x00000009UL // ECMŽó•t‹‘”Û + + +class CBcasCard +{ +public: + CBcasCard(); + ~CBcasCard(); + + const DWORD GetCardReaderNum(void) const; + LPCTSTR GetCardReaderName(const DWORD dwIndex = 0UL) const; + + const bool OpenCard(LPCTSTR lpszReader = NULL); + void CloseCard(void); + + const BYTE * GetBcasCardID(void); + const BYTE * GetInitialCbc(void); + const BYTE * GetSystemKey(void); + const BYTE * GetKsFromEcm(const BYTE *pEcmData, const DWORD dwEcmSize); + + const DWORD GetLastError(void) const; + +protected: + const bool EnumCardReader(void); + const bool TransmitCommand(const BYTE *pSendData, const DWORD dwSendSize, BYTE *pRecvData, const DWORD dwMaxRecv, DWORD *pdwRecvSize = NULL); + const bool InitialSetting(void); + + SCARDCONTEXT m_ScardContext; + SCARDHANDLE m_hBcasCard; + + bool m_bIsEstablish; + +#ifdef _UNICODE + vector m_CardReaderArray; +#else + vector m_CardReaderArray; +#endif + + struct TAG_BCASCARDINFO + { + BYTE BcasCardID[6]; // Card ID + BYTE SystemKey[32]; // Descrambling system key + BYTE InitialCbc[8]; // Descrambler CBC initial value + } m_BcasCardInfo; + + struct TAG_ECMSTATUS + { + DWORD dwLastEcmSize; // ÅŒã‚É–â‚¢‡‚킹‚Ì‚ ‚Á‚½ECMƒTƒCƒY + BYTE LastEcmData[256]; // ÅŒã‚É–â‚¢‡‚킹‚Ì‚ ‚Á‚½ECMƒf[ƒ^ + BYTE KsData[16]; // Ks Odd + Even + } m_EcmStatus; + + DWORD m_dwLastError; + +private: + const bool StoreEcmData(const BYTE *pEcmData, const DWORD dwEcmSize); +}; diff --git a/b25-remote/CasClient.cpp b/b25-remote/CasClient.cpp new file mode 100755 index 0000000..4b6c6fb --- /dev/null +++ b/b25-remote/CasClient.cpp @@ -0,0 +1,97 @@ +// CasClient.cpp: CCasClient ƒNƒ‰ƒX‚̃Cƒ“ƒvƒŠƒƒ“ƒe[ƒVƒ‡ƒ“ +// +////////////////////////////////////////////////////////////////////// + +#include +#include "W2L.h" +#include "CasClient.h" + + +#define TCP_TIMEOUT 1000UL // 1•b + + +CCasClient::CCasClient(ICasClientHandler *pEventHandler, CSmartSock *pSocket) + : CBcasCard() + , m_pSocket(pSocket) + , m_pEventHandler(pEventHandler) + , m_hClientThread(NULL) +{ + // ƒNƒ‰ƒCƒAƒ“ƒgƒXƒŒƒbƒh‹N“® + pthread_create(&m_hClientThread, NULL, CCasClient::ClientThreadRaw, (LPVOID)this); + if(!m_hClientThread){ + printf("ClientThread failed\n"); + delete this; + } + printf("ClientThread started\n"); +} + +CCasClient::~CCasClient(void) +{ + delete m_pSocket; + if (m_hClientThread) pthread_join(m_hClientThread, NULL); +} + +void CCasClient::CloseClient(void) +{ + // ƒNƒ‰ƒCƒAƒ“ƒg‚ðØ’f‚·‚é + m_pSocket->Close(); +} + +void CCasClient::ClientThread(void) +{ + // ƒJ[ƒhƒŠ[ƒ_‚ðŠJ‚­ + if(!OpenCard())return; + + // ŽóMƒoƒbƒtƒ@ + BYTE byDataLen; + BYTE RecvBuf[256]; + DWORD dwRecvSize; + + // ƒƒbƒZ[ƒWŽóMƒ‹[ƒv + while(1){ + // ƒwƒbƒ_‚ðŽóM + if(!m_pSocket->Recv(&byDataLen, 1UL, TCP_TIMEOUT)){ + if(m_pSocket->GetLastError() == CSmartSock::EC_TIMEOUT)continue; + else break; + } + + // ƒf[ƒ^‚ðŽóM + if(!m_pSocket->Recv(RecvBuf, byDataLen, TCP_TIMEOUT))break; + + // ƒJ[ƒh‘—ŽóM + if(!TransmitCommand(RecvBuf, byDataLen, &RecvBuf[1], sizeof(RecvBuf) - 1UL, &dwRecvSize))dwRecvSize = 0UL; + + // ƒf[ƒ^‚𑗐M + RecvBuf[0] = (BYTE)dwRecvSize; + if(!m_pSocket->Send(RecvBuf, dwRecvSize + 1UL, TCP_TIMEOUT))break; + } + + printf("ClientThread exited\n"); + // ƒJ[ƒhƒŠ[ƒ_‚ð•Â‚¶‚é + CloseCard(); +} + +void* CCasClient::ClientThreadRaw(LPVOID pParam) +{ + // ƒNƒ‰ƒCƒAƒ“ƒgƒXƒŒƒbƒh + CCasClient *pThis = static_cast(pParam); + + // Ú‘±ƒCƒxƒ“ƒg’Ê’m + pThis->SendEvent(EID_CONNECTED); + + // ƒƒ“ƒoŠÖ”‚ɃŠƒ_ƒCƒŒƒNƒg‚·‚é + pThis->ClientThread(); + + // Ø’fƒCƒxƒ“ƒg’Ê’m + pThis->SendEvent(EID_DISCONNECTED); + + delete pThis; + + return 0UL; +} + +void CCasClient::SendEvent(const DWORD dwEventID, PVOID pParam) +{ + // ƒnƒ“ƒhƒ‰‚ɃCƒxƒ“ƒg‚ð’Ê’m‚·‚é + if(m_pEventHandler)m_pEventHandler->OnCasClientEvent(this, dwEventID, pParam); +} diff --git a/b25-remote/CasClient.h b/b25-remote/CasClient.h new file mode 100755 index 0000000..ecd1c56 --- /dev/null +++ b/b25-remote/CasClient.h @@ -0,0 +1,41 @@ +// CasClient.h: CCasClient ƒNƒ‰ƒX‚̃Cƒ“ƒ^[ƒtƒFƒCƒX +// +////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "W2L.h" +#include "BCasCard.h" +#include "SmartSock.h" + + +class CCasClient : private CBcasCard +{ +public: + class ICasClientHandler + { + public: + virtual void OnCasClientEvent(CCasClient *pClient, const DWORD dwEventID, PVOID pParam) = 0; + }; + + enum + { + EID_CONNECTED, // ƒNƒ‰ƒCƒAƒ“ƒgÚ‘± + EID_DISCONNECTED // ƒNƒ‰ƒCƒAƒ“ƒgØ’f + }; + + CCasClient(ICasClientHandler *pEventHandler, CSmartSock *pSocket); + ~CCasClient(void); + + void CloseClient(void); + +protected: + void ClientThread(void); + static void* ClientThreadRaw(LPVOID pParam); + + void SendEvent(const DWORD dwEventID, PVOID pParam = NULL); + + CSmartSock *m_pSocket; + ICasClientHandler *m_pEventHandler; + pthread_t m_hClientThread; +}; diff --git a/b25-remote/CasProxy.cpp b/b25-remote/CasProxy.cpp new file mode 100755 index 0000000..dbf0330 --- /dev/null +++ b/b25-remote/CasProxy.cpp @@ -0,0 +1,87 @@ +// CasProxy.cpp: CCasProxy ƒNƒ‰ƒX‚̃Cƒ“ƒvƒŠƒƒ“ƒe[ƒVƒ‡ƒ“ +// +////////////////////////////////////////////////////////////////////// + + +#include "CasProxy.h" +#include + +#define TCP_TIMEOUT 1000UL // 1•b + + +DWORD CCasProxy::dwErrorDelayTime = 0UL; + + +CCasProxy::CCasProxy(void) +{ + +} + +CCasProxy::~CCasProxy(void) +{ + // ƒT[ƒo‚©‚çØ’f + m_Socket.Close(); +} + +const BOOL CCasProxy::Connect(void) +{ +/* + // ƒGƒ‰[”­¶Žž‚̃K[ƒhƒCƒ“ƒ^[ƒoƒ‹ + if(dwErrorDelayTime){ + if((::GetTickCount() - dwErrorDelayTime) < TCP_TIMEOUT)return FALSE; + else dwErrorDelayTime = 0UL; + } +*/ + // ƒT[ƒo‚ɐڑ± + char* env = getenv("B25_SERVER_IP"); + LPCTSTR lpszHost; + WORD wPort; + if (env) { + lpszHost = env; + } + else { + lpszHost = "127.0.0.1"; + } + env = getenv("B25_SERVER_PORT"); + if (env) { + wPort = atoi(env); + } + else { + wPort = 6900; + } + + if(m_Socket.Connect(lpszHost, wPort, TCP_TIMEOUT)){ + return TRUE; + } + else{ + //dwErrorDelayTime = ::GetTickCount(); + return FALSE; + } +} + +const DWORD CCasProxy::TransmitCommand(const BYTE *pSendData, const DWORD dwSendSize, BYTE *pRecvData) +{ + // ‘—Mƒf[ƒ^€”õ + BYTE SendBuf[256]; + SendBuf[0] = (BYTE)dwSendSize; + memcpy(&SendBuf[1], pSendData, dwSendSize); + + try{ + // ƒŠƒNƒGƒXƒg‘—M + if(!m_Socket.Send(SendBuf, dwSendSize + 1UL, TCP_TIMEOUT))throw (const DWORD)__LINE__; + + // ƒŒƒXƒ|ƒ“ƒXƒwƒbƒ_ŽóM + if(!m_Socket.Recv(SendBuf, 1UL, TCP_TIMEOUT))throw (const DWORD)__LINE__; + + // ƒŒƒXƒ|ƒ“ƒXƒf[ƒ^ŽóM + if(!m_Socket.Recv(pRecvData, SendBuf[0], TCP_TIMEOUT))throw (const DWORD)__LINE__; + } + catch(const DWORD dwLine){ + // ’ʐMƒGƒ‰[”­¶ + m_Socket.Close(); + return 0UL; + } + + return SendBuf[0]; +} + diff --git a/b25-remote/CasProxy.h b/b25-remote/CasProxy.h new file mode 100755 index 0000000..2b0d6e4 --- /dev/null +++ b/b25-remote/CasProxy.h @@ -0,0 +1,36 @@ +// CasProxy.h: CCasProxy ƒNƒ‰ƒX‚̃Cƒ“ƒ^[ƒtƒFƒCƒX +// +////////////////////////////////////////////////////////////////////// + + +#pragma once + + +#include "SmartSock.h" +#include + +class CCasProxy +{ +public: + enum + { + CPEI_ENTERPROCESS, // ƒvƒƒZƒXŠJŽn’Ê’m + CPEI_EXITPROCESS, // ƒvƒƒZƒXI—¹’Ê’m + CPEI_GETSERVERIP, // ƒT[ƒoIPŽæ“¾ + CPEI_GETSERVERPORT, // ƒT[ƒoƒ|[ƒgŽæ“¾ + CPEI_CONNECTSUCCESS, // Ú‘±Š®—¹ + CPEI_CONNECTFAILED, // Ú‘±Ž¸”s + CPEI_DISCONNECTED // Ú‘±Ø’f + }; + + CCasProxy(void); + ~CCasProxy(void); + + const BOOL Connect(void); + const DWORD TransmitCommand(const BYTE *pSendData, const DWORD dwSendSize, BYTE *pRecvData); + +protected: + CSmartSock m_Socket; + + static DWORD dwErrorDelayTime; +}; diff --git a/b25-remote/CasServer.cpp b/b25-remote/CasServer.cpp new file mode 100755 index 0000000..4c733b8 --- /dev/null +++ b/b25-remote/CasServer.cpp @@ -0,0 +1,110 @@ +// CasServer.cpp: CCasServer ƒNƒ‰ƒX‚̃Cƒ“ƒvƒŠƒƒ“ƒe[ƒVƒ‡ƒ“ +// +////////////////////////////////////////////////////////////////////// + + +#include "CasServer.h" +#include "BCasCard.h" + +#define FALSE 0 +#define TRUE 1 + +CCasServer::CCasServer(ICasServerHandler *pEventHandler) + : m_pEventHandler(pEventHandler) + , m_hServerThread(NULL) +{ + +} + +CCasServer::~CCasServer(void) +{ + CloseServer(); +} + +const BOOL CCasServer::OpenServer(const WORD wServerPort) +{ + // ƒJ[ƒhƒŠ[ƒ_‘¶Ýƒ`ƒFƒbƒN + CBcasCard BCasCard; + if(!BCasCard.OpenCard())return FALSE; + + // ƒT[ƒoƒ\ƒPƒbƒgƒI[ƒvƒ“ + if(!m_pSocket.Listen(wServerPort))return FALSE; + + // ƒT[ƒoƒXƒŒƒbƒh‹N“® + pthread_create(&m_hServerThread, NULL, CCasServer::ServerThreadRaw, (LPVOID)this); + if(!m_hServerThread){ + m_pSocket.Close(); + return FALSE; + } + + return TRUE; +} + +void CCasServer::CloseServer(void) +{ + // ƒT[ƒoƒ\ƒPƒbƒgƒNƒ[ƒY + m_pSocket.Close(); + + // ƒXƒŒƒbƒhƒnƒ“ƒhƒ‹ŠJ•ú + if(m_hServerThread){ + pthread_join(m_hServerThread, NULL); + m_hServerThread = NULL; + } + + // ‘SƒNƒ‰ƒCƒAƒ“ƒgØ’f + m_Lock.Lock(); + + for(ClientList::iterator It = m_ClientList.begin() ; It != m_ClientList.end() ; It++){ + It->first->CloseClient(); + } + + m_Lock.Unlock(); + + // ‘SƒNƒ‰ƒCƒAƒ“ƒg‚̏I—¹‚ð‘Ò‚Â + while(m_ClientList.size()) sleep(1UL); +} + +const DWORD CCasServer::GetClientNum(void) const +{ + // Ú‘±’†‚̃Nƒ‰ƒCƒAƒ“ƒg”‚ð•Ô‚· + return m_ClientList.size(); +} + +void CCasServer::OnCasClientEvent(CCasClient *pClient, const DWORD dwEventID, PVOID pParam) +{ + CBlockLock AutoLock(&m_Lock); + + // ƒNƒ‰ƒCƒAƒ“ƒgƒCƒxƒ“ƒg + switch(dwEventID){ + case CCasClient::EID_CONNECTED : + // ƒŠƒXƒg‚ɒljÁ + m_ClientList[pClient] = pClient; + if (m_pEventHandler) m_pEventHandler->OnCasServerEvent(this, CSEI_CONNECTED); + break; + + case CCasClient::EID_DISCONNECTED : + // ƒŠƒXƒg‚©‚çíœ + m_ClientList.erase(pClient); + if (m_pEventHandler) m_pEventHandler->OnCasServerEvent(this, CSEI_DISCONNECTED); + break; + } +} + +void CCasServer::ServerThread(void) +{ + // ƒAƒNƒZƒvƒgƒ‹[ƒv + CSmartSock *pNewSocket; + + while(pNewSocket = m_pSocket.Accept()){ + // ƒNƒ‰ƒCƒAƒ“ƒgƒCƒ“ƒXƒ^ƒ“ƒX¶¬ + new CCasClient(this, pNewSocket); + } +} + +void* CCasServer::ServerThreadRaw(LPVOID pParam) +{ + // ƒT[ƒoƒXƒŒƒbƒh + static_cast(pParam)->ServerThread(); + + return 0UL; +} diff --git a/b25-remote/CasServer.h b/b25-remote/CasServer.h new file mode 100755 index 0000000..35d7732 --- /dev/null +++ b/b25-remote/CasServer.h @@ -0,0 +1,56 @@ +// CasServer.h: CCasServer ƒNƒ‰ƒX‚̃Cƒ“ƒ^[ƒtƒFƒCƒX +// +////////////////////////////////////////////////////////////////////// + +#pragma once + + +#include +#include "CasClient.h" +#include "TsUtilClass.h" +#include "SmartSock.h" + + +using std::map; + + +class CCasServer : protected CCasClient::ICasClientHandler +{ +public: + class ICasServerHandler + { + public: + virtual void OnCasServerEvent(CCasServer *pCasServer, const WORD wEventID) = 0; + }; + + enum + { + CSEI_CONNECTED, // ƒNƒ‰ƒCƒAƒ“ƒgÚ‘± + CSEI_DISCONNECTED, // ƒNƒ‰ƒCƒAƒ“ƒgØ’f + }; + + CCasServer(void); + CCasServer(ICasServerHandler *pEventHandler); + ~CCasServer(void); + + const BOOL OpenServer(const WORD wServerPort); + void CloseServer(void); + + const DWORD GetClientNum(void) const; + +protected: + virtual void OnCasClientEvent(CCasClient *pClient, const DWORD dwEventID, PVOID pParam); + + void ServerThread(void); + static void* ServerThreadRaw(LPVOID pParam); + + ICasServerHandler *m_pEventHandler; + + CSmartSock m_pSocket; + pthread_t m_hServerThread; + + typedef map ClientList; + ClientList m_ClientList; + + CCriticalLock m_Lock; +}; diff --git a/b25-remote/Makefile b/b25-remote/Makefile new file mode 100755 index 0000000..ed4d823 --- /dev/null +++ b/b25-remote/Makefile @@ -0,0 +1,45 @@ +PREFIX = /usr/local +TARGET_SERVER = b25-server +TARGET_CLIENT = b25-client.so +OBJ_SERVER = BCasCard.o CasClient.o CasServer.o SmartSock.o TsUtilClass.o b25-server.o +HEADER_SERVER = BCasCard.h CasClient.h CasServer.h SmartSock.h TsUtilClass.h +OBJ_CLIENT = CasProxy.o SmartSock.o b25-client.o +HEADER_CLIENT = CasProxy.h SmartSock.h +PCSC_CFLAGS = `pkg-config libpcsclite --cflags` +PCSC_LDLIBS = `pkg-config libpcsclite --libs` + +CC = g++ +CFLAGS = -fPIC -O2 -Wall -g ${PCSC_CFLAGS} +CFLAGS_FOR_LIB = -fPIC -shared +LDFLAGS = -pthread ${PCSC_LDLIBS} +LIBS = + +.cpp.o: + ${CC} $(CFLAGS) -c $< + +.c.o: + ${CC} $(CFLAGS) -c $< + +all: ${TARGET_SERVER} ${TARGET_CLIENT} + +${TARGET_SERVER}: ${OBJ_SERVER} + ${CC} ${CFLAGS} ${OBJ_SERVER} -o $@ ${LDFLAGS} ${LIBS} + +${TARGET_CLIENT}: ${OBJ_CLIENT} + ${CC} ${CFLAGS_FOR_LIB} ${OBJ_CLIENT} -o $@ ${LDFLAGS} ${LIBS} + +${OBJ_SERVER}: ${HEADER_SERVER} + +${OBJ_CLIENT}: ${HEADER_CLIENT} + +install: ${TARGET_SERVER} ${TARGET_CLIENT} + install -m755 ${TARGET_SERVER} ${PREFIX}/bin + install -m755 ${TARGET_CLIENT} ${PREFIX}/lib + +uninstall: + rm ${PREFIX}/bin/${TARGET_SERVER} + rm ${PREFIX}/lib/${TARGET_CLIENT} + +clean: + rm -f core ${TARGET_SERVER} *.o *.so + diff --git a/b25-remote/Readme.txt b/b25-remote/Readme.txt new file mode 100755 index 0000000..0f591d0 --- /dev/null +++ b/b25-remote/Readme.txt @@ -0,0 +1,56 @@ + +- b25-remote Ver.0.0.1 - + + +1.概要 +  ・スマートカードリーダをLANを経由で共有するためのシステムです。 +  ・BonCasLink互換プロトコルを使用します。 + +  +2.注意事項 +  ・一般的にスマートカードには個人を特定可能な情報が含まれている可能性があります。 +  ・本ソフトウェアは通信の暗号化を行わないためこのリスクを十分に考えた上でご使用ください。 +  ・本ソフトウェアの警告を無視しLAN以外のネットワークにおいて使用した結果発生したいかなる +   損害も作者に責任を求めないこととします。 + + +3.ライセンスについて +  ・本パッケージに含まれる全てのソースコード、バイナリについて著作権は一切主張しません。 +  ・オリジナルのまま又は改変し、各自のソフトウェアに自由に添付、組み込むことができます。 +  ・但しGPLに従うことを要求しますのでこれらを行う場合はソースコードの開示が必須となります。 +  ・このとき本ソフトウェアの著作権表示を行うかどうかは任意です。 + +  ・通信プロトコルの変更及び追加を含むソースコードの改変は一切許可できません。 +  ・上記を禁止するいかなる根拠または拘束力も作者にはありませんがこれに反して、 +   作成した改変物を配布する場合は下記を要求します。 +  ・ソフトウェアの名称を「b25-remote」以外に変更すること。 +  ・「Rec10」の著作権表示を一切行わないこと。 +  ・ソースコードの流用元の表示を一切行わないこと。 +  ・このソースコードは拡張ツール中の人(nakanohito@2sen.dip.jp)が作成されたBonCasLink(公式サイト:http://2sen.dip.jp/friio/)のソースコードを流用しています。 + +  ・ビルドに必要な環境 +   - pcsc-lite-devel ※Fedoraç³» +   - libpcsclite-dev ※Debianç³» + + +4.使用方法 +  ①スマートカードリーダが接続されたPCで「b25-server」を起動します。 + +  ②LANに参加している他のPCでPCSCを利用するアプリケーションを起動します。 + +  ③このとき環境変数を以下のように設定します。 +   LD_PRELOAD = {b25-client.soの絶対パス} +   B25_REMOTE_IP = {サーバーのアドレス(DNS可)} +   B25_REMOTE_PORT = {サーバーの使用ポート(デフォルト:6900)} + +   ※ファイヤウォールやフィルタリングを使用している場合は共有に使用するポートを開放してください。 + + +6.サポート、連絡先 +   連絡先  : Rec10 +   公式サイト: http://sourceforge.jp/projects/rec10/ + + +8.更新履歴 + Ver.0.0.1 ・初回リリース + diff --git a/b25-remote/SmartSock.cpp b/b25-remote/SmartSock.cpp new file mode 100755 index 0000000..cbf802c --- /dev/null +++ b/b25-remote/SmartSock.cpp @@ -0,0 +1,572 @@ +// SmartSock.cpp: CSmartSock ƒNƒ‰ƒX‚̃Cƒ“ƒvƒŠƒƒ“ƒe[ƒVƒ‡ƒ“ +// +////////////////////////////////////////////////////////////////////// + +#include "SmartSock.h" +#include +#include + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + +//#pragma warning(disable: 4101) // warning C4101: "ƒ[ƒJƒ‹•Ï”‚Í 1 “x‚àŽg‚í‚ê‚Ä‚¢‚Ü‚¹‚ñB" +//#pragma warning(disable: 4996) // warning C4996: "This function or variable may be unsafe. Consider using _wsplitpath_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details" + + +//#pragma comment(lib, "WS2_32") + + +////////////////////////////////////////////////////////////////////// +// ƒ}ƒNƒ’è‹` +////////////////////////////////////////////////////////////////////// + +#define CHECK_FREESOCK(R) if(m_Socket != INVALID_SOCKET){m_dwLastError = EC_SOCKINVALID; return (R);} +#define CHECK_TCPSOCK(R) if((m_Socket == INVALID_SOCKET) || (m_bSockType != SOCKTYPE_TCP)){m_dwLastError = EC_SOCKINVALID; return (R);} +#define CHECK_UDPSOCK(R) if((m_Socket == INVALID_SOCKET) || (m_bSockType != SOCKTYPE_UDP)){m_dwLastError = EC_SOCKINVALID; return (R);} + + +////////////////////////////////////////////////////////////////////// +// \’z/Á–Å +////////////////////////////////////////////////////////////////////// + +DWORD CSmartSock::dwInstanceNum = 0UL; + +CSmartSock::CSmartSock() + : m_Socket(INVALID_SOCKET) + , m_bSockType(SOCKTYPE_NON) + , m_dwLastError(EC_NOERROR) +{ + // WinSock2‰Šú‰» + if(!(dwInstanceNum++))InitWinSock2(); +} + +CSmartSock::~CSmartSock() +{ + Close(); + + // WinSock2ŠJ•ú + if(!(--dwInstanceNum))FreeWinSock2(); +} + +const BOOL CSmartSock::Connect(LPCTSTR lpszHost, const WORD wPort, const DWORD dwTimeOut) +{ + CHECK_FREESOCK(FALSE); + + if(!lpszHost){ + m_dwLastError = EC_PARAMINVALID; + return FALSE; + } + + // ƒAƒhƒŒƒX–¼‚©‚çIPƒAƒhƒŒƒXŽæ“¾ + const DWORD dwIP = HostToIP(lpszHost); + + if(dwIP == INADDR_NONE){ + m_dwLastError = EC_SOCKERROR; + return FALSE; + } + + return Connect(dwIP, wPort, dwTimeOut); +} + +const BOOL CSmartSock::Connect(const DWORD dwIP, const WORD wPort, const DWORD dwTimeOut) +{ + CHECK_FREESOCK(FALSE); + + // ƒ\ƒPƒbƒgì¬ + if((m_Socket = ::socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET){ + m_dwLastError = EC_SOCKERROR; + return FALSE; + } + + // ƒAƒhƒŒƒXÝ’è + SOCKADDR_IN SockAddr; + SockAddr.sin_family = AF_INET; + SockAddr.sin_port = htons(wPort); + SockAddr.sin_addr.s_addr = htonl(dwIP); + + // “¯ŠúƒRƒlƒNƒg + if(!dwTimeOut){ + if(::connect(m_Socket, (PSOCKADDR)&SockAddr, sizeof(sockaddr))){ + Close(); + m_dwLastError = EC_SOCKERROR; + return FALSE; + } + + m_dwLastError = EC_NOERROR; + return TRUE; + } + + // ”ñ“¯ŠúƒRƒlƒNƒg + u_long nArg; + fd_set FdSet; + struct timeval TimeVal; + TimeVal.tv_sec = 10UL; + TimeVal.tv_usec = 0UL; + nArg = fcntl(m_Socket, F_GETFL, 0); + FD_ZERO(&FdSet); + FD_SET(m_Socket, &FdSet); + + try{ + // ”ñ“¯Šú‚ɐ؂è‘Ö‚¦ + if(::fcntl(m_Socket, F_SETFL, nArg | O_NONBLOCK) == SOCKET_ERROR)throw (const DWORD)__LINE__; + + // ƒRƒlƒNƒg + if(::connect(m_Socket, (PSOCKADDR)&SockAddr, sizeof(sockaddr)) != SOCKET_ERROR)throw (const DWORD)__LINE__; + + if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINPROGRESS)throw (const DWORD)__LINE__; + + // Ú‘±Š®—¹‘Ò‚¿ + if(!::select(32, NULL, &FdSet, NULL, &TimeVal))throw (const DWORD)__LINE__; + + // ƒ^ƒCƒ€ƒAƒEƒg”»’è + if(!FD_ISSET(m_Socket, &FdSet)){ + Close(); + m_dwLastError = EC_TIMEOUT; + return FALSE; + } + + // “¯Šú‚ɐ؂è‘Ö‚¦ + if(::fcntl(m_Socket, F_SETFL, nArg) == SOCKET_ERROR)throw (const DWORD)__LINE__; + } + catch(const DWORD dwLine){ + // ƒGƒ‰[”­¶ + Close(); + m_dwLastError = EC_SOCKERROR; + return FALSE; + } + + m_bSockType = SOCKTYPE_TCP; + m_dwLastError = EC_NOERROR; + + return TRUE; +} + +const BOOL CSmartSock::Listen(const WORD wPort) +{ + CHECK_FREESOCK(FALSE); + + // ƒ\ƒPƒbƒgì¬ + if((m_Socket = ::socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET){ + m_dwLastError = EC_SOCKERROR; + return FALSE; + } + + // ƒAƒhƒŒƒXÝ’è + SOCKADDR_IN SockAddr; + SockAddr.sin_family = AF_INET; + SockAddr.sin_port = htons(wPort); + SockAddr.sin_addr.s_addr = INADDR_ANY; + + try{ + // uƒAƒhƒŒƒXŽg—p’†vƒGƒ‰[‚ð‰ñ”ð + int on = 1; + setsockopt(m_Socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + + // ƒoƒCƒ“ƒh + if(::bind(m_Socket, (PSOCKADDR)&SockAddr, sizeof(SockAddr)) == SOCKET_ERROR)throw (const DWORD)__LINE__; + + // Ú‘±Žó‚¯“ü‚ê + if(::listen(m_Socket, 5) == SOCKET_ERROR)throw (const DWORD)__LINE__; + } + catch(const DWORD dwLine){ + // ƒGƒ‰[”­¶ + Close(); + m_dwLastError = EC_SOCKERROR; + return FALSE; + } + + m_bSockType = SOCKTYPE_TCP; + m_dwLastError = EC_NOERROR; + + return TRUE; +} + +CSmartSock * CSmartSock::Accept(void) +{ + CHECK_TCPSOCK(FALSE); + + SOCKADDR_IN AddrIn; + memset(&AddrIn, 0, sizeof(AddrIn)); + socklen_t iAddrLen = sizeof(AddrIn); + + // ƒRƒlƒNƒgŽó‚¯“ü‚ê + SOCKET SockIn = ::accept(m_Socket, (sockaddr *)&AddrIn, &iAddrLen); + + if(SockIn == INVALID_SOCKET){ + Close(); + m_dwLastError = EC_SOCKERROR; + return NULL; + } + + CSmartSock *pNewSock = new CSmartSock; + pNewSock->m_Socket = SockIn; + pNewSock->m_bSockType = SOCKTYPE_TCP; + + m_dwLastError = EC_NOERROR; + + return pNewSock; +} + +const BOOL CSmartSock::Send(const BYTE *pBuff, const DWORD dwLen, const DWORD dwTimeOut) +{ + CHECK_TCPSOCK(FALSE); + + if(!pBuff || !dwLen){ + m_dwLastError = EC_PARAMINVALID; + return FALSE; + } + + // Žw’èƒTƒCƒY‘—M + DWORD dwRef = 0UL, dwSend = 0UL; + + do{ + dwRef = SendOnce(pBuff + dwSend, dwLen - dwSend, dwTimeOut); + if(!dwRef) return FALSE; + } + while((dwSend += dwRef) < dwLen); + + return TRUE; +} + +const BOOL CSmartSock::Recv(BYTE *pBuff, const DWORD dwLen, const DWORD dwTimeOut) +{ + CHECK_TCPSOCK(FALSE); + + if(!pBuff || !dwLen){ + m_dwLastError = EC_PARAMINVALID; + return FALSE; + } + + // Žw’èƒTƒCƒYŽóM + DWORD dwRef = 0UL, dwRecv = 0UL; + + do{ + if(!(dwRef = RecvOnce(pBuff + dwRecv, dwLen - dwRecv, dwTimeOut)))return FALSE; + } + while((dwRecv += dwRef) < dwLen); + + return TRUE; +} + +const DWORD CSmartSock::SendOnce(const BYTE *pBuff, const DWORD dwMaxLen, const DWORD dwTimeOut) +{ + CHECK_TCPSOCK(0UL); + + if(!pBuff || !dwMaxLen){ + m_dwLastError = EC_PARAMINVALID; + return FALSE; + } + + // ƒ^ƒCƒ€ƒAƒEƒgÝ’è + struct timeval stTimeOut; + + stTimeOut.tv_sec = 10UL; + stTimeOut.tv_usec = 0UL; + if(::setsockopt(m_Socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&stTimeOut, sizeof(struct timeval))){ + Close(); + m_dwLastError = EC_SOCKERROR; + return 0UL; + } + + // ‘—M + const int iRef = ::send(m_Socket, (const char *)pBuff, dwMaxLen, 0); + + if((iRef == SOCKET_ERROR) || !iRef){ + if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS){ + m_dwLastError = EC_TIMEOUT; + return 0UL; + } + else{ + Close(); + m_dwLastError = EC_SOCKERROR; + return 0UL; + } + } + + m_dwLastError = EC_NOERROR; + + return (DWORD)iRef; +} + +const DWORD CSmartSock::RecvOnce(BYTE *pBuff, const DWORD dwMaxLen, const DWORD dwTimeOut) +{ + CHECK_TCPSOCK(0UL); + + if(!pBuff || !dwMaxLen){ + m_dwLastError = EC_PARAMINVALID; + return FALSE; + } + + // ƒ^ƒCƒ€ƒAƒEƒg’lÝ’è + struct timeval stTimeOut; + + stTimeOut.tv_sec = 10UL; + stTimeOut.tv_usec = 0UL; + if(::setsockopt(m_Socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&stTimeOut, sizeof(struct timeval))){ + Close(); + m_dwLastError = EC_SOCKERROR; + return 0UL; + } + + // ŽóM + int iRef = ::recv(m_Socket, (char *)pBuff, dwMaxLen, 0); + + if((iRef == SOCKET_ERROR) || !iRef){ + if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS){ + m_dwLastError = EC_TIMEOUT; + return 0UL; + } + else{ + Close(); + m_dwLastError = EC_SOCKERROR; + return 0UL; + } + } + + m_dwLastError = EC_NOERROR; + + return (DWORD)iRef; +} + +const BOOL CSmartSock::GetLocalAddr(DWORD *pdwIP, WORD *pwPort) +{ + CHECK_TCPSOCK(FALSE); + + struct sockaddr_in LocalAddr; + socklen_t AddrLen = sizeof(LocalAddr); + + // ƒ[ƒJƒ‹ƒAƒhƒŒƒXŽæ“¾ + if(::getsockname(m_Socket, (struct sockaddr *)&LocalAddr, &AddrLen) == SOCKET_ERROR){ + m_dwLastError = EC_SOCKERROR; + return FALSE; + } + + if(pdwIP)*pdwIP = htonl(LocalAddr.sin_addr.s_addr); + if(pwPort)*pwPort = ntohs(LocalAddr.sin_port); + + m_dwLastError = EC_NOERROR; + + return TRUE; +} + +const BOOL CSmartSock::GetPeerAddr(DWORD *pIP, WORD *pPort) +{ + CHECK_TCPSOCK(FALSE); + + struct sockaddr_in PeerAddr; + socklen_t AddrLen = sizeof(PeerAddr); + + // ƒsƒAƒAƒhƒŒƒXŽæ“¾ + if(::getpeername(m_Socket, (struct sockaddr *)&PeerAddr, &AddrLen) == SOCKET_ERROR){ + m_dwLastError = EC_SOCKERROR; + return FALSE; + } + + if(pIP)*pIP = htonl(PeerAddr.sin_addr.s_addr); + if(pPort)*pPort = ntohs(PeerAddr.sin_port); + + m_dwLastError = EC_NOERROR; + + return TRUE; +} + +const BOOL CSmartSock::Bind() +{ + CHECK_FREESOCK(FALSE); + + // UDPƒ\ƒPƒbƒgì¬ + if((m_Socket = ::socket(PF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET){ + m_dwLastError = EC_SOCKERROR; + return FALSE; + } + + // ƒAƒhƒŒƒXÝ’è + SOCKADDR_IN SockAddr; + SockAddr.sin_family = AF_INET; + SockAddr.sin_port = 0U; + SockAddr.sin_addr.s_addr = INADDR_ANY; + + // ƒoƒCƒ“ƒh + if(::bind(m_Socket, (struct sockaddr *)&SockAddr, sizeof(SockAddr)) == SOCKET_ERROR){ + Close(); + m_dwLastError = EC_SOCKERROR; + return FALSE; + } + + m_dwLastError = EC_NOERROR; + m_bSockType = SOCKTYPE_UDP; + + return TRUE; +} + +const DWORD CSmartSock::SendTo(const DWORD dwIP, const WORD wPort, const BYTE *pBuff, const DWORD dwLen) +{ + CHECK_UDPSOCK(0UL); + + if(!pBuff || !dwLen){ + m_dwLastError = EC_PARAMINVALID; + return 0UL; + } + + // ƒAƒhƒŒƒXÝ’è + SOCKADDR_IN SockAddr; + SockAddr.sin_family = AF_INET; + SockAddr.sin_port = htons(wPort); + SockAddr.sin_addr.s_addr = htonl(dwIP); + + // ‘—M + int iSend = sendto(m_Socket, (const char *)pBuff, dwLen, 0, (struct sockaddr *)&SockAddr, sizeof(SockAddr)); + + if(iSend == SOCKET_ERROR){ + m_dwLastError = EC_SOCKERROR; + return 0UL; + } + + m_dwLastError = EC_NOERROR; + + return (DWORD)iSend; +} + +const DWORD CSmartSock::SendTo(LPCTSTR lpszHost, const WORD wPort, const BYTE *pBuff, const DWORD dwLen) +{ + CHECK_UDPSOCK(0UL); + + if(!lpszHost || !pBuff || !dwLen){ + m_dwLastError = EC_PARAMINVALID; + return 0UL; + } + + // ƒAƒhƒŒƒX–¼‚©‚çIPƒAƒhƒŒƒXŽæ“¾ + const DWORD dwIP = HostToIP(lpszHost); + + if(dwIP == INADDR_NONE){ + m_dwLastError = EC_SOCKERROR; + return 0UL; + } + + return SendTo(dwIP, wPort, pBuff, dwLen); +} + +const DWORD CSmartSock::RecvFrom(BYTE *pBuff, const DWORD dwLen, DWORD *pdwIP, WORD *pwPort) +{ + CHECK_UDPSOCK(0UL); + + if(!pBuff || !dwLen){ + m_dwLastError = EC_PARAMINVALID; + return 0UL; + } + + // ƒAƒhƒŒƒXÝ’è + socklen_t iSockSize = sizeof(SOCKADDR_IN); + SOCKADDR_IN SockAddr; + SockAddr.sin_family = AF_INET; + SockAddr.sin_port = 0U; + SockAddr.sin_addr.s_addr = 0UL; + + // ŽóM + const int iRecv = ::recvfrom(m_Socket, (char *)pBuff, dwLen, 0, (struct sockaddr *)&SockAddr, &iSockSize); + + if(iRecv == SOCKET_ERROR){ + m_dwLastError = EC_SOCKERROR; + return 0UL; + } + + if(pdwIP)*pdwIP = SockAddr.sin_addr.s_addr; + if(pwPort)*pwPort = ntohs(SockAddr.sin_port); + + m_dwLastError = EC_NOERROR; + + return (DWORD)iRecv; +} + +const BOOL CSmartSock::Close() +{ + // ƒ\ƒPƒbƒgƒNƒ[ƒY + if(m_Socket != INVALID_SOCKET){ + if(m_bSockType == SOCKTYPE_TCP){ + char byData; + ::shutdown(m_Socket, SD_BOTH); + while(::recv(m_Socket, &byData, 1, 0) == 1); + } + + ::close(m_Socket); + m_Socket = INVALID_SOCKET; + } + + m_bSockType = SOCKTYPE_NON; + m_dwLastError = EC_NOERROR; + + return TRUE; +} + +const DWORD CSmartSock::HostToIP(LPCTSTR lpszHost) +{ +#ifdef _UNICODE + char szHost[1024] = {"\0"}; + ::wcstombs(szHost, lpszHost, sizeof(szHost) - 1); +#else + LPCSTR szHost = lpszHost; +#endif + + // ƒzƒXƒg–¼‚©‚çIPƒAƒhƒŒƒXŽæ“¾ + const DWORD dwIP = ::inet_addr(szHost); + + if(dwIP == INADDR_NONE){ + struct hostent *pHost = ::gethostbyname(szHost); + if(!pHost){ + return INADDR_NONE; + } + else return *((DWORD *)pHost->h_addr_list[0]); + } + else return htonl(dwIP); +} + +const DWORD CSmartSock::IPToHost(LPTSTR lpszHost, const DWORD dwIP) +{ + if(!lpszHost)return FALSE; + + // IPƒAƒhƒŒƒX‚©‚çƒzƒXƒg–¼Žæ“¾ + const DWORD dwNetIP = htonl(dwIP); + struct hostent *pHost = ::gethostbyaddr((const char *)&dwNetIP, sizeof(dwNetIP), AF_INET); + if(!pHost)return FALSE; + +#ifdef _UNICODE + ::mbstowcs(lpszHost, pHost->h_name, ::lstrlenA(pHost->h_name)); +#else + ::strcpy(lpszHost, pHost->h_name); +#endif + + return ::strlen(lpszHost); +} + +const DWORD CSmartSock::GetLastError() const +{ + // ÅŒã‚É”­¶‚µ‚½ƒGƒ‰[‚ð•Ô‚· + return m_dwLastError; +} + +const BOOL CSmartSock::InitWinSock2(void) +{ +#ifdef _UNICODE + ::setlocale(LC_ALL, "japanese"); +#endif +/* + WSADATA WsaData; + + // WinSock2‰Šú‰» + if(::WSAStartup(MAKEWORD(2, 2), &WsaData))return FALSE; + + if((LOBYTE(WsaData.wVersion) != 2U) || (HIBYTE(WsaData.wVersion) != 2U))return FALSE; +*/ + return TRUE; +} + +const BOOL CSmartSock::FreeWinSock2(void) +{ +/* + // WinSock2ŠJ•ú + return (::WSACleanup())? TRUE : FALSE; +*/ + return TRUE; +} diff --git a/b25-remote/SmartSock.h b/b25-remote/SmartSock.h new file mode 100755 index 0000000..d735339 --- /dev/null +++ b/b25-remote/SmartSock.h @@ -0,0 +1,79 @@ +// SmartSock.h: CSmartSock ƒNƒ‰ƒX‚̃Cƒ“ƒ^[ƒtƒFƒCƒX +// +////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "W2L.h" +#include +#include +#include +#include +#include +#include + +#define BOOL bool +#define LPTSTR char* +#define LPCTSTR const char* +#define LPCSTR const char* +#define BYTE unsigned char +#define WORD unsigned short +#define DWORD unsigned long +#define SOCKET int + +// WinSock2ƒ^ƒCƒ€ƒAƒEƒg‘Ήžƒ‰ƒbƒp[ƒNƒ‰ƒX http://2sen.dip.jp/friio/ +class CSmartSock +{ +public: + enum // LastErrorƒR[ƒh + { + EC_NOERROR, // ³íI—¹ + EC_SOCKERROR, // ƒ\ƒPƒbƒgƒGƒ‰[ + EC_TIMEOUT, // ƒ^ƒCƒ€ƒAƒEƒg + EC_SOCKINVALID, // ƒ\ƒPƒbƒg‚ª–³Œø + EC_PARAMINVALID // ƒpƒ‰ƒ[ƒ^‚ª–³Œø + }; + + CSmartSock(); + virtual ~CSmartSock(); + +// TCPƒ\ƒPƒbƒg + const BOOL Connect(LPCTSTR lpszHost, const WORD wPort, const DWORD dwTimeOut = 0UL); + const BOOL Connect(const DWORD dwIP, const WORD wPort, const DWORD dwTimeOut = 0UL); + + const BOOL Listen(const WORD wPort); + CSmartSock * Accept(void); + + const BOOL Send(const BYTE *pBuff, const DWORD dwLen, const DWORD dwTimeOut = 0UL); + const BOOL Recv(BYTE *pBuff, const DWORD dwLen, const DWORD dwTimeOut = 0UL); + const DWORD SendOnce(const BYTE *pBuff, const DWORD dwMaxLen, const DWORD dwTimeOut = 0UL); + const DWORD RecvOnce(BYTE *pBuff, const DWORD dwMaxLen, const DWORD dwTimeOut = 0UL); + + const BOOL GetLocalAddr(DWORD *pdwIP, WORD *pwPort = NULL); + const BOOL GetPeerAddr(DWORD *pdwIP, WORD *pwPort = NULL); + +// UDPƒ\ƒPƒbƒg + const BOOL Bind(void); + + const DWORD SendTo(const DWORD dwIP, const WORD wPort, const BYTE *pBuff, const DWORD dwLen); + const DWORD SendTo(LPCTSTR lpszHost, const WORD wPort, const BYTE *pBuff, const DWORD dwLen); + const DWORD RecvFrom(BYTE *pBuff, const DWORD dwLen, DWORD *pdwIP = NULL, WORD *pwPort = NULL); + + const BOOL Close(void); + + static const DWORD HostToIP(LPCTSTR lpszHost); + static const DWORD IPToHost(LPTSTR lpszHost, const DWORD dwIP); + + const DWORD GetLastError(void) const; + +protected: + static const BOOL InitWinSock2(void); + static const BOOL FreeWinSock2(void); + + enum {SOCKTYPE_NON, SOCKTYPE_TCP, SOCKTYPE_UDP}; + + int m_Socket; // ƒ\ƒPƒbƒgƒnƒ“ƒhƒ‹ + BYTE m_bSockType; // ƒ\ƒPƒbƒgƒ^ƒCƒv + DWORD m_dwLastError; // ÅIƒGƒ‰[ƒR[ƒh + static DWORD dwInstanceNum; // ƒCƒ“ƒXƒ^ƒ“ƒX‚̐” +}; diff --git a/b25-remote/TsUtilClass.cpp b/b25-remote/TsUtilClass.cpp new file mode 100755 index 0000000..ec4c298 --- /dev/null +++ b/b25-remote/TsUtilClass.cpp @@ -0,0 +1,88 @@ +// TsUtilClass.cpp: TSƒ†[ƒeƒBƒŠƒeƒB[ƒNƒ‰ƒX‚̃Cƒ“ƒvƒŠƒƒ“ƒe[ƒVƒ‡ƒ“ +// +////////////////////////////////////////////////////////////////////// + +#include "TsUtilClass.h" + + +////////////////////////////////////////////////////////////////////// +// CDynamicReferenceable ƒNƒ‰ƒX‚̍\’z/Á–Å +////////////////////////////////////////////////////////////////////// + +CDynamicReferenceable::CDynamicReferenceable() + : m_dwRefCount(0UL) +{ + +} + +CDynamicReferenceable::~CDynamicReferenceable() +{ + +} + +void CDynamicReferenceable::AddRef(void) +{ + // ŽQÆƒJƒEƒ“ƒgƒCƒ“ƒNƒŠƒƒ“ƒg + m_dwRefCount++; +} + +void CDynamicReferenceable::ReleaseRef(void) +{ + // ŽQÆƒJƒEƒ“ƒgƒfƒNƒŠƒƒ“ƒg + if(m_dwRefCount){ + // ƒCƒ“ƒXƒ^ƒ“ƒXŠJ•ú + if(!(--m_dwRefCount))delete this; + } +#ifdef _DEBUG + else{ + ::DebugBreak(); + } +#endif +} + + +////////////////////////////////////////////////////////////////////// +// CCriticalLock ƒNƒ‰ƒX‚̍\’z/Á–Å +////////////////////////////////////////////////////////////////////// + +CCriticalLock::CCriticalLock() +{ + // ƒNƒŠƒeƒBƒJƒ‹ƒZƒNƒVƒ‡ƒ“‰Šú‰» + pthread_mutex_init(&m_CriticalSection, NULL); +} + +CCriticalLock::~CCriticalLock() +{ + // ƒNƒŠƒeƒBƒJƒ‹ƒZƒNƒVƒ‡ƒ“íœ + pthread_mutex_destroy(&m_CriticalSection); +} + +void CCriticalLock::Lock(void) +{ + // ƒNƒŠƒeƒBƒJƒ‹ƒZƒNƒVƒ‡ƒ“Žæ“¾ + pthread_mutex_lock(&m_CriticalSection); +} + +void CCriticalLock::Unlock(void) +{ + // ƒNƒŠƒeƒBƒJƒ‹ƒZƒNƒVƒ‡ƒ“ŠJ•ú + pthread_mutex_unlock(&m_CriticalSection); +} + + +////////////////////////////////////////////////////////////////////// +// CBlockLock ƒNƒ‰ƒX‚̍\’z/Á–Å +////////////////////////////////////////////////////////////////////// + +CBlockLock::CBlockLock(CCriticalLock *pCriticalLock) + : m_pCriticalLock(pCriticalLock) +{ + // ƒƒbƒNŽæ“¾ + m_pCriticalLock->Lock(); +} + +CBlockLock::~CBlockLock() +{ + // ƒƒbƒNŠJ•ú + m_pCriticalLock->Unlock(); +} diff --git a/b25-remote/TsUtilClass.h b/b25-remote/TsUtilClass.h new file mode 100755 index 0000000..ebae86b --- /dev/null +++ b/b25-remote/TsUtilClass.h @@ -0,0 +1,61 @@ +// TsUtilClass.h: TSƒ†[ƒeƒBƒŠƒeƒB[ƒNƒ‰ƒX‚̃Cƒ“ƒ^[ƒtƒFƒCƒX +// +////////////////////////////////////////////////////////////////////// + +#pragma once +#include "W2L.h" +#include + +#define DWORD unsigned long + +///////////////////////////////////////////////////////////////////////////// +// ƒ_ƒCƒiƒ~ƒbƒNƒŠƒtƒ@ƒŒƒ“ƒXŠÇ—ƒx[ƒXƒNƒ‰ƒX +///////////////////////////////////////////////////////////////////////////// + +class CDynamicReferenceable +{ +public: + CDynamicReferenceable(); + virtual ~CDynamicReferenceable(); + + void AddRef(void); + void ReleaseRef(void); + +private: + DWORD m_dwRefCount; +}; + + +///////////////////////////////////////////////////////////////////////////// +// ƒNƒŠƒeƒBƒJƒ‹ƒZƒNƒVƒ‡ƒ“ƒ‰ƒbƒp[ƒNƒ‰ƒX +///////////////////////////////////////////////////////////////////////////// + +class CCriticalLock +{ +public: + CCriticalLock(); + virtual ~CCriticalLock(); + + void Lock(void); + void Unlock(void); + +private: + pthread_mutex_t m_CriticalSection; +}; + + +///////////////////////////////////////////////////////////////////////////// +// ƒuƒƒbƒNƒXƒR[ƒvƒƒbƒNƒNƒ‰ƒX +///////////////////////////////////////////////////////////////////////////// + +class CBlockLock +{ +public: + CBlockLock(CCriticalLock *pCriticalLock); + virtual ~CBlockLock(); + +private: + CCriticalLock *m_pCriticalLock; +}; + + diff --git a/b25-remote/W2L.h b/b25-remote/W2L.h new file mode 100755 index 0000000..678823d --- /dev/null +++ b/b25-remote/W2L.h @@ -0,0 +1,14 @@ +#include + +#define TCHAR char +#define PVOID void* +#define HANDLE void* +#define TRUE 1 +#define FALSE 0 +#define INVALID_SOCKET (-1) +#define SOCKET_ERROR (-1) +#define SOCKADDR_IN struct sockaddr_in +#define SOCKADDR struct sockaddr +#define PSOCKADDR SOCKADDR* +#define SD_BOTH SHUT_RDWR + diff --git a/b25-remote/b25-client.cpp b/b25-remote/b25-client.cpp new file mode 100755 index 0000000..f108e00 --- /dev/null +++ b/b25-remote/b25-client.cpp @@ -0,0 +1,87 @@ +// MllMain.cpp : DLL ƒAƒvƒŠƒP[ƒVƒ‡ƒ“‚̃Gƒ“ƒgƒŠ ƒ|ƒCƒ“ƒg‚ð’è‹`‚µ‚Ü‚·B +// +#include +#include +#include "CasProxy.h" +#include "W2L.h" +#ifndef SCARD_AUTOALLOCATE + #define SCARD_AUTOALLOCATE (DWORD)(-1) /**< see SCardFreeMemory() */ +#endif + +////////////////////////////////////////////////////////////////////// +// WinSCardƒtƒbƒN +////////////////////////////////////////////////////////////////////// +LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol) +{ + // ƒvƒƒLƒVƒCƒ“ƒXƒ^ƒ“ƒX¶¬ + CCasProxy *pCasProxy = new CCasProxy(); + + // ƒT[ƒo‚ɐڑ± + if(!pCasProxy->Connect()){ + delete pCasProxy; + *phCard = NULL; + return SCARD_E_READER_UNAVAILABLE; + } + + // ƒnƒ“ƒhƒ‹‚É–„‚ߍž‚Þ + *phCard = reinterpret_cast(pCasProxy); + if(pdwActiveProtocol)*pdwActiveProtocol = SCARD_PROTOCOL_T1; + + return SCARD_S_SUCCESS; +} + +LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition) +{ + // ƒT[ƒo‚©‚çØ’f + CCasProxy *pCasProxy = reinterpret_cast(hCard); + if(pCasProxy)delete pCasProxy; + + return SCARD_S_SUCCESS; +} + +LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext) +{ + return SCARD_S_SUCCESS; +} + +LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem) +{ + return SCARD_S_SUCCESS; +} + +LONG SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups, LPSTR mszReaders, LPDWORD pcchReaders) +{ + const char szReaderName[] = "BonCasLink Proxy Card Reader\0"; + + if(pcchReaders){ + if((*pcchReaders == SCARD_AUTOALLOCATE) && mszReaders){ + *((LPCSTR *)mszReaders) = szReaderName; + return SCARD_S_SUCCESS; + } + else{ + *pcchReaders = sizeof(szReaderName); + } + } + + if(mszReaders) memcpy(mszReaders, szReaderName, sizeof(szReaderName)); + + return SCARD_S_SUCCESS; +} + +LONG SCardTransmit(SCARDHANDLE hCard, LPCSCARD_IO_REQUEST pioSendPci, LPCBYTE pbSendBuffer, DWORD cbSendLength, LPSCARD_IO_REQUEST pioRecvPci, LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength) +{ + // ƒT[ƒo‚ɃŠƒNƒGƒXƒg‘—ŽóM + CCasProxy *pCasProxy = reinterpret_cast(hCard); + if(!pCasProxy)return SCARD_E_READER_UNAVAILABLE; + + DWORD dwRecvLen = pCasProxy->TransmitCommand(pbSendBuffer, cbSendLength, pbRecvBuffer); + if(pcbRecvLength)*pcbRecvLength = dwRecvLen; + + return (dwRecvLen)? SCARD_S_SUCCESS : SCARD_E_TIMEOUT; +} + +LONG SCardReleaseContext(SCARDCONTEXT hContext) +{ + return SCARD_S_SUCCESS; +} + diff --git a/b25-remote/b25-server.cpp b/b25-remote/b25-server.cpp new file mode 100755 index 0000000..674af68 --- /dev/null +++ b/b25-remote/b25-server.cpp @@ -0,0 +1,14 @@ +#include +#include "CasServer.h" + +CCasServer m_CasServer(NULL); +int m_dwServerPort = 6900UL; + +int main() { + if(!m_CasServer.OpenServer(m_dwServerPort)){ + printf("サーバの起動に失敗しました。\nTCPポートまたはカードリーダをオープンできません。\n"); + return TRUE; + } + getchar(); +} +