Commit 0d4bf35a by 刘帅

1. 首次提交;

2. 只有支付和设置门店信息接口
parents
*.pro.user
/bin/*
!/bin/*.dll
File added
#ifndef __ZHCRYPT_H__
#define __ZHCRYPT_H__
extern "C" {
int ZH_getKey(char * keyBuf, char * ctrlBuf, void * pvInfo);
char * ZH_encodeSendData(char * codeBuf, char * buf, int length, int * eLength, char * keyBuf, int keyLengh);
char * ZH_decodeRecvData(char * codeBuf, char * buf, int length, int * dLength, char * keyBuf, int keyLength, int * pcurKeyPos);
int ZH_encodeBkData(char * pOrgData, int dataLen, char * keyBuf, int keyLen, char * pCodeBuf);
void ZH_decodeBkData(char * pCodeBuf, char * pOrgBuf,int totalLen);
int ZH_checkChkValue(char * pJsonData, int dLength, int tbckValue);
}
#endif
File added
#include <QCoreApplication>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
return a.exec();
}
#include "qfmclient.h"
#include "fmcrypt.h"
#include <windows.h>
#include <QByteArray>
#include <QJsonDocument>
#include <QJsonParseError>
#include <QJsonObject>
#include <QFile>
#include <Qdebug>
#include <QJsonArray>
#ifdef WIN32
#include <direct.h>
#include <windows.h>
#include <winsock.h>
#include <DbgHelp.h>
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "fmcrypt.lib")
#pragma comment(lib, "DbgHelp.lib")
#else
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <unistd.h>
#endif
unsigned int QFmClient::s_reqCount = 0;
QFmClient::QFmClient(QObject *parent) : QThread(parent)
{
_endflag = false;
}
bool QFmClient::Init(QString proxy_IP, unsigned short proxy_port, unsigned short listen_prot, unsigned short long_timeout, unsigned short short_timeout)
{
if(proxy_IP.size() == 0 ||
proxy_port <= 0 ||
listen_prot <= 0 ||
short_timeout <= 0 ||
long_timeout <= 0
)
return false;
if(proxy_IP.toStdString().size() > 30)
return false;
strcpy(_proxyIP, proxy_IP.toStdString().c_str());
_proxyIP[proxy_IP.toStdString().size()] = 0;
this->_proxyPort = proxy_port;
this->_clientPort = listen_prot;
this->_shortTimeOut = short_timeout;
this->_longTimeOut = long_timeout;
#ifdef WIN32
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2,2);
err = WSAStartup(wVersionRequested, &wsaData);
#endif
memset(_codeKey, 0, MAX_CODE_KEY);
memset(_codeBuf, 0, MAX_BUF_LEN);
memset(_recvbuf, 0, MAX_BUF_LEN);
memset(_tempbuf, 0, MAX_BUF_LEN);
memset(_sendbuf, 0, MAX_BUF_LEN);
_codeFlag = 1;
return true;
}
int QFmClient::RecvSockData(int sock, char *buffer, int length)
{
#ifdef WIN32
return ::recv(sock, buffer, length, 0);
#else
return ::read(sock, buffer, length);
#endif
}
void QFmClient::WaitAndSleep(int elapse)
{
#ifdef WIN32
Sleep(elapse);
#else
sleep(elapse/1000);
#endif
}
bool QFmClient::WaitForConnectReqFromPos()
{
int sin_size = sizeof(struct sockaddr_in);
struct sockaddr_in c_add;
if(0 < _acceptedSock)
{
RecvSockData(_acceptedSock, _recvbuf, (MAX_BUF_LEN - 1));
CloseSocket(&_acceptedSock);
}
_acceptedSock = accept(_listenSock, (struct sockaddr *)(&c_add), &sin_size);
if(-1 == _acceptedSock)
{
qDebug() << "accept socket fail!\r\n";
return false;
}
qDebug() << "accept ok, ZF Client get connection from POS!\r\n";
return true;
}
int QFmClient::CheckIsCompleteJsonData(int * count, char * data)
{
int loop = 0;
while(data[loop])
{
if ('{' == data[loop])
{
(*count) ++;
}
if ('}' == data[loop])
{
(*count) --;
}
loop++;
if (0 == (*count))
{
break;
}
}
return loop;
}
#ifdef WIN32
int QFmClient::GBKToUTF8(unsigned char * lpGBKStr,int gbkLen, unsigned char * lpUTF8Str,int nUTF8StrLen)
{
wchar_t * lpUnicodeStr = NULL;
int nRetLen = 0;
if(!lpGBKStr) //如果GBK字符串为NULL则出错退出
return 0;
nRetLen = MultiByteToWideChar(CP_ACP,0,(char *)lpGBKStr,gbkLen,NULL,NULL); //获取转换到Unicode编码后所需要的字符空间长度
//lpUnicodeStr = new WCHAR[nRetLen + 1]; //为Unicode字符串空间
lpUnicodeStr = (WCHAR*)malloc( sizeof(WCHAR)*(nRetLen + 1));
memset(lpUnicodeStr, sizeof(WCHAR)*(nRetLen + 1), 0);
nRetLen = MultiByteToWideChar(CP_ACP,0,(char *)lpGBKStr,gbkLen,lpUnicodeStr,nRetLen); //转换到Unicode编码
if(!nRetLen) //转换失败则出错退出
return 0;
nRetLen = WideCharToMultiByte(CP_UTF8,0,lpUnicodeStr,nRetLen,NULL,0,NULL,NULL); //获取转换到UTF8编码后所需要的字符空间长度
if(!lpUTF8Str) //输出缓冲区为空则返回转换后需要的空间大小
{
if(lpUnicodeStr)
free(lpUnicodeStr);
return nRetLen;
}
if(nUTF8StrLen < nRetLen) //如果输出缓冲区长度不够则退出
{
if(lpUnicodeStr)
free(lpUnicodeStr);
return 0;
}
nRetLen = WideCharToMultiByte(CP_UTF8,0,lpUnicodeStr,nRetLen,(char *)lpUTF8Str,nUTF8StrLen,NULL,NULL); //转换到UTF8编码
if(lpUnicodeStr)
free(lpUnicodeStr);
return nRetLen;
}
int QFmClient::UTF8ToGBK(unsigned char * lpUTF8Str,unsigned char * lpGBKStr,int nGBKStrLen)
{
wchar_t * lpUnicodeStr = NULL;
int nRetLen = 0;
if(!lpUTF8Str) //如果UTF8字符串为NULL则出错退出
return 0;
nRetLen = MultiByteToWideChar(CP_UTF8,0,(char *)lpUTF8Str,-1,NULL,NULL); //获取转换到Unicode编码后所需要的字符空间长度
//lpUnicodeStr = new WCHAR[nRetLen + 1]; //为Unicode字符串空间
lpUnicodeStr = (WCHAR*)malloc( sizeof(WCHAR)*(nRetLen + 1));
nRetLen = MultiByteToWideChar(CP_UTF8,0,(char *)lpUTF8Str,-1,lpUnicodeStr,nRetLen); //转换到Unicode编码
if(!nRetLen) //转换失败则出错退出
return 0;
nRetLen = WideCharToMultiByte(CP_ACP,0,lpUnicodeStr,-1,NULL,NULL,NULL,NULL); //获取转换到GBK编码后所需要的字符空间长度
if(!lpGBKStr) //输出缓冲区为空则返回转换后需要的空间大小
{
if(lpUnicodeStr)
free(lpUnicodeStr);
return nRetLen;
}
if(nGBKStrLen < nRetLen) //如果输出缓冲区长度不够则退出
{
if(lpUnicodeStr)
free(lpUnicodeStr);
return 0;
}
nRetLen = WideCharToMultiByte(CP_ACP,0,lpUnicodeStr,-1,(char *)lpGBKStr,nRetLen,NULL,NULL); //转换到GBK编码
if(lpUnicodeStr)
free(lpUnicodeStr);
return nRetLen;
}
#endif
char * QFmClient::DecodeRecvData(char * buf, int length, int * dLength)
{
int curKeyPos = _curKeyPos;
char * rltPtr = ZH_decodeRecvData(_codeBuf, buf, length, dLength, (char *)_codeKey, _keyLength, &curKeyPos);
_curKeyPos = (char)curKeyPos;
return rltPtr;
}
int QFmClient::WaitAndReadDataFromPos(int type, int flag)
{
qDebug() << "wait and receive data from POS...\r\n";
_rcvLength = 0;
int recbytes, finLen, curPos = 0, prosLen = 0, checkCount = 0;
int i = 0;
do
{
char * precvBuf;
if (0 >= (recbytes = RecvSockData(_acceptedSock, _tempbuf, (MAX_BUF_LEN - 1))))
{
#ifdef WIN32
qDebug() << "recv() return : " << recbytes << ";error : " << WSAGetLastError() << ";\r\n";
#endif
qDebug() << "read data from socket " << _acceptedSock << " fail!\r\n";
return -1;
}
#ifdef WIN32
qDebug() << "received data " << _acceptedSock << " : " << _tempbuf;
if(type)
{
memcpy( _sendbuf, _tempbuf, recbytes );
//recbytes = GBKToUTF8( (unsigned char *)_sendbuf, recbytes, (unsigned char *)_tempbuf, MAX_BUF_LEN - 100);
}
#endif
precvBuf = _tempbuf;
_tempbuf[recbytes] = '\0';
if(1 == flag)
precvBuf = DecodeRecvData(_tempbuf, recbytes, &recbytes);
qDebug() << "received data from socket " << _acceptedSock << " : " << precvBuf;
while(0 < recbytes)
{
finLen = CheckIsCompleteJsonData(&checkCount, precvBuf + prosLen);
if (((0 == checkCount) && ( '}' != precvBuf[ prosLen + finLen - 1])) || ((MAX_BUF_LEN - 1) < curPos + finLen))
{
qDebug() << "checkCount out!\r\n";
return -1;
}
memcpy(_recvbuf + curPos, precvBuf + prosLen, finLen);
curPos += finLen;
prosLen += finLen;
if (0 == checkCount)
{
_recvbuf[curPos] = '\0';
_rcvLength = curPos;
curPos = 0;
checkCount = 0;
qDebug() << "checkCount = 0";
goto finishRecv;
}
recbytes -= finLen;
}
prosLen = 0;
}while(1);
finishRecv:
return 0;
}
void QFmClient::AddReqCount(QJsonObject& object)
{
s_reqCount %= MAX_REQ_COUNT;
s_reqCount ++;
object["clientReqCount"] = (int)s_reqCount;
}
int QFmClient::CheckReqFromPos(char * pJsonData, int dLength, int chkValue)
{
return ZH_checkChkValue(pJsonData, dLength, chkValue);
}
int QFmClient::ProcessPosReqData(QJsonObject& object)
{
int flag = 0;
QByteArray recvdata(_recvbuf);
QJsonParseError json_error;
QJsonDocument doc = QJsonDocument::fromJson(recvdata, &json_error);
if(json_error.error != QJsonParseError::NoError || !doc.isObject())
{
qDebug() << "error request json data!\r\n " << json_error.error;
return -1;
}
//! TODO: Json 转换
object = doc.object();
int fm_cmd = 10031;
if(object.contains("fm_cmd"))
{
fm_cmd = object.take("fm_cmd").toInt();
switch(fm_cmd)
{
case 10031:
if(object.find("store_id") != object.end())
{
GetStoreInfo(object);
}
qDebug()<<"convert json format";
ConvertJsonFormat(object);
break;
case 1000:
GetStoreInfo(object);
sendResponseToPos(1000);
return 1;
break;
default:
break;
}
}
do
{
_sockTimeOut = _longTimeOut;
if(object.contains("reqtype"))
{
if(object["reqtype"] != 72)
{
_sockTimeOut = _shortTimeOut;
}
if(object["reqtype"] == 72 || object["reqtype"] == 71)
{
flag = 1;
}
}else
{
qDebug() << "not found reqtype";
flag = -1;
break;
}
// if(!object.contains("checkValue") || !object["checkValue"].isDouble())
// {
// qDebug() << "checkValue failed!\r\n";
// flag = -1;
// break;
// }
AddReqCount(object);
}while(0);
return flag;
}
//convert pos requst json format from
// 非码支付插件 API 对接说明.pdf
//to
// 非码支付FMClient商户版_20170921.pdf
bool QFmClient::ConvertJsonFormat(QJsonObject &object)
{
QJsonObject newObject;
QJsonArray transactionArray;
QJsonObject transactionObject;
newObject.insert("ver",2);
newObject.insert("reqtype",72);
newObject.insert("partnerId",store_info.partner_id);
newObject.insert("store_id",store_info.store_id);
newObject.insert("station_id",store_info.pos_id);
newObject.insert("operator_id",store_info.operator_id);
newObject.insert("business_date",store_info.business_date);
if(object.contains("trans_id"))
{
QString trans_id = object.take("trans_id").toString();
newObject.insert("trans_id",trans_id);
}
if(object.contains("order_amount"))
{
int order_amount = object.take("order_amount").toInt();
transactionObject.insert("amount",order_amount);
}
if(object.contains("undis_amount"))
{
int undis_amount = object.take("undis_amount").toInt();
transactionObject.insert("undis_amount",undis_amount);
}
if(object.contains("barcode"))
{
QString barcode = object.take("barcode").toString();
transactionObject.insert("code",barcode);
}
if(object.contains("products"))
{
QJsonValue products = object.take("products");
if(products.isArray())
transactionObject.insert("products",products);
}
transactionArray.append(transactionObject);
newObject.insert("transactions",transactionArray);
object = newObject;
qDebug()<<object;
return true;
}
//获取门店信息
void QFmClient::GetStoreInfo(QJsonObject &object)
{
if(object.contains("partner_id"))
{
QString partner_id = object.take("partner_id").toString();
store_info.partner_id = partner_id;
}
if(object.contains("store_id"))
{
QString store_id = object.take("store_id").toString();
store_info.store_id = store_id;
}
if(object.contains("pos_id"))
{
QString pos_id = object.take("pos_id").toString();
store_info.pos_id = pos_id;
}
if(object.contains("business_date"))
{
QString business_date = object.take("business_date").toString();
store_info.business_date = business_date;
}
if(object.contains("operator_id"))
{
QString operator_id = object.take("operator_id").toString();
store_info.operator_id = operator_id;
}
}
//nflag: 1000 response for set store infomation
void QFmClient::sendResponseToPos(int nflag)
{
if(nflag == 1000)
{
QJsonObject responseObj;
responseObj.insert("status_code",100);
responseObj.insert("msg",QString("set store infomation success"));
QString str = QJsonDocument(responseObj).toJson();
char* pResponse = new char[str.size()+1];
strcpy(pResponse,str.toStdString().c_str());
int nRt = SendSocketData(_acceptedSock,pResponse,str.size(),0);
delete []pResponse;
if(nRt == 0)
qDebug()<<"send response for set store info failed!";
}
}
int QFmClient::Try2ConnectZhProxy()
{
struct sockaddr_in proxyAddr;
int rlt = 0;
unsigned long ul = 1;
unsigned long sendsize = 32;
BOOL bNoDelay = TRUE;
fd_set fs;
struct timeval cntTO = {_shortTimeOut,0};
#ifdef WIN32
int sockTimeOut = _sockTimeOut * 1000;
#else
struct timeval sockTimeOut={_sockTimeOut,0};
#endif
_zhProxySock = socket(AF_INET, SOCK_STREAM, 0);
memset(&proxyAddr, 0, sizeof(struct sockaddr_in));
proxyAddr.sin_addr.s_addr =inet_addr(_proxyIP);
proxyAddr.sin_family = AF_INET;
proxyAddr.sin_port = htons(_proxyPort);
#ifdef WIN32
ioctlsocket(_zhProxySock, FIONBIO, &ul);
#else
ioctl(_zhProxySock, FIONBIO, &ul);
#endif
::connect(_zhProxySock, (struct sockaddr *)&proxyAddr, sizeof(struct sockaddr));
FD_ZERO(&fs);
FD_SET(_zhProxySock, &fs);
rlt = select(_zhProxySock + 1, 0, &fs, 0, &cntTO);
if (0 >= rlt)
{
#ifdef WIN32
closesocket(_zhProxySock);
#else
closesocket(_zhProxySock);
#endif
return -1;
}
ul = 0;
#ifdef WIN32
ioctlsocket(_zhProxySock, FIONBIO, &ul);
#else
ioctl(_zhProxySock, FIONBIO, &ul);
#endif
#ifdef WIN32
//setsockopt(g_clientInfo.zhProxySock, SOL_SOCKET, SO_SNDBUF, (char*)&sendsize,sizeof(int));
setsockopt(_zhProxySock, IPPROTO_TCP, TCP_NODELAY, (char FAR *)&bNoDelay, sizeof(BOOL));
setsockopt(_zhProxySock, SOL_SOCKET, SO_SNDTIMEO, (char *)&sockTimeOut, sizeof(int));
setsockopt(_zhProxySock, SOL_SOCKET, SO_RCVTIMEO, (char *)&sockTimeOut, sizeof(int));
#else
setsockopt(_zhProxySock, SOL_SOCKET, SO_RCVTIMEO, (char *)&sockTimeOut, sizeof(struct timeval));
setsockopt(_zhProxySock, SOL_SOCKET, SO_SNDTIMEO, (char *)&sockTimeOut, sizeof(struct timeval));
#endif
return 0;
}
void QFmClient::GetKey()
{
_curKeyPos = 0;
_keyLength = ZH_getKey((char *)_codeKey, _tempbuf, 0);
}
char * QFmClient::EncodeSendData(char * buf, int length, int * eLength)
{
return ZH_encodeSendData(_codeBuf, buf, length, eLength, (char *)_codeKey, _keyLength);
}
int QFmClient::SendSocketData(int sock, char * buf, int length, int flag)
{
char * psendBuf = buf;
int tmplen = 0, tmp = _fmMSS, tmpsize = _fmMSS, len = 0;
if (1 == flag)
{
psendBuf = EncodeSendData(buf, length, &length);
}
#ifdef WIN32
if(length <= tmp)
{
return send(sock, psendBuf, length, 0);
}else
{
while(tmplen < length)
{
if(tmplen + tmp > length)
{
tmpsize = length - tmplen;
tmplen = length;
}else
{
tmpsize = tmp;
tmplen += tmp;
}
send(sock, psendBuf + len, tmpsize, 0);
len = tmplen;
}
}
return tmplen;
#else
return write(sock, psendBuf, length);
#endif
}
int QFmClient::SendCtrlInfo2Proxy()
{
int sendRlt, offset = 1;
_tempbuf[0] = _codeFlag;
if (_codeFlag)
{
GetKey();
offset += (1 + _tempbuf[1]);
}
_tempbuf[offset] = _sockTimeOut;
sendRlt = SendSocketData(_zhProxySock, _tempbuf, MAX_CTRL_INFO_LEN, 0);
if (sendRlt != MAX_CTRL_INFO_LEN)
{
#ifdef WIN32
qDebug() << "recv() return : " << sendRlt << ";error : " << WSAGetLastError() << ";\r\n";
#endif
return -1;
}
return 0;
}
int QFmClient::RecvAndCheckDataFromSock(int sock, int flag, int type) //type = 0 proxy re, = 1 pos re
{
int recbytes, finLen, curPos = 0, prosLen = 0, checkCount = 0;
int i = 0;
do
{
char * precvBuf;
if (0 >= (recbytes = RecvSockData(sock, _tempbuf, (MAX_BUF_LEN - 1))))
{
#ifdef WIN32
qDebug() << "recv() return : " << recbytes << ";error : " << WSAGetLastError() << ";\r\n";
#endif
qDebug() << "read data from socket "<< sock <<" fail!\r\n";
return -1;
}
#ifdef WIN32
if(type)
{
memcpy( _sendbuf, _tempbuf, recbytes );
recbytes = GBKToUTF8( (unsigned char *)_sendbuf, recbytes, (unsigned char *)_tempbuf, MAX_BUF_LEN - 100);
}
#endif
precvBuf = _tempbuf;
_tempbuf[recbytes] = '\0';
if (1 == flag)
{
precvBuf = DecodeRecvData(_tempbuf, recbytes, &recbytes);
}
qDebug() << "received data from socket " << sock << " : " << precvBuf;
while(0 < recbytes)
{
finLen = CheckIsCompleteJsonData(&checkCount, precvBuf + prosLen);
if (((0 == checkCount) && ( '}' != precvBuf[ prosLen + finLen - 1])) || ((MAX_BUF_LEN - 1) < curPos + finLen))
{
qDebug() << "checkCount out!\r\n";
return -1;
}
memcpy(_recvbuf + curPos, precvBuf + prosLen, finLen);
curPos += finLen;
prosLen += finLen;
if (0 == checkCount)
{//a complete json data received
_recvbuf[curPos] = '\0';
_rcvLength = curPos;
curPos = 0;
checkCount = 0;
qDebug() << "checkCount = 0";
goto finishRecv;
}
recbytes -= finLen;
}
prosLen = 0;
}while(1);
finishRecv:
return 0;
}
int QFmClient::SendData2ZhProxyAndWaitRspData()
{
int rlt, length;
length = strlen(_sendbuf);
rlt = SendSocketData(_zhProxySock, _sendbuf, length, _codeFlag);
if (rlt != length)
{
#ifdef WIN32
qDebug() << "recv() return : " << rlt << ";error : " << WSAGetLastError() << ";\r\n";
#endif
qDebug() << "send data to socket failed!\r\n";
return -1;
}
qDebug() << "wait and receive data from ZH Proxy...\r\n";
if (0 != RecvAndCheckDataFromSock(_zhProxySock, _codeFlag,0))
{
qDebug() << "receive data or check data failed\r\n";
return -1;
}
return 0;
}
int QFmClient::CheckRecvedData()
{
QByteArray recvdata(_recvbuf);
QJsonParseError json_error;
QJsonDocument doc = QJsonDocument::fromJson(recvdata, &json_error);
if(json_error.error != QJsonParseError::NoError || !doc.isObject())
{
qDebug() << "error request json data!\r\n";
return -1;
}
return 0;
}
int QFmClient::ProcessZhProxyRspDataAndSend2Pos()
{
int rlt, length;
if (0 != CheckRecvedData())
{
return -1;
}
memcpy( _tempbuf, _recvbuf, strlen(_recvbuf) );
//UTF8ToGBK(g_clientInfo.tmpBuf, g_clientInfo.rcvBuf,MAX_SEND_RCV_BUF_LEN -100);
length = strlen(_recvbuf);
//! TODO: 转换JSON
rlt = SendSocketData(_acceptedSock, _recvbuf, length, 0);
if (rlt != length)
{
#ifdef WIN32
qDebug() << "recv() return : " << rlt << ";error : " << WSAGetLastError() << ";\r\n";
#endif
return -1;
}
return 0;
}
void QFmClient::BackupPosReq(char * req)
{
QFile file(qApp->applicationDirPath()+ "/" + ROLL_BACK_FILE_NAME);
int wl = strlen(req);
if(file.open(QFile::ReadWrite))
{
wl = ZH_encodeBkData(req, wl, (char *)_codeKey, _keyLength, _codeBuf);
file.write(_codeBuf, wl);
file.close();
}
}
void QFmClient::run()
{
if(!Init("115.159.63.201", 29534, 34952, 5, 30))
{
qDebug() << "Init QFmClient failed";
emit Error("Init QFmClient failed");
}
qDebug()<< "Init success";
do
{
CloseSocket(&_acceptedSock);
CloseSocket(&_listenSock);
CheckRollBackData();
if(!StartListenport())
{
qDebug() << "Start Listen port : " << _clientPort <<" failed";
WaitAndSleep(3000);
continue ;
}
do
{
int rlt, needBackup;
if (!WaitForConnectReqFromPos())
{
break;
}
if (0 != WaitAndReadDataFromPos(1, 0))
{
CloseSocket(&_acceptedSock);
continue;
}
QJsonObject object;
char temp_recv[MAX_BUF_LEN] = {0};
strcpy(temp_recv, _recvbuf);
needBackup = ProcessPosReqData(object);
if (0 > needBackup)
{
CloseSocket(&_acceptedSock);
continue;
}
if (0 != Try2ConnectZhProxy())
{
qDebug() << "connect to proxy failed";
CloseSocket(&_acceptedSock);
continue;
}
if (0 != SendCtrlInfo2Proxy())
{
CloseSocket(&_acceptedSock);
continue;
}
memset(_sendbuf, 0, MAX_BUF_LEN);
QString temp = QString(QJsonDocument(object).toJson());
strcpy(_sendbuf, temp.toStdString().c_str());
rlt = SendData2ZhProxyAndWaitRspData();
if (0 == rlt)
{
rlt = ProcessZhProxyRspDataAndSend2Pos();
}
CloseSocket(&_zhProxySock);
if (0 != rlt)
{
if (1 == needBackup)
{//is write off data, need to check roll back
BackupPosReq(temp_recv);
break;
}
CloseSocket(&_acceptedSock);
}
}while(1);
WaitAndSleep(3000);
}while(!_endflag);
qDebug() << "Exit ZH Client!\r\n";
#ifdef WIN32
WSACleanup();
#endif
}
void QFmClient::CloseSocket(int *sock)
{
if(0 < *sock)
{
#ifdef WIN32
closesocket(*sock);
#else
close(*sock);
#endif
*sock = 0;
}
}
bool QFmClient::StartListenport()
{
struct sockaddr_in s_add;
int reuse = 1;
#ifdef WIN32
_listenSock = socket(AF_INET, SOCK_STREAM, 0);
#else
_listenSock = socket(AF_INET, SOCK_STREAM, 0);
#endif
if(-1 == _listenSock)
{
return false;
}
memset(&s_add, 0, sizeof(struct sockaddr_in));
s_add.sin_family=AF_INET;
s_add.sin_addr.s_addr=htonl(INADDR_ANY);
s_add.sin_port=htons(_clientPort);
setsockopt(_listenSock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));
if(-1 == bind(_listenSock,(struct sockaddr *)(&s_add), sizeof(struct sockaddr)))
{
return false;
}
if(-1 == listen(_listenSock,1))
{
return false;
}
return true;
}
void QFmClient::CheckRollBackData()
{
QString filename = qApp->applicationDirPath() + "/" + ROLL_BACK_FILE_NAME;
FILE *file = fopen(filename.toStdString().c_str(), "rb");
if (0 == file)
{//no data need to be roll back
return;
}
qDebug() << "need to roll back data...\r\n";
fseek(file, 0, SEEK_SET);
fseek(file, 0, SEEK_END);
int readLen = ftell(file);
fseek(file, 0, SEEK_SET);
memset(_codeBuf, 0, MAX_BUF_LEN);
int rlt = fread(_codeBuf, readLen, 1, file);
fclose(file);
if (1 != rlt || 0 >= readLen)
{
qDebug() << "roll back file error, file length error!\r\n";
remove(filename.toStdString().c_str());
return ;
}
memset(_sendbuf, 0, MAX_BUF_LEN);
ZH_decodeBkData(_codeBuf, _sendbuf, readLen);
//qDebug() << "rollback data:" << _sendbuf;
qDebug() << "\r\n";
QByteArray senddata(_sendbuf);
QJsonParseError json_error;
QJsonDocument doc = QJsonDocument::fromJson(senddata, &json_error);
if(json_error.error != QJsonParseError::NoError || !doc.isObject())
{
qDebug() << "error rbk json data!\r\n";
remove(filename.toStdString().c_str());
return ;
}
QJsonObject json = doc.object();
json["reqtype"] = 3;
AddReqCount(json);
memset(_sendbuf, 0, MAX_BUF_LEN);
QString temp = QString(QJsonDocument(json).toJson());
strcpy(_sendbuf, temp.toStdString().c_str());
qDebug() << "rollback data:" << _sendbuf;
qDebug() << "\r\n";
do
{
WaitAndSleep(5000);
if (0 != Try2ConnectZhProxy())
{
qDebug() << "roll back data: connect ZH Proxy failed, will try after 5 seconds...\r\n";
continue;
}
if (0 != SendCtrlInfo2Proxy())
{
qDebug() << "roll back data: send ctrl info 2 ZH Proxy failed, will try after 5 seconds...\r\n";
continue;
}
if (0 != SendData2ZhProxyAndWaitRspData())
{
qDebug() << "roll back data: send data to proxy fail, will try after 5 seconds...\r\n";
continue;
}
break;
}while(1);
qDebug() << "roll back ok!\r\n";
CloseSocket(&_zhProxySock);
remove(filename.toStdString().c_str());
return;
}
#ifndef QFMCLIENT_H
#define QFMCLIENT_H
#include <QThread>
#include <windows.h>
#include <QTextStream>
#include <QCoreApplication>
#define MAX_CODE_KEY 32
#define MAX_CTRL_INFO_LEN 16
#define MAX_BUF_LEN 4096
#define MAX_REQ_COUNT 25600
#define ROLL_BACK_FILE_NAME "fmclient.rbk"
class QFmClient : public QThread
{
Q_OBJECT
public:
QFmClient(QObject *parent = NULL);
void run();
bool Init(QString proxy_IP, unsigned short proxy_port, unsigned short listen_prot, unsigned short long_timeout, unsigned short short_timeout);
signals:
void Error(QString error);
private:
void CloseSocket(int *sock);
void GetKey();
bool StartListenport();
void CheckRollBackData();
int Try2ConnectZhProxy();
int SendCtrlInfo2Proxy();
void WaitAndSleep(int elapse);
bool WaitForConnectReqFromPos();
int ProcessPosReqData(QJsonObject& object);
bool ConvertJsonFormat(QJsonObject& object); //convert pos requst json format from 非码支付插件 API 对接说明.pdf to 非码支付FMClient商户版_20170921.pdf
void GetStoreInfo(QJsonObject& object); //获取门店信息
void sendResponseToPos(int nflag);
void AddReqCount(QJsonObject &object);
int CheckIsCompleteJsonData(int *count, char *data);
int RecvSockData(int sock, char *buffer, int length);
int WaitAndReadDataFromPos(int type, int flag);
char *DecodeRecvData(char *buf, int length, int *dLength);
int UTF8ToGBK(unsigned char *lpUTF8Str, unsigned char *lpGBKStr, int nGBKStrLen);
int GBKToUTF8(unsigned char *lpGBKStr, int gbkLen, unsigned char *lpUTF8Str, int nUTF8StrLen);
int CheckReqFromPos(char *pJsonData, int dLength, int chkValue);
int SendSocketData(int sock, char *buf, int length, int flag);
char *EncodeSendData(char *buf, int length, int *eLength);
int SendData2ZhProxyAndWaitRspData();
int RecvAndCheckDataFromSock(int sock, int flag, int type);
int ProcessZhProxyRspDataAndSend2Pos();
int CheckRecvedData();
void BackupPosReq(char *req);
private:
bool _endflag;
char _recvbuf[MAX_BUF_LEN];
char _tempbuf[MAX_BUF_LEN];
char _sendbuf[MAX_BUF_LEN];
char _codeBuf[MAX_BUF_LEN];
unsigned char _codeKey[MAX_CODE_KEY];
//proxy IP
char _proxyIP[30];
//proxy 端口
unsigned short _proxyPort;
//QFMClient监听端口
unsigned short _clientPort;
//应用层分段大小(1024)
unsigned int _fmMSS;
//监听本地端口的socket
int _listenSock;
//接收pos请求的socket
int _acceptedSock;
//和proxy交互的socket
int _zhProxySock;
//接收数据长度
int _rcvLength;
//长超时
unsigned short _longTimeOut;
//短超时
unsigned short _shortTimeOut;
//当前使用超时
unsigned short _sockTimeOut;
char _keyLength;
char _curKeyPos;
char _codeFlag;
char _reserved;
//门店信息
typedef struct _STORE_INFO{
QString partner_id; //商户编号
QString store_id; //商家门店号
QString pos_id; //商家POS机编号
QString operator_id; //营业员编号
QString business_date; //营业日
}STORE_INFO;
STORE_INFO store_info;
static unsigned int s_reqCount;
};
#endif // QFMCLIENT_H
QT += core
QT -= gui
TARGET = qfmclient
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
LIBS += -L$$PWD/lib/
DESTDIR = $$PWD/bin
win32 {
LIBS += -lfmcrypt
}
SOURCES += main.cpp \
qfmclient.cpp
HEADERS += \
fmcrypt.h \
qfmclient.h
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment