Exemple #1
0
// 函数名: CheckProcCancel
// 编程  : 陈永华 2004-3-10 15:44:20
// 描述  : 检查是否本处理请求,前台是否要求停止。注意:这个由于要检查连接上是否有该停止命令而会导致等1毫秒,而使得处理效率降低
// 返回  : int 1:表示前台有要求停止的命令;0:没有
int CheckProcCancel()
{
   if (g_SvrLink.CheckProcCancel())
      return(1);
   else 
      return(0);
}
Exemple #2
0
int FTestIReply(TRUSERID *handle,int iRequest,ST_PACK *rPack,int *iRetCode,char *szMsg)
{
   unsigned char *pb;
   pb = g_SvrLink.head.ParmBits;
   g_SvrLink.SetCol(handle,pb);
   PutRow(handle,rPack,iRetCode,szMsg);
   AnswerData(handle,*iRetCode,szMsg);
   return(0);
}
Exemple #3
0
// 函数名: BCCMsgLogOut
// 编程  : 陈永华 2004-3-10 19:31:25
// 描述  : 由BCC集中输出本BU的文本日志信息
// 返回  : int 0:成功;否则即为与BCC通讯出现问题,建议业务取消处理
// 参数  : int logid :本日志的ID号
// 参数  : char *pFormat :文本日志的格式定义
// 参数  : ... :以pFormat定义的输出参数
int BCCMsgLogOut(int logid,char *pFormat,...)
{
   char omsg[1024];
   va_list pArg;
   va_start(pArg,pFormat);
   vsprintf(omsg,pFormat,pArg);
   va_end(pArg);
   return(g_SvrLink.BCCLogOut(LT_MSG,logid,strlen(omsg),omsg));
}
Exemple #4
0
// 函数名: SetBUError
// 编程  : 陈永华 2004-3-22 11:42:37
// 描述  : 设置本BU出错信息,用于提供给前端程序
// 返回  : int 0:成功;否则即为与BCC通讯出现问题,建议业务取消处理
// 参数  : int errcode
// 参数  : char *pFormat
// 参数  : ...
int SetBUError(int errcode,char *pFormat,...)
{
   char omsg[1024];
   va_list pArg;
   va_start(pArg,pFormat);
   vsprintf(omsg,pFormat,pArg);
   va_end(pArg);
   return(g_SvrLink.SetBUError(errcode,omsg));   
}
Exemple #5
0
int SetHeadCol(ST_CPACK *in_cpack, ...)
{
	va_list ap;
	int arg;
	va_start(ap, in_cpack);
	while ((arg = va_arg(ap, int)) >= 0)
	{
		SetParmBit(&(in_cpack->head), arg);
	}
	va_end(ap);
    return(g_SvrLink.SetCol(0, in_cpack->head.ParmBits));
}
Exemple #6
0
/* ****** Updated by CHENYH at 2004-3-10 22:17:31 ****** 
// 函数名: SetCol
// 编程  : 陈永华 2004-2-8 23:26:38
// 描述  : 设置CPACK报文位图;当已经用PutRow输出了数据记录,则将上次数据打包发送给原请求端
// 返回  : int 0:成功;与BCC通讯出现问题,建议业务取消处理
// 参数  : void *handle - 暂时就对应的 TRUSERID *, 在本系统没有意义,因为单线程的缘故
// 参数  : ...  用 F_XXXXX 定义的相关字段列表,用 0表示结束;当handle后即为0,则清空位图重新设置位图
*/
int SetCol(TRUSERID *handle,...)
{
	va_list ap;
	int arg;
   ST_PACKHEAD head;
   memset(&head,0,sizeof(head));
	va_start(ap, handle);
	while ((arg = va_arg(ap, int)) != 0)
	{
		SetParmBit( &head, arg);
	}
	va_end(ap);
   return(g_SvrLink.SetCol(handle,head.ParmBits));
}
int CopyHeadCol(ST_PACK* rPack,ST_CPACK* sPack)
{
	int iLastFidx;
	ST_CPACK* cpack=(ST_CPACK*)((char*)rPack-sizeof(ST_PACKHEAD));
	
	pXPack->GetPackDef(iLastFidx);
	for(int i=0;i<iLastFidx;i++)
	{
		if(pXPack->IsValidField(&(cpack->head),i))
		{
			SetParmBit(&(sPack->head),i);
		}
	}
	return(g_SvrLink.SetCol(0, sPack->head.ParmBits));
}
Exemple #8
0
/* ****** Updated by CHENYH at 2004-3-10 22:17:31 ****** 
// 函数名: SetCol
// 编程  : 陈永华 2004-2-8 23:26:38
// 描述  : 设置CPACK报文位图;当已经用PutRow输出了数据记录,则将上次数据打包发送给原请求端
// 返回  : int 0:成功;与BCC通讯出现问题,建议业务取消处理
// 参数  : void *handle - 暂时就对应的 TRUSERID *, 在本系统没有意义,因为单线程的缘故
// 参数  : ...  用 F_XXXXX 定义的相关字段列表,用END_FIELD表示结束;当handle后即为END_FIELD,则清空位图重新设置位图
*/
int SetCol(TRUSERID *handle,...)
{
	va_list ap;
	int arg;
   ST_PACKHEAD head;
   memset(&head,0,sizeof(head));
	va_start(ap, handle);

/* ****** Updated by CHENYH at 2005-1-25 14:27:25 ****** 
	while ((arg = va_arg(ap, int)) != 0)
*/
   while ((arg=va_arg(ap,int))>=0)
//////////////////////////////////////////////////////////////////////////
	{
		SetParmBit( &head, arg);
	}
	va_end(ap);
   return(g_SvrLink.SetCol(handle,head.ParmBits));
}
Exemple #9
0
int main(int argc,char *argv[])
{
   int rtn;
   pSqlDB = &(g_BUnit.m_SqlDB); // 供外部方便检查,主要用于DEBUGSQLERROR(msg)
   g_BUnit.pSvrLink = &g_SvrLink;
   g_LogFile.SetFlushDelay(0);
   g_LogFile.Open("bulog");
   memset(pSqlDB,0,sizeof(ST_SQLDB));
   openlog("fdykt_hhd",LOG_PID|LOG_CONS|LOG_NDELAY,LOG_LOCAL4);
   puts("Before Reading ini...");
   if (argc<2)
      ReadIni("fdsvrall.ini");
   else
      ReadIni(argv[1]);
   puts("读配置文件end!\n");
   DEBUG_RUNTIME_MSGOUT("读配置文件end");
   ResetBPFunctions();
   if (argc>2)
   {
      ListBPFunctions(argv[2]);
   }

   pSqlDB->bConnected = 0;   

   // 初始化数据库连接:
   SQLInitialize();
   if (SQLConnectToServer()!=0)
   {
      DEBUG_RUNTIME_MSGOUT("不能正常建立数据库连接, 检查配置和数据库服务器!\n");
      return(-100);
   }
   // 初始化与BCC连接:
   DEBUG_RUNTIME_MSGOUT("连接数据库成功!\n");
   do 
   {
      rtn = g_SvrLink.ToLink(&g_BUnit);
      if (rtn==1)
      {
         DEBUG_RUNTIME_MSGOUT("与业务调度中心(BCC)的连接成功!\n");
         break;
      }
      else if (rtn==-100)
      {
         DEBUG_RUNTIME_MSGOUT("估计业务调度中心(BCC)尚未正式启动,或者检查配置中的[SERVER]项参数\n");
	 puts("sleep waiting for connect  BCC!");
         mysleep(g_BUnit.iHBInterval);
      }
      else
      {
         // 应该属于故障,或对方并不是BCC
         DEBUG_RUNTIME_MSGOUT("未知错误\n");
         return(rtn);
      }
   } while (1);
   setnoblockgetch();

/**********************************************************************
 Added by hhd at 2004-09-16
 为了增加签到处理,达到共享内存的处理
 增加共享内存和信号量
 共享内存一共1024个字节,其中使用前18个字节
 shm[0]:代表是否进行过签到的标志,如果为1,已经签过到但不知道是否成功
 		,后续业务将不能进行签到处理,如果为其他值,系统将进行签到
 shm[1]:代表签到是否成功的标志,如果为1,则标识签到成功,后续16个字节为
 		银行正常返回数据,可以使用
 shm[2~17]:前8个字节为加密的PIN密钥,后8个字节为加密的MAC密钥
***********************************************************************/
/**********************************************************************
 Update by hhd at 2004-10-27
 为了增加签到处理,达到共享内存的处理
 增加共享内存和信号量
 为了反映每个终端的当前工作状态,在共享内存中设置一个状态标志
 共享内存一共1024个字节,其中使用前26个字节
 shm[0]:代表是否进行过签到的标志,如果为1,已经签过到但不知道是否成功
 		,后续业务将不能进行签到处理,如果为其他值,系统将进行签到
 shm[1]:代表签到是否成功的标志,如果为1,则标识签到成功,后续16个字节为
 		银行正常返回数据,可以使用
 shm[2]:代表系统重新启动标志,如果不为1,系统进行初始化操作(进行设备
 		注册表中设备的状态的清空操作),然后系统将改标志置为1,其他BU启动
 		跳过该项操作
 shm[10~25]:前8个字节为加密的PIN密钥,后8个字节为加密的MAC密钥
***********************************************************************/

	key_t key;
	int ret=0;
	struct shmid_ds buf;


// Update by lq at 2005-03-10
// 将创建共享内存和设备签到移到bankguard中去
// 必须先运行bankguard此处操作才能完成

	key=ftok(".",0);
	shmid=shmget(key,SEGSIZE,0666);
	if(-1==shmid)
	{
		DEBUG_RUNTIME_MSGOUT("获取共享内存失败,请确保bankguard已经启动\n");
		return 	E_CREATE_SHARE_MEMORY;	
	}
	shm=(char*)shmat(shmid,0,0);
	if((int)shm==-1)
	{
		DEBUG_RUNTIME_MSGOUT("映射共享内存失败");
		return 	E_JOIN_SHARE_MEMORY;	
	}
	semid=semget(key,1,0);
	if(semid==-1)
	{
		DEBUG_RUNTIME_MSGOUT("获取共享锁id失败");
		return E_JOIN_SHARE_MEMORY;
	}

   while (g_SvrLink.LinkOK())
   {
      switch (mygetch())
      {
      case '?':
      case 'h':
      case 'H':
         printf("\nCommand List:\n");
         printf("\t ? or h: display this Help informations!\n");
         printf("\t x: To eXit this business unit.\n");
         printf("\t d: Display functions status.\n");
         printf("\t l: List functions status into <function.lst>.\n");
         printf("Enter command to select:\n");
         break;
      case 'x':
      case 'X':
         g_SvrLink.bExit = true;
         continue;
         break;
      case 'd':
      case 'D':
         ListBPFunctions(NULL);
         break;
      case 'l':
      case 'L':
         ListBPFunctions("function.lst");
         break;
      }
      
      TestSQLConnect();
      if (pSqlDB->bConnected==0)	//这个变量有人维护吗?
      {
         mysleep(1000);
         if (!g_SvrLink.CheckLink()) 
            break;  // BCC exit (可能用户发现数据库连接断开,需要维护系统,导致手工将BCC退出同时也需要BU退出)
         if (SQLConnectToServer()!=0)
         {
            // SQL Link error:
            DEBUG_RUNTIME_MSGOUT("不能正常建立数据库连接, 检查配置和数据库服务器!\n");
         }
         else
         {
            DEBUG_RUNTIME_MSGOUT("与数据库连接成功!\n");
         }
         continue;
      }
      else 
         g_SvrLink.Processing(&g_BUnit);
      if (g_SvrLink.bExit) break;
   }


/* ****** Updated by CHENYH at 2004-4-14 11:07:19 ****** 
   经过测试后,CheckLink()工作正常,测试环境为:BCC(WIN)+BU(WIN),BCC(LINUX)+BU(WIN),BCC(LINUX)+BU(LINUX)
   while (1)
   {
      mysleep(1000);
      if (!g_SvrLink.CheckLink())
      {
         printf("TEST CHECK LINK return <false>!\n");
         break;
      }
   }
*/

	shmdt(shm);
	shmctl(shmid,IPC_RMID,&buf);
	d_sem(semid);

	closelog();
	g_SvrLink.Close();
	SQLExit();
	DEBUG_RUNTIME_MSGOUT("业务处理单元BU系统正常退出!\n");
	g_LogFile.Close();
	return(0);
}
Exemple #10
0
// 函数名: ExtCallNext
// 编程  : 陈永华 2004-3-8 17:31:47
// 描述  : 在调用ExtCall之后,发现对方尚有数据还没有取回来,则用本功能获取后续数据
// 返回  : int >=0:成功,返回的为应答数据包体记录数;<0:错误;-2:等待接收应答超时;-1:其他通讯错误;-3:已经取完了后续数据
// 参数  : int acktime
// 参数  : ST_CPACK *apack
// 参数  : ST_PACK *pArrays
int ExtCallNext(int acktime,ST_CPACK *apack,ST_PACK *pArrays)
{
   return(g_SvrLink.ExtCallNext(acktime,apack,pArrays));
}
Exemple #11
0
// 函数名: ResetNormalCPack
// 编程  : 陈永华 2004-3-11 20:30:59
// 描述  : 根据本业务请求包,设置一个CPACK包头,位图和数据都被清空了
// 返回  : void 
// 参数  : ST_CPACK *pack
void ResetNormalCPack(ST_CPACK *pack,unsigned char nextflag,int recCount)
{
   g_SvrLink.ResetNormalCPack(pack,nextflag,recCount);
}
Exemple #12
0
// 函数名: SetMaxRow
// 编程  : 陈永华 2004-3-22 11:41:26
// 描述  : 设置本次功能处理时候,每个应答包返回的最大记录数,只对本次功能处理有效
// 返回  : int 0:成功;否则即为与BCC通讯出现问题,建议业务取消处理
// 参数  : int maxrows
int SetMaxRow(int maxrows)
{
   return(g_SvrLink.SetMaxRow(maxrows));
}
Exemple #13
0
// 函数名: SetAnswerMode
// 编程  : 陈永华 2004-3-10 18:48:18
// 描述  : 更改应答模式,见AM_xxxx的定义
// 返回  : int 0:成功;否则即为与BCC通讯出现问题,建议业务取消处理
// 参数  : char iAnswerMode 见AM_xxxx的定义
int SetAnswerMode(char iAnswerMode)
{
   return(g_SvrLink.SetAnswerMode(iAnswerMode));
}
Exemple #14
0
// 函数名: PutRowData
// 编程  : 陈永华 2004-2-8 23:30:07
// 描述  : 在输出的CPACK报文中增加一条ST_PACK报体记录,实际对之前用SetCol定义的字段有效,没有定义的无效
// 返回  : int 0:成功;与BCC通讯出现问题,建议业务取消处理
// 参数  : ST_PACK *pdata  - 增加的ST_PACK存放数据
int PutRowData(ST_PACK *pdata)
{
   return(g_SvrLink.PutRowData(pdata));
}
Exemple #15
0
// 函数名: CT_ERR_DEAL
// 编程  : 陈永华 2004-2-22 16:39:51
// 描述  : 清除原来准备的应答信息,并且在运行时跟踪文件中记录(错误)信息(为了与集中交易兼容)
// 返回  : int 0:成功;否则即为与BCC通讯出现问题,建议业务取消处理
// 参数  : char *msg
// 参数  : int retcode
int CT_ERR_DEAL(char *msg,int retcode)
{
   return(g_SvrLink.Err_Deal(msg,retcode));
}
Exemple #16
0
// 函数名: CopyAnswerHead
// 编程  : 陈永华 2004-4-15 9:24:20
// 描述  : 将提交给请求方的应答的数据包头复制到指定的phead里
// 返回  : void 
// 参数  : ST_PACKHEAD *phead :复制包头的缓冲
void CopyAnswerHead(ST_PACKHEAD *phead)
{
   g_SvrLink.CopyAnswerHead(phead);
}
Exemple #17
0
// 函数名: AnswerDataEx
// 编程  : 陈永华 2004-2-8 23:37:00
// 描述  : 向ruserid的客户端,发送apack和pArrays组成应答返回的数据
// 返回  : int 0:成功;否则即为与BCC通讯出现问题,建议业务取消处理
// 参数  : TRUSERID *ruserid  目标客户端的标识
// 参数  : ST_CPACK *apack  应答数据头和首报体
// 参数  : ST_PACK *pArrays 后续数据报体,当apack->head.RetCount<=1时候,无效 可以填写为NULL
// 参数  : int retcode 应答数据的返回码 对应ST_CPACK的头中的RetCode
// 参数  : char *szmsg 如果为NULL或“”,则应答数据中,就不包括vsmess字段数据
int AnswerDataEx(TRUSERID *ruserid,ST_CPACK *apack,ST_PACK *pArrays,int retcode,char *szmsg)
{
   return(g_SvrLink.AnswerDataEx(ruserid,apack,pArrays,retcode,szmsg));
}
Exemple #18
0
// 函数名: AnswerDataPart
// 编程  : 陈永华 2004-2-12 12:12:09
// 描述  : 与AnswerData类似,但是用于通知客户端,还有更多的数据返回
//         常用于将有大批量数据返回,尽管数据项相同但是为了不让客户端长时间等待
//         先发送部分数据。
// 返回  : int 0:成功;否则即为与BCC通讯出现问题,建议业务取消处理
// 参数  : TRUSERID *ruserid
// 参数  : int retcode
// 参数  : char *szmsg
int AnswerDataPart(TRUSERID *ruserid,int retcode,char *szmsg)
{
   return(g_SvrLink.AnswerData(ruserid,retcode,szmsg,1));
}
Exemple #19
0
// 函数名: SetAnswerTimeout
// 编程  : 陈永华 2004-3-22 12:49:02
// 描述  : 设定本业务每个应答包的超时时间,以毫秒计,常用于如批结算时候特殊的处理
// 返回  : int 0:成功;否则即为与BCC通讯出现问题,建议业务取消处理
// 参数  : unsigned int atimeout  指定的超时时间(以毫秒计)
int SetAnswerTimeout(unsigned int atimeout)
{
   return(g_SvrLink.SetAnswerTimeout(atimeout));
}
Exemple #20
0
// 函数名: ExtCall
// 编程  : 陈永华 2004-3-6 17:47:14
// 描述  : 向另外一个服务点发送请求,要求对方处理应答返回,本功能常常用于不同系统之间的对接,如要求其他外围系统服务
// 返回  : int >=0:成功,返回的为应答数据包体记录数;<0:错误;-2:等待接收应答超时;-1:其他通讯错误
// 参数  : int sourceno  使用的通讯平台的编号,参见TRUSERID::SourceNo
// 参数  : int destno    目标通讯平台编号
// 参数  : int funcno    目标服务端在通讯平台上注册的通讯功能号
// 参数  : int batchno   该目标点会话批次号 (如果确认针对该目标点,不会有其他的推送模式,则可以直接填写为0)
// 参数  : int acktime   该请求的有效时间,以秒计
// 参数  : ST_CPACK *rpack  请求包数据
// 参数  : ST_CPACK *apack  目标点应答的数据返回
// 参数  : ST_PACK *pArrays 应答数据后续包数据
int ExtCall(int sourceno,int destno,int funcno,int batchno,int acktime,ST_CPACK *rpack,ST_CPACK *apack,ST_PACK *pArrays)
{
   return(g_SvrLink.ExtCall(sourceno,destno,funcno,batchno,acktime,rpack,apack,pArrays));
}
Exemple #21
0
// 函数名: PushData
// 编程  : 陈永华 2004-2-8 23:43:01
// 描述  : 向一个作为服务方式注册的目标点,推送数据
// 返回  : int 0:成功;否则即为与BCC通讯出现问题,建议业务取消处理
// 参数  : int sourceno  推送数据使用的通讯平台的编号,参见TRUSERID::SourceNo
// 参数  : int destno    推送数据的目标通讯平台编号
// 参数  : int funcno    目标服务端在通讯平台上注册的通讯功能号
// 参数  : int batchno   针对该目标点会话批次号
// 参数  : ST_CPACK *ppack  推送的数据包,ppack->head.RetCount<=1,即推送数据不能超过1条报体记录
// 参数  : char pushmode  推送模式,见上述定义的PM_xxx
// 参数  : int acktime   确认回答的期限,以秒计,对于PM_ACK ,PM_ANSWER 有效 
int PushData(int sourceno,int destno,int funcno,int batchno,ST_CPACK *ppack,char pushmode,int acktime)
{
   return(g_SvrLink.PushData(sourceno,destno,funcno,batchno,ppack,pushmode,acktime));
}
Exemple #22
0
// 函数名: ResetAnswerData
// 编程  : 陈永华 2004-3-24 22:16:17
// 描述  : 重置清除已经提交的应答数据,常用于重新执行一个处理,比如因为程序死锁后Retry
// 返回  : int 
int ResetAnswerData()
{
   return(g_SvrLink.ResetAnswerData());
}
Exemple #23
0
// 函数名: PushDataEx
// 编程  : 陈永华 2004-2-9 0:10:53
// 描述  : 向pushdests定义的作为服务方式注册目标点推送数据
// 返回  : int 0:成功;否则即为与BCC通讯出现问题,建议业务取消处理
// 参数  : TPUSHDEST *pushdests 定义的目标点列表
// 参数  : int pdcount  目标点的个数
// 参数  : ST_CPACK *ppack 推送的不超过一条记录的数据包
// 参数  : char pushmode 推送模式,见上述定义的PM_xxx
// 参数  : int acktime  确认回答的期限,以秒计,对于PM_ACK ,PM_ANSWER 有效 
int PushDataEx(TPUSHDEST *pushdests,int pdcount,ST_CPACK *ppack,char pushmode,int acktime)
{
   return(g_SvrLink.PushDataEx(pushdests,pdcount,ppack,pushmode,acktime));
}
Exemple #24
0
// 函数名: PutRow
// 编程  : 陈永华 2004-2-20 10:03:04
// 描述  : 一次性完成PutRowData 和 AnswerData, 但是并不马上发送 (为了与大集中版本兼容)
// 返回  : int 0:成功;否则即为与BCC通讯出现问题,建议业务取消处理
// 参数  : TRUSERID *handle
// 参数  : ST_PACK *pdata
// 参数  : int *pRetCode
// 参数  : char *rtnMsg
int PutRow(TRUSERID *handle,ST_PACK *pdata,int *pRetCode,char *rtnMsg)
{
   return(g_SvrLink.PutRow(handle,pdata,*pRetCode,rtnMsg));
}
Exemple #25
0
int main(int argc,char *argv[])
{
   int rtn;
   pSqlDB = &(g_BUnit.m_SqlDB); // 供外部方便检查,主要用于DEBUGSQLERROR(msg)
   g_BUnit.pSvrLink = &g_SvrLink;
   g_LogFile.SetFlushDelay(0);
   g_LogFile.Open("bulog");
   openlog("yktbase",LOG_PID|LOG_CONS|LOG_NDELAY,LOG_LOCAL0);
   memset(pSqlDB,0,sizeof(ST_SQLDB));
   //puts("Before Reading ini...");
   if (argc<2)
      ReadIni("fdsvrall.ini");
   else
      ReadIni(argv[1]);
   DEBUG_RUNTIME_MSGOUT("读配置文件end");
   ResetBPFunctions();
   if (argc>2)
   {
      ListBPFunctions(argv[2]);
   }

   pSqlDB->bConnected = 0;   

   // 初始化数据库连接:
   SQLInitialize();
   if (SQLConnectToServer()!=0)
   {
      	DEBUG_RUNTIME_MSGOUT("不能正常建立数据库连接, 检查配置和数据库服务器!\n");
   	g_LogFile.Close();
	closelog();
      return(-100);
   }
#ifndef WIN32
	struct sigaction sigact;
	memset(&sigact,0,sizeof sigact);
	sigact.sa_handler = sig_alarm_handler;
	
	sigaction(SIGALRM,&sigact,NULL);
#endif
   // 初始化与BCC连接:
   DEBUG_RUNTIME_MSGOUT("连接数据库成功!\n");
   do 
   {
      rtn = g_SvrLink.ToLink(&g_BUnit);
      if (rtn==1)
      {
         puts("与业务调度中心(BCC)的连接成功!\n");
         break;
      }
      else if (rtn==-100)
      {
         DEBUG_RUNTIME_MSGOUT("估计业务调度中心(BCC)尚未正式启动,或者检查配置中的[SERVER]项参数\n");
	 puts("sleep waiting for connect  BCC!");
         mysleep(g_BUnit.iHBInterval);
      }
      else
      {
    			g_LogFile.Close();
			closelog();
         	 	return(rtn);
      }
   } while (1);
   setnoblockgetch();

   while (g_SvrLink.LinkOK())
   {
   /*
      switch (mygetch())
      {
      case '?':
      case 'h':
      case 'H':
         printf("\nCommand List:\n");
         printf("\t ? or h: display this Help informations!\n");
         printf("\t x: To eXit this business unit.\n");
         printf("\t d: Display functions status.\n");
         printf("\t l: List functions status into <function.lst>.\n");
         printf("Enter command to select:\n");
         break;
      case 'x':
      case 'X':
         g_SvrLink.bExit = true;
         continue;
         break;
      case 'd':
      case 'D':
         ListBPFunctions(NULL);
         break;
      case 'l':
      case 'L':
         ListBPFunctions("function.lst");
         break;
      }
      */
      TestSQLConnect();
      if (pSqlDB->bConnected==0)
      {
         mysleep(1000);
         if (!g_SvrLink.CheckLink()) 
            break;  // BCC exit (可能用户发现数据库连接断开,需要维护系统,导致手工将BCC退出同时也需要BU退出)
         if (SQLConnectToServer()!=0)
         {
            // SQL Link error:
            DEBUG_RUNTIME_MSGOUT("不能正常建立数据库连接, 检查配置和数据库服务器!\n");
         }
         else
         {
            DEBUG_RUNTIME_MSGOUT("与数据库连接成功!\n");
         }
         continue;
      }
      else 
         g_SvrLink.Processing(&g_BUnit);
      if (g_SvrLink.bExit) break;
   }


/* ****** Updated by CHENYH at 2004-4-14 11:07:19 ****** 
   经过测试后,CheckLink()工作正常,测试环境为:BCC(WIN)+BU(WIN),BCC(LINUX)+BU(WIN),BCC(LINUX)+BU(LINUX)
   while (1)
   {
      mysleep(1000);
      if (!g_SvrLink.CheckLink())
      {
         printf("TEST CHECK LINK return <false>!\n");
         break;
      }
   }
*/
   g_SvrLink.Close();
   closelog();
   SQLExit();
   DEBUG_RUNTIME_MSGOUT("业务处理单元BU系统正常退出!\n");
   g_LogFile.Close();
   return(0);
}