/******************************************************************************
* Product: # # ###### ##### # ### ######
* ## ## # # # # # # # #
* # # # # # # # # # # #
* # # # # # # # # ######
* # # # # # # # # #
* # # # # # # # # # #
* # # ###### ##### ####### ####### ### ######
*
* File: mdc_client.c
* Description: MDC Generic communications routines.
*
* Version: %I%
* Dated: %D%
* Copyright: P. Smart, 1996-2019
*
* History: 1.0 - Initial Release.
*
******************************************************************************
* This source file is free software: you can redistribute it and#or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This source file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
******************************************************************************/
/* Bring in system header files.
*/
#if defined(SOLARIS)
#include
#endif
#include
#include
#include
#include
#include
/* Bring in Unix Library headers for TCP/IP communications.
*/
#include
/* Indicate that we are a C module for any header specifics.
*/
#define MDC_CLIENT_C
/* Bring in mdc header files.
*/
#include "mdc.h"
#include "mdc_common.h"
/******************************************************************************
* Function: _MDC_DataCB
* Description: This function is called back when data is received on any of
* the service connections
* Returns: void
******************************************************************************/
void _MDC_DataCB(UINT nChanId, UCHAR *szData, UINT nDataLen)
{
UCHAR *szFunc = "_MDC_DataCB";
UCHAR *szDeComData; /* pointer to decompressed data buffer */
CHSTATE eChanSt;
void (*pUserCB) (UINT, UCHAR *, UINT);
UCHAR *pszNAKErrStr; /* pointer to Error string in */
/* channel status structure */
/* Decompress
*/
szDeComData = Decompress(szData, &nDataLen);
if (szDeComData == NULL)
{
Lgr(LOG_DEBUG, szFunc, "Cannot malloc");
return;
}
/* Check if the data is a service request reply
*/
if (MDC.nPendSRChanId > 0 && nChanId == MDC.nPendSRChanId)
{
/* Reply received for service request
*/
MDC.cReplyType = * ((char *) szDeComData);
if (MDC.cReplyType == MDC_NAK)
{
Lgr(LOG_DEBUG, szFunc, "NAK received for service request");
_MDC_PrintErrMsg((szDeComData + 1), (nDataLen - 1));
}
MDC.nPendSRChanId = 0;
if (szDeComData != szData)
free(szDeComData);
return;
}
/* This is User Data, an ACK or a NAK
Get channel state
*/
if (_MDC_GetChState(nChanId, &eChanSt) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc,
"No status information for channel ID %d", nChanId);
if (szDeComData != szData)
free(szDeComData);
return;
}
switch(* ((char *) szDeComData))
{
case MDC_DATA:
if (eChanSt != IN_SEND_REQUEST)
{
Lgr(LOG_DEBUG, szFunc,
"Received data when in wrong state on channel %d", nChanId);
if (szDeComData != szData)
free(szDeComData);
return;
}
/* Get call back function address
*/
if (_MDC_GetUserCB(nChanId, &pUserCB) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc,
"_MDC_GetUserCB failed for channel ID %d", nChanId);
if (szDeComData != szData)
free(szDeComData);
return;
}
if (pUserCB == NULL)
{
Lgr(LOG_DEBUG, szFunc,
"User call back is NULL for channel ID %d", nChanId);
if (szDeComData != szData)
free(szDeComData);
return;
}
/* Call User call back.
Remove packet type character
*/
(*pUserCB) (nChanId, (szDeComData + 1), (nDataLen - 1));
break;
case MDC_ACK:
if (eChanSt != IN_SEND_REQUEST)
{
Lgr(LOG_DEBUG, szFunc,
"Received ACK when in wrong state on channel %d", nChanId);
if (szDeComData != szData)
free(szDeComData);
return;
}
if (_MDC_SetSRResult(nChanId, TRUE) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc,
"_MDC_SetSRResult failed for channel %d", nChanId);
if (szDeComData != szData)
free(szDeComData);
return;
}
if (_MDC_SetChState(nChanId, SEND_REQUEST_COMPLETE) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc,
"_MDC_SetChState failed for channel %d", nChanId);
if (szDeComData != szData)
free(szDeComData);
return;
}
break;
case MDC_NAK:
if (eChanSt != IN_SEND_REQUEST)
{
Lgr(LOG_DEBUG, szFunc,
"Received ACK when in wrong state on channel %d", nChanId);
if (szDeComData != szData)
free(szDeComData);
return;
}
/* Extract and save Error String
*/
if (_MDC_GetNAKErrStr(nChanId, &pszNAKErrStr) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc,
"_MDC_GetNAKErrStr failed for channel %d", nChanId);
if (szDeComData != szData)
free(szDeComData);
return;
}
strcpy((char *) pszNAKErrStr, (char *) (szDeComData + 1));
if (_MDC_SetSRResult(nChanId, FALSE) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc,
"_MDC_SetSRResult failed for channel %d", nChanId);
if (szDeComData != szData)
free(szDeComData);
return;
}
if (_MDC_SetChState(nChanId, SEND_REQUEST_COMPLETE) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc,
"_MDC_SetChState failed for channel %d", nChanId);
if (szDeComData != szData)
free(szDeComData);
return;
}
break;
default:
/* Unrecognised message type */
Lgr(LOG_DEBUG, szFunc,
"Unrecognised message type %c for channel ID %d",
eChanSt, nChanId);
break;
}
if (szDeComData != szData)
free(szDeComData);
}
/******************************************************************************
* Function: _MDC_CtrlCB
* Description: This function is called back when control information is received
* on any of the service connections
* Returns: void
******************************************************************************/
void _MDC_CtrlCB(int nType, ...)
{
/* Local variables.
*/
UINT nChanId;
UINT nPortNo;
ULNG lIPaddr;
va_list pArgs;
UCHAR *szFunc = "_MDC_CtrlCB";
/* Start var-arg list by making pArgs point to first arg in list.
*/
va_start(pArgs, nType);
/* What type of callback is it...?
*/
switch(nType)
{
/* A new connection has arrived.
*/
case SLC_NEWSERVICE:
nChanId = va_arg(pArgs, UINT);
nPortNo = va_arg(pArgs, UINT);
lIPaddr = va_arg(pArgs, ULNG);
/* Log link going down event for bug catching.
*/
Lgr(LOG_DEBUG, szFunc,
"New Service with client: nChanId=%d, nPortNo=%d, IP=%s",
nChanId, nPortNo, SL_HostIPtoString(lIPaddr));
break;
/* A connection has been made
*/
case SLC_CONNECT:
nChanId = va_arg(pArgs, UINT);
nPortNo = va_arg(pArgs, UINT);
lIPaddr = va_arg(pArgs, ULNG);
if (nChanId == MDC.nPendConChanId)
{
MDC.nPendConChanId = 0;
MDC.nLinkUp = TRUE;
Lgr(LOG_DEBUG, szFunc,
"Connected to client: nChanId=%d, nPortNo=%d, IP=%s",
nChanId, nPortNo, SL_HostIPtoString(lIPaddr));
} else
{
Lgr(LOG_DEBUG, szFunc,
"Rcvd unexpected connection: nChanId=%d, nPortNo=%d, IP=%s",
nChanId, nPortNo, SL_HostIPtoString(lIPaddr));
}
break;
/* Given connection has become temporarily unavailable.
*/
case SLC_LINKDOWN:
nChanId = va_arg(pArgs, UINT);
nPortNo = va_arg(pArgs, UINT);
lIPaddr = va_arg(pArgs, ULNG);
/* Log link going down event for bug catching.
*/
Lgr(LOG_DEBUG, szFunc,
"Link down to client: nChanId=%d, nPortNo=%d, IP=%s",
nChanId, nPortNo, SL_HostIPtoString(lIPaddr));
/* Reset flag to indicate that we dont have a connection.
*/
MDC.nLinkUp = FALSE;
break;
/* Given connection has died.
*/
case SLC_LINKFAIL:
nChanId = va_arg(pArgs, UINT);
nPortNo = va_arg(pArgs, UINT);
lIPaddr = va_arg(pArgs, ULNG);
/* Clean up for Channel ID
*/
if (SL_DelClient(nChanId) != R_OK)
{
Lgr(LOG_DEBUG, szFunc,
"SL_DelClient failed for Channel ID %d", nChanId);
}
/* Log link failure event for bug catching.
*/
Lgr(LOG_DEBUG, szFunc,
"Link closed to client: nChanId=%d, nPortNo=%d, IP=%s",
nChanId, nPortNo, SL_HostIPtoString(lIPaddr));
break;
default:
/* Log a message as this condition shouldnt occur.
*/
Lgr(LOG_DEBUG, szFunc, "Unrecognised message type (%d)", nType);
break;
}
/* Terminate var-arg list.
*/
va_end(pArgs);
}
/******************************************************************************
* Function: _MDC_SendPacket
* Description: Send a packet to a daemon
* Returns: MDC_OK or MDC_FAIL
******************************************************************************/
int _MDC_SendPacket(UINT nChanId, char cPacketType, UCHAR *psnzBuf, UINT nBuflen)
{
char *psnzPktMsgBuf; /* buffer for preparing message to be sent */
char *psnzComBuf; /* pointer to buffer containing compressed message */
UCHAR *szFunc = "_MDC_SendPacket";
UINT nlocalBufLen; /* Local buffer length variable */
nlocalBufLen = nBuflen + 1;
psnzPktMsgBuf = malloc(nlocalBufLen);
if (psnzPktMsgBuf == NULL)
{
Lgr(LOG_DEBUG, szFunc, "Cannot malloc");
return(MDC_FAIL);
}
/* Prepend packet type to service request data */
*psnzPktMsgBuf = cPacketType;
memcpy((psnzPktMsgBuf + 1), psnzBuf, (nlocalBufLen - 1));
/* Log message that we are sending to ease debugging.
*/
Lgr(LOG_DEBUG, szFunc, "Sending packet (Before Compress): Data=%s, Len=%d",
psnzPktMsgBuf, nlocalBufLen);
/* Compress packet to be sent
*/
psnzComBuf = Compress(psnzPktMsgBuf, &nlocalBufLen);
if (psnzComBuf == NULL)
{
Lgr(LOG_DEBUG, szFunc, "Cannot malloc for Compress");
free(psnzPktMsgBuf);
return(MDC_FAIL);
}
/* Log message that we are sending to ease debugging.
*/
Lgr(LOG_DEBUG, szFunc,
"Sending packet (After Compress): nChanId=%d, Data=%s, Len=%d",
nChanId, psnzPktMsgBuf, nlocalBufLen);
/* Send packet to the daemon */
if (SL_SendData(nChanId, (UCHAR *) psnzComBuf, nlocalBufLen) != R_OK)
{
Lgr(LOG_DEBUG, szFunc, "SL_SendData failed");
free(psnzPktMsgBuf);
if (psnzPktMsgBuf != psnzComBuf)
free(psnzComBuf);
return(MDC_FAIL);
}
free(psnzPktMsgBuf);
if (psnzPktMsgBuf != psnzComBuf)
free(psnzComBuf);
return(MDC_OK);
}
/******************************************************************************
* Function: _MDC_GetSrvRqtReply
* Description: Get reply to a service request packet
* Returns: MDC_OK or MDC_FAIL
******************************************************************************/
int _MDC_GetSrvRqtReply(UINT nChanId, char *pcPacketType)
{
/* Local variables.
*/
int nTotalTime;
UCHAR *szFunc = "_MDC_GetSrvRqtReply";
MDC.nPendSRChanId = nChanId;
/* Wait for the service request reply
*/
nTotalTime = 0;
while (MDC.nSrvReqTimeout > nTotalTime && MDC.nPendSRChanId != 0)
{
SL_Poll((ULNG) SR_SLEEP_TIME);
nTotalTime += SR_SLEEP_TIME;
}
if (MDC.nPendSRChanId != 0)
{
MDC.nPendSRChanId = 0;
Lgr(LOG_DEBUG, szFunc, "Timed out waiting for service request reply");
return(MDC_FAIL);
}
*pcPacketType = MDC.cReplyType;
return(MDC_OK);
}
/******************************************************************************
* Function: _MDC_CreateChStatus
* Description: Make a new Channel status structure and add to linked list
* Returns: MDC_OK or MDC_FAIL
******************************************************************************/
int _MDC_CreateChStatus(UINT nChanId) /* Channel ID */
{
UINT nLocalChanId = nChanId;
UCHAR *szFunc = "_MDC_CreateChStatus";
CHANSTATUS *psNewChanSt;
/* Check that there is not already an entry for the Channel ID
*/
if (FindItem(MDC.spChanDetHead, &nLocalChanId, NULL, NULL) != NULL)
{
Lgr(LOG_DEBUG, szFunc, "Channel ID %d already in use", nLocalChanId);
return(MDC_FAIL);
}
psNewChanSt = (CHANSTATUS *) malloc(sizeof(CHANSTATUS));
if (psNewChanSt == NULL)
{
Lgr(LOG_DEBUG, szFunc, "Cannot malloc");
return(MDC_FAIL);
}
psNewChanSt->nChanId = nLocalChanId;
psNewChanSt->State = MAKING_CONN;
psNewChanSt->UserDataCB = NULL;
if (AddItem(&MDC.spChanDetHead, &MDC.spChanDetTail, SORT_NONE, &nLocalChanId,
NULL, NULL, psNewChanSt) != R_OK)
{
Lgr(LOG_DEBUG, szFunc, "AddItem failed for Channel ID %d",
nLocalChanId);
return(MDC_FAIL);
}
return(MDC_OK);
}
/******************************************************************************
* Function: _MDC_DelChStatus
* Description: Delete an item from the Channel status linked list
* Returns: MDC_OK or MDC_FAIL
******************************************************************************/
int _MDC_DelChStatus(UINT nChanId) /* Channel ID */
{
UINT nLocalChanId = nChanId;
UCHAR *szFunc = "_MDC_DelChStatus";
CHANSTATUS *ChanSt;
if ((ChanSt = FindItem(MDC.spChanDetHead, &nLocalChanId, NULL, NULL)) == NULL)
{
Lgr(LOG_DEBUG, szFunc,
"FindItem failed: Channel ID %d not found", nLocalChanId);
return(MDC_FAIL);
}
if (DelItem(&MDC.spChanDetHead, &MDC.spChanDetTail, NULL, &nLocalChanId, NULL, NULL) != R_OK)
{
Lgr(LOG_DEBUG, szFunc,
"DelItem failed: Channel ID %d not found", nLocalChanId);
return(MDC_FAIL);
}
/* pds: 12/7/96. Ian forgot to tell the UX library that the channel had closed, so
* the following statement sends a request to UX to close the channel.
*/
SL_DelClient(nChanId);
free(ChanSt);
return(MDC_OK);
}
/******************************************************************************
* Function: _MDC_SetChState
* Description: Set Channel State to the given value
* Returns: MDC_OK or MDC_FAIL
******************************************************************************/
int _MDC_SetChState( UINT nChanId, /* Channel ID */
CHSTATE eNewState) /* New state */
{
UINT nLocalChanId = nChanId;
UCHAR *szFunc = "_MDC_SetChState";
CHANSTATUS *ChanSt;
if ((ChanSt = FindItem(MDC.spChanDetHead, &nLocalChanId, NULL, NULL)) == NULL)
{
Lgr(LOG_DEBUG, szFunc,
"FindItem failed: Channel ID %d not found", nLocalChanId);
return(MDC_FAIL);
}
ChanSt->State = eNewState;
return(MDC_OK);
}
/******************************************************************************
* Function: _MDC_SetSRResult
* Description: Set Channel Send Request result
* Returns: MDC_OK or MDC_FAIL
******************************************************************************/
int _MDC_SetSRResult( UINT nChanId, /* Channel ID */
UINT bResult) /* Send Request result */
{
UINT nLocalChanId = nChanId;
UCHAR *szFunc = "_MDC_SetSRResult";
CHANSTATUS *ChanSt;
if ((ChanSt = FindItem(MDC.spChanDetHead, &nLocalChanId, NULL, NULL)) == NULL)
{
Lgr(LOG_DEBUG, szFunc,
"FindItem failed: Channel ID %d not found", nLocalChanId);
return(MDC_FAIL);
}
ChanSt->bSendReqResult = bResult;
return(MDC_OK);
}
/******************************************************************************
* Function: _MDC_GetSRResult
* Description: Get Channel Send Request result
* Returns: MDC_OK or MDC_FAIL
******************************************************************************/
int _MDC_GetSRResult( UINT nChanId, /* Channel ID */
UINT *bResult) /* Send Request result */
{
UINT nLocalChanId = nChanId;
UCHAR *szFunc = "_MDC_GetSRResult";
CHANSTATUS *ChanSt;
if ((ChanSt = FindItem(MDC.spChanDetHead, &nLocalChanId, NULL, NULL)) == NULL)
{
Lgr(LOG_DEBUG, szFunc,
"FindItem failed: Channel ID %d not found", nLocalChanId);
return(MDC_FAIL);
}
*bResult = ChanSt->bSendReqResult;
return(MDC_OK);
}
/******************************************************************************
* Function: _MDC_SetUserCB
* Description: Set Send Request call back to the given value
* Returns: MDC_OK or MDC_FAIL
******************************************************************************/
int _MDC_SetUserCB( UINT nChanId, /* Channel ID */
void (*UserCB) (UINT, UCHAR *, UINT)) /* call back */
{
UINT nLocalChanId = nChanId;
UCHAR *szFunc = "_MDC_SetUserCB";
CHANSTATUS *ChanSt;
if ((ChanSt = FindItem(MDC.spChanDetHead, &nLocalChanId, NULL, NULL)) == NULL)
{
Lgr(LOG_DEBUG, szFunc,
"FindItem failed: Channel ID %d not found", nLocalChanId);
return(MDC_FAIL);
}
ChanSt->UserDataCB = UserCB;
return(MDC_OK);
}
/******************************************************************************
* Function: _MDC_GetChState
* Description: Get Channel State for a given channel
* Returns: MDC_OK or MDC_FAIL
******************************************************************************/
int _MDC_GetChState( UINT nChanId, /* Channel ID */
CHSTATE *eState) /* Channel state */
{
UINT nLocalChanId = nChanId;
UCHAR *szFunc = "_MDC_GetChState";
CHANSTATUS *ChanSt;
if ((ChanSt = FindItem(MDC.spChanDetHead, &nLocalChanId, NULL, NULL)) == NULL)
{
Lgr(LOG_DEBUG, szFunc,
"FindItem failed: Channel ID %d not found", nLocalChanId);
return(MDC_FAIL);
}
*eState = ChanSt->State;
return(MDC_OK);
}
/******************************************************************************
* Function: _MDC_GetNAKErrStr
* Description: Get pointer to NAK error string
* Returns: MDC_OK or MDC_FAIL
******************************************************************************/
int _MDC_GetNAKErrStr( UINT nChanId, /* Channel ID */
UCHAR **ppszErrStr) /* pointer to pointer to error string */
{
UINT nLocalChanId = nChanId;
UCHAR *szFunc = "_MDC_GetNAKErrStr";
CHANSTATUS *ChanSt;
if ((ChanSt = FindItem(MDC.spChanDetHead, &nLocalChanId, NULL, NULL)) == NULL)
{
Lgr(LOG_DEBUG, szFunc,
"FindItem failed: Channel ID %d not found", nLocalChanId);
return(MDC_FAIL);
}
*ppszErrStr = ChanSt->pszErrStr;
return(MDC_OK);
}
/******************************************************************************
* Function: _MDC_GetUserCB
* Description: Get User call back for the channel
* Returns: MDC_OK or MDC_FAIL
******************************************************************************/
int _MDC_GetUserCB( UINT nChanId, /* Channel ID */
void (**UserCB) (UINT, UCHAR *, UINT)) /* User call back */
{
UINT nLocalChanId = nChanId;
UCHAR *szFunc = "_MDC_GetUserCB";
CHANSTATUS *ChanSt;
if ((ChanSt = FindItem(MDC.spChanDetHead, &nLocalChanId, NULL, NULL)) == NULL)
{
Lgr(LOG_DEBUG, szFunc,
"FindItem failed: Channel ID %d not found", nLocalChanId);
return(MDC_FAIL);
}
*UserCB = ChanSt->UserDataCB;
return(MDC_OK);
}
/******************************************************************************
* Function: _MDC_PrintErrMsg
* Description: Print error message text
* Returns: MDC_OK or MDC_FAIL
******************************************************************************/
int _MDC_PrintErrMsg( UCHAR *psnzErrMsg, /* Error message none terminated */
UINT nBufLen) /* Buffer Length */
{
char *pszTmpBuf;
UCHAR *szFunc = "_MDC_PrintErrMsg";
pszTmpBuf = (char *) malloc(nBufLen + 1);
if (pszTmpBuf == NULL)
{
Lgr(LOG_DEBUG, szFunc, "Cannot malloc");
return(MDC_FAIL);
}
memcpy(pszTmpBuf, psnzErrMsg, nBufLen);
pszTmpBuf[nBufLen] = '\0';
Lgr(LOG_DEBUG, "", "Error Message: %s", pszTmpBuf);
free(pszTmpBuf);
return(MDC_OK);
}
/******************************************************************************
* Function: _MDC_WaitOnSndReq
* Description: Block until send request completes
* Returns: MDC_OK or MDC_FAIL
******************************************************************************/
int _MDC_WaitOnSndReq(UINT nChanId) /* Channel ID */
{
/* Local variables.
*/
UCHAR *szFunc = "_MDC_WaitOnSndReq";
int nTotalTime;
int bSendreqCom; /* Indicates if the send request is complete */
CHSTATE eChanSt;
/* Wait for send request to complete
*/
nTotalTime = 0;
bSendreqCom = FALSE;
while (MDC.nSndReqTimeout > nTotalTime && bSendreqCom == FALSE)
{
SL_Poll((ULNG) SNDREQ_SLEEP_TIME);
if (_MDC_GetChState(nChanId, &eChanSt) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc,
"No status information for channel ID %d", nChanId);
return(MDC_FAIL);
}
if(MDC.nLinkUp == FALSE)
{
Lgr(LOG_DEBUG, szFunc, "Link to daemon failed, aborting...");
return(MDC_FAIL);
}
if (eChanSt == SEND_REQUEST_COMPLETE)
bSendreqCom = TRUE;
nTotalTime += SNDREQ_SLEEP_TIME;
}
return(MDC_OK);
}
/******************************************************************************
* Function: MDC_SendRequest
* Description: Send a request to a driver
* Returns: MDC_OK or MDC_FAIL
******************************************************************************/
int MDC_SendRequest( UINT nChanId, /* I: Channel to send message on */
UCHAR *szData, /* I: Data to send */
UINT nDataLen, /* I: Length of data */
void (*DataCB) (UINT, UCHAR *, UINT))
/* I: call back function for data */
{
/* Local variables.
*/
UCHAR *szFunc = "MDC_SendRequest";
CHSTATE eCurrState; /* Current State for Channel ID */
/* If threading is enabled, then lock this function so that no other
* thread can enter.
*/
SINGLE_THREAD_LOCK
/* Check if in MDC Comms mode
*/
if (MDC.nMDCCommsMode == FALSE)
{
Lgr(LOG_DEBUG, szFunc, "Not in MDC Comms Mode");
THREAD_UNLOCK_RETURN(MDC_BADCONTEXT);
}
if (_MDC_GetChState(nChanId, &eCurrState) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc, "Cannot get status for channel %d", nChanId);
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
if (eCurrState != IDLE)
{
Lgr(LOG_DEBUG, szFunc, "Channel state not IDLE");
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
/* Store user call back function
*/
if (_MDC_SetUserCB(nChanId, DataCB) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc,
"_MDC_SetUserCB failed for Channel ID %d", nChanId);
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
if (_MDC_SetChState(nChanId, IN_SEND_REQUEST) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc, "Cannot set channel status to IDLE");
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
if (_MDC_SendPacket(nChanId, MDC_PREQ, szData, nDataLen) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc, "_MDC_SendPacket failed");
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
/* Return success to caller as getting this far without hitch is success!
*/
THREAD_UNLOCK_RETURN(MDC_OK);
}
/******************************************************************************
* Function: MDC_GetResult
* Description: Wait for all replies to a send request and then return result
* Returns: MDC_OK or MDC_FAIL
******************************************************************************/
int MDC_GetResult( UINT nChanId, /* I: Channel ID */
UCHAR **ppszErrorMsg) /* O: Associated error message */
{
/* Local variables.
*/
UCHAR *szFunc = "MDC_GetResult";
CHSTATE eChanSt;
UINT bReqResult;
/* If threading is enabled, then lock this function so that no other
* thread can enter.
*/
SINGLE_THREAD_LOCK
/* Check if in MDC Comms mode
*/
if (MDC.nMDCCommsMode == FALSE)
{
Lgr(LOG_DEBUG, szFunc, "Not in MDC Comms Mode");
THREAD_UNLOCK_RETURN(MDC_BADCONTEXT);
}
if (_MDC_GetChState(nChanId, &eChanSt) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc,
"No status information for channel ID %d", nChanId);
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
switch(eChanSt)
{
case SEND_REQUEST_COMPLETE:
break;
case IN_SEND_REQUEST:
/* Block until to Send Request Completes
*/
if(_MDC_WaitOnSndReq(nChanId) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc,
"_MDC_WaitOnSndReq failed for channel ID %d", nChanId);
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
break;
default:
Lgr(LOG_DEBUG, szFunc,
"MDC_GetResult called when in state %c on channel %d",
eChanSt, nChanId);
THREAD_UNLOCK_RETURN(MDC_FAIL);
break;
}
if (_MDC_SetChState(nChanId, IDLE) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc,
"Cannot set channel state to IDLE for channel ID %d", nChanId);
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
if (_MDC_GetSRResult(nChanId, &bReqResult) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc,
"_MDC_GetSRResult failed for channel ID %d", nChanId);
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
if (_MDC_GetNAKErrStr(nChanId, ppszErrorMsg) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc,
"_MDC_GetNAKErrStr failed for channel %d", nChanId);
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
if (bReqResult == FALSE)
THREAD_UNLOCK_RETURN(MDC_SNDREQNAK);
/* Return success to caller as getting this far without hitch is success!
*/
THREAD_UNLOCK_RETURN(MDC_OK);
}
/******************************************************************************
* Function: MDC_GetStatus
* Description: Returns a boolean that indicates whether the Send Request for
* given channel has completed.
* Returns: MDC_OK or MDC_FAIL
******************************************************************************/
int MDC_GetStatus( UINT nChanId, /* I: Channel ID */
UINT *bSndReqCom ) /* O: Indicates whether Send */
/* Request has completed */
{
UCHAR *szFunc = "MDC_GetStatus";
CHSTATE eChanSt;
/* If threading is enabled, then lock this function so that no other
* thread can enter.
*/
SINGLE_THREAD_LOCK
/* Check if in MDC Comms mode
*/
if (MDC.nMDCCommsMode == FALSE)
{
Lgr(LOG_DEBUG, szFunc, "Not in MDC Comms Mode");
THREAD_UNLOCK_RETURN(MDC_BADCONTEXT);
}
/* Call SL_Poll to process any outstanding messages
*/
SL_Poll(0);
if (_MDC_GetChState(nChanId, &eChanSt) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc,
"No status information for channel ID %d", nChanId);
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
switch(eChanSt)
{
case SEND_REQUEST_COMPLETE:
*bSndReqCom = TRUE;
break;
case IN_SEND_REQUEST:
*bSndReqCom = FALSE;
break;
default:
Lgr(LOG_DEBUG, szFunc,
"MDC_GetStatus called when in state %c on channel %d",
eChanSt, nChanId);
THREAD_UNLOCK_RETURN(MDC_FAIL);
break;
}
/* Return success to caller as getting this far without hitch is success!
*/
THREAD_UNLOCK_RETURN(MDC_OK);
}
/******************************************************************************
* Function: MDC_CreateService
* Description: Create a connection to a daemon so that service requests can be
* issued
* Returns: Channel ID, or negative error code
******************************************************************************/
int MDC_CreateService( UCHAR *szHostName, /* I: Host for connect*/
UINT *nPortNo, /* I: Port host on */
SERVICEDETAILS *serviceDet ) /* I: Service details */
{
/* Statics.
*/
static int nProcessingFlag = FALSE;
/* Local variables.
*/
ULNG lIPAddr;
UINT nServicesPortNo;
UCHAR *szFunc = "MDC_CreateService";
int nTotalTime; /* total time waiting for connection to be made */
int ChanId;
char ReplyPktType;
/* If threading is enabled, then lock this function so that no other
* thread can enter.
*/
SINGLE_THREAD_LOCK
/* Check to see that we are not in the midst of a create service. If we are,
* get out!
*/
if( nProcessingFlag == TRUE )
{
Lgr(LOG_DEBUG, szFunc, "Not allowed to issue a %s from within a %s",
szFunc, szFunc);
THREAD_UNLOCK_RETURN(MDC_BADCONTEXT);
}
/* Check if in MDC comms mode
*/
if (MDC.nMDCCommsMode != TRUE)
{
Lgr(LOG_DEBUG, szFunc, "Not in MDC Comms Mode");
THREAD_UNLOCK_RETURN(MDC_BADCONTEXT);
}
if (MDC.nPendCon == TRUE)
{
Lgr(LOG_DEBUG, szFunc, "Already an outstanding service request");
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
if (SL_GetIPaddr(szHostName, &lIPAddr) != R_OK)
{
Lgr(LOG_DEBUG, szFunc, "SL_GetIPaddr failed");
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
/* OK, we are active, so set the processing flag to avoid being clobbered.
*/
nProcessingFlag = TRUE;
/* If the port number has not been given, then look one up.
*/
if (nPortNo == NULL)
{
if (SL_GetService(DEF_SERVICENAME, &nServicesPortNo) != R_OK)
{
Lgr(LOG_DEBUG, szFunc, "SL_GetService failed");
nProcessingFlag = FALSE;
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
}
else
nServicesPortNo = *nPortNo;
if ((ChanId = SL_AddClient(nServicesPortNo, lIPAddr, szHostName,
_MDC_DataCB, _MDC_CtrlCB)) < 0)
{
Lgr(LOG_DEBUG, szFunc, "SL_AddClient failed");
nProcessingFlag = FALSE;
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
/* Create Status structure for the new Channel
*/
if (_MDC_CreateChStatus(ChanId) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc, "_MDC_CreateChStatus failed");
nProcessingFlag = FALSE;
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
MDC.nPendConChanId = (UINT) ChanId;
MDC.nPendCon = TRUE;
/* Wait for an indication that the connection has been made
*/
nTotalTime = 0;
while (MDC.nNewSrvTimeout > nTotalTime && MDC.nPendConChanId != 0)
{
SL_Poll((ULNG) CS_SLEEP_TIME);
nTotalTime += CS_SLEEP_TIME;
}
MDC.nPendCon = FALSE;
if (MDC.nPendConChanId != 0)
{
/* No connection made
*/
Lgr(LOG_DEBUG, szFunc,
"Timed out making connection to daemon at %s, port no %d",
szHostName, nServicesPortNo);
MDC.nPendConChanId = 0;
SL_DelClient((UINT) ChanId);
_MDC_DelChStatus((UINT) ChanId);
nProcessingFlag = FALSE;
THREAD_UNLOCK_RETURN(MDC_NODAEMON);
}
if (_MDC_SetChState((UINT) ChanId, IN_SERVICE_REQUEST) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc, "_MDC_SendData failed");
SL_DelClient((UINT) ChanId);
_MDC_DelChStatus((UINT) ChanId);
nProcessingFlag = FALSE;
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
/* Send service request structure to the daemon
*/
if (_MDC_SendPacket((UINT) ChanId, MDC_INIT, (UCHAR *) serviceDet,
(UINT) sizeof(SERVICEDETAILS)) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc, "_MDC_SendData failed");
SL_DelClient((UINT) ChanId);
_MDC_DelChStatus((UINT) ChanId);
nProcessingFlag = FALSE;
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
/* Get reply to service request.
*/
if (_MDC_GetSrvRqtReply((UINT) ChanId, &ReplyPktType) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc, "_MDC_GetSrvRqtReply failed");
SL_DelClient((UINT) ChanId);
_MDC_DelChStatus((UINT) ChanId);
nProcessingFlag = FALSE;
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
if (ReplyPktType == MDC_NAK)
{
Lgr(LOG_DEBUG, szFunc, "NAK reply received for service request");
SL_DelClient((UINT) ChanId);
_MDC_DelChStatus((UINT) ChanId);
nProcessingFlag = FALSE;
THREAD_UNLOCK_RETURN(MDC_SERVICENAK);
}
if (_MDC_SetChState((UINT) ChanId, IDLE) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc, "Cannot set channel status to IDLE");
SL_DelClient((UINT) ChanId);
_MDC_DelChStatus((UINT) ChanId);
nProcessingFlag = FALSE;
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
/* OK, finished processing successfully, so reset flag.
*/
nProcessingFlag = FALSE;
/* Get out, returning channel identifier of newly created service.
*/
THREAD_UNLOCK_RETURN(ChanId);
}
/******************************************************************************
* Function: MDC_SetTimeout
* Description: Function to program one of the system timeout values from the
* default to a user setting.
* Returns: MDC_OK - Setting changed.
* MDC_FAIL - Setting couldnt be changed, see error message.
******************************************************************************/
int MDC_SetTimeout( UCHAR *pszWhichTimeout, /* I: Timeout to set */
UINT nTimeoutValue, /* I: New value */
UCHAR *pszErrMsg ) /* O: Error message */
{
/* Local variables.
*/
UINT nReturn = MDC_OK;
UCHAR *szFunc = "MDC_SetTimeout";
/* If threading is enabled, then lock this function so that no other
* thread can enter.
*/
SINGLE_THREAD_LOCK
/* Simply compare the string given by the caller and match against known
* strings. If we get a match, then set the timeout value to that given.
*/
if(strcmp(pszWhichTimeout, NEW_SERVICE_TIMEOUT) == 0)
{
MDC.nNewSrvTimeout = nTimeoutValue;
} else
if(strcmp(pszWhichTimeout, SRV_REQ_TIMEOUT) == 0)
{
MDC.nSrvReqTimeout = nTimeoutValue;
} else
if(strcmp(pszWhichTimeout, SEND_REQ_TIMEOUT) == 0)
{
MDC.nSndReqTimeout = nTimeoutValue;
} else
{
nReturn = MDC_FAIL;
}
/* Exit with result code.
*/
THREAD_UNLOCK_RETURN(nReturn);
}
/******************************************************************************
* Function: MDC_CloseService
* Description: Close a service channel
* Returns: MDC_FAIL or MDC_OK or MDC_BADCONTEXT
******************************************************************************/
int MDC_CloseService( UINT nChanId ) /* I: Channel to close */
{
/* Local variables.
*/
UCHAR szTmpBuf[2];
UCHAR *szFunc = "MDC_CloseService";
/* If threading is enabled, then lock this function so that no other
* thread can enter.
*/
SINGLE_THREAD_LOCK
/* Prepare initial messages.
*/
sprintf(szTmpBuf, "%c", MDC_EXIT);
/* Check if in MDC Comms mode
*/
if (MDC.nMDCCommsMode == FALSE)
{
Lgr(LOG_DEBUG, szFunc, "Not in MDC Comms Mode");
THREAD_UNLOCK_RETURN(MDC_BADCONTEXT);
}
/* Send command to remote to initiate closedown procedures.
*/
if (SL_BlockSendData(nChanId, (UCHAR *) szTmpBuf, strlen(szTmpBuf) != R_OK))
{
Lgr(LOG_DEBUG, szFunc,
"Transmission of closedown message to client failed");
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
/* Give the UX library a slice of CPU so that it can tidy up.
SL_Poll(MAX_TERMINATE_TIME);
*/
/* Delete the channel.
*/
if (_MDC_DelChStatus(nChanId) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc, "_MDC_DelChStatus failed for Channel ID %d",
nChanId);
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
/* All done, return completion code to caller.
*/
THREAD_UNLOCK_RETURN(MDC_OK);
}
/******************************************************************************
* Function: MDC_Start
* Description: This is called to initialise the MDC Comms.
* Returns: MDC_FAIL or MDC_OK
******************************************************************************/
int MDC_Start( void )
{
/* Local variables.
*/
int ret;
UCHAR *szFunc = "MDC_Start";
/* If threading is enabled, then lock this function so that no other
* thread can enter.
*/
SINGLE_THREAD_LOCK
/* Setup logger mode.
*/
Lgr(LOG_CONFIG, LGM_STDOUT, LOG_MESSAGE, "");
if (_MDC_Init() != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc, "_MDC_Init failed");
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
/* Check if MDC Comms is already initialised
*/
if (MDC.nMDCCommsMode == TRUE)
{
Lgr(LOG_DEBUG, szFunc, "Already in MDC Comms Mode");
THREAD_UNLOCK_RETURN(MDC_BADCONTEXT);
}
/* Initialise UX comms
*/
if ((ret = SL_Init(MDC_CL_KEEPALIVE, (UCHAR *) NULL)) != R_OK)
{
Lgr(LOG_DEBUG, szFunc, "SL_Init failed");
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
/* Now in MDC Comms Mode
*/
MDC.nMDCCommsMode = TRUE;
/* Return success to caller as getting this far without hitch is success!
*/
THREAD_UNLOCK_RETURN(MDC_OK);
}
/******************************************************************************
* Function: MDC_End
* Description: This is called to shutdown the MDC Comms.
* Returns: MDC_FAIL or MDC_OK
******************************************************************************/
int MDC_End( void )
{
/* Local variables.
*/
int ret;
CHANSTATUS *spChanDet;
LINKLIST *spNext;
UCHAR *szFunc = "MDC_End";
/* If threading is enabled, then lock this function so that no other
* thread can enter.
*/
SINGLE_THREAD_LOCK
/* Check if in MDC Comms mode
*/
if (MDC.nMDCCommsMode == FALSE)
{
Lgr(LOG_DEBUG, szFunc, "Not in MDC Comms Mode");
THREAD_UNLOCK_RETURN(MDC_BADCONTEXT);
}
/* Go through all current connections and close them if they are open.
*/
for(spChanDet=(CHANSTATUS *)StartItem(MDC.spChanDetHead, &spNext);
spChanDet != NULL;
spChanDet=(CHANSTATUS *)NextItem(&spNext))
{
/* Force closure of connection.
*/
MDC_CloseService(spChanDet->nChanId);
}
/* Final MDC termination tidy up.
*/
if (_MDC_Terminate() != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc, "_SL_Terminate failed");
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
/* Shutdown UX comms
*/
if ((ret = SL_Exit((UCHAR *) NULL)) != R_OK)
{
Lgr(LOG_DEBUG, szFunc, "SL_Exit failed");
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
/* Exit MDC Comms Mode
*/
MDC.nMDCCommsMode = FALSE;
/* Return success to caller as weve got to the end without hitch.
*/
THREAD_UNLOCK_RETURN(MDC_OK);
}
/******************************************************************************
* Function: MDC_ChangeService
* Description: Change Service for an existing daemon connection
* Returns: MDC_OK, MDC_FAIL, MDC_NODAEMON, MDC_NOSERVICE, MDC_BADPARMS
******************************************************************************/
int MDC_ChangeService( UINT nChanId, /* I: Chan ID of srvc */
SERVICEDETAILS *serviceDet ) /* I: Service details */
{
/* Local variables.
*/
UCHAR *szFunc = "MDC_ChangeService";
char ReplyPktType;
CHSTATE eChanSt;
/* If threading is enabled, then lock this function so that no other
* thread can enter.
*/
SINGLE_THREAD_LOCK
/* Check if in MDC comms mode
*/
if (MDC.nMDCCommsMode != TRUE)
{
Lgr(LOG_DEBUG, szFunc, "Not in MDC Comms Mode");
THREAD_UNLOCK_RETURN(MDC_BADCONTEXT);
}
/* Check that in IDLE state on channel
*/
if (_MDC_GetChState(nChanId, &eChanSt) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc,
"No status information for channel ID %d", nChanId);
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
if (eChanSt != IDLE)
{
Lgr(LOG_DEBUG, szFunc, "Channel ID %d not in idle state", nChanId);
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
if (_MDC_SetChState(nChanId, IN_CHANGE_SERVICE) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc,
"Cannot set status to IN_CHANGE_SERVICE for channel ID %d",nChanId);
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
/* Send service request structure to the daemon.
*/
if (_MDC_SendPacket((UINT)nChanId, MDC_CHANGE, (UCHAR *) serviceDet,
(UINT) sizeof(SERVICEDETAILS)) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc, "_MDC_SendPacket failed");
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
/* Get reply to service request.
*/
if (_MDC_GetSrvRqtReply((UINT)nChanId, &ReplyPktType) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc, "_MDC_GetSrvRqtReply failed");
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
if (ReplyPktType == MDC_NAK)
{
Lgr(LOG_DEBUG, szFunc, "NAK reply received for service request");
THREAD_UNLOCK_RETURN(MDC_SERVICENAK);
}
if (_MDC_SetChState((UINT)nChanId, IDLE) != MDC_OK)
{
Lgr(LOG_DEBUG, szFunc, "Cannot set channel status to IDLE");
THREAD_UNLOCK_RETURN(MDC_FAIL);
}
/* Return new channel id, shouldnt really have changed.
*/
THREAD_UNLOCK_RETURN(nChanId);
}