diff --git a/Scommon.h b/Scommon.h index 6b466d14..bf7da342 100644 --- a/Scommon.h +++ b/Scommon.h @@ -50,7 +50,9 @@ typedef enum { eFinish, eEvent, eWarning, - eError + eError, + eHdbValue, + eHdbEvent } OutCode; #include "interrupt.h" diff --git a/makefile_linux b/makefile_linux index bb656195..33944cd7 100644 --- a/makefile_linux +++ b/makefile_linux @@ -26,7 +26,7 @@ SUBLIBS = psi/libpsi.a psi/hardsup/libhlib.a matrix/libmatrix.a \ LIBS = -L$(HDFROOT)/lib $(SUBLIBS) $(NILIB)\ -ltcl8.4 -lmxml $(HDFROOT)/lib/libhdf5.a \ $(HDFROOT)/lib/libmfhdf.a $(HDFROOT)/lib/libdf.a \ - -lmxml -lghttp -ljpeg -ldl -lz -lsz -lm -lc + -lmxml -lghttp -ljpeg -ljson -ldl -lz -lsz -lm -lc include make_gen diff --git a/matrix/libmatrix.a b/matrix/libmatrix.a new file mode 100644 index 00000000..6107b71c Binary files /dev/null and b/matrix/libmatrix.a differ diff --git a/protocol.c b/protocol.c index 22b2e97e..8c006ac4 100644 --- a/protocol.c +++ b/protocol.c @@ -16,11 +16,13 @@ #include #include "commandlog.h" #include "protocol.h" +#include #define MAXMSG 1024 #define INIT_STR_SIZE 256 #define STR_RESIZE_LENGTH 256 - +#define NUMPROS 5 +#define PROLISTLEN 6 typedef struct __Protocol { pObjectDescriptor pDes; /* required as first field */ char *name; /* protocol handler name */ @@ -28,7 +30,7 @@ typedef struct __Protocol { int iNumPros; /* number of valid protocols? */ writeFunc defaultWriter; /* default write function */ int isDefaultSet; - char *pProList[5]; /* list of valid protocols? */ + char *pProList[PROLISTLEN]; /* list of valid protocols? */ } Protocol; char *pEventType[]={ @@ -85,8 +87,6 @@ pProtocol CreateProtocol(void); static int ProtocolOptions(SConnection* pCon, pProtocol pPro); static int ProtocolHelp(SConnection* pCon, Protocol* pPro); static int ProtocolSet(SConnection* pCon, Protocol* pPro, char *pProName); -static int ProtocolGet(SConnection* pCon, Protocol* pPro, char *pProName, - int *pIndex); static int ProtocolList(SConnection* pCon, Protocol* pPro); int ProtocolAction(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]); @@ -95,15 +95,17 @@ static int InitDefaultProtocol(SConnection* pCon, Protocol *pPro); /* Signatures for protocol writers implemented in this file */ int SCWriteSycamore(SConnection *pCon, char *pBuffer, int iOut); +int SCWriteJSON_String(SConnection *pCon, char *pBuffer, int iOut); /*--------------------------------------------------------------------------*/ pProtocol CreateProtocol(void) { - int i, iNumPros = 4; - char *pPros[5] = {"default", + int i, iNumPros = NUMPROS; + char *pPros[] = {"default", "normal", "withcode", "sycamore", + "json", NULL }; pProtocol pNew = NULL; @@ -276,7 +278,9 @@ static int ProtocolSet(SConnection* pCon, Protocol* pPro, char *pProName) case 3: /* sycamore */ SCSetWriteFunc(pCon,SCWriteSycamore); break; - + case 4: /* json */ + SCSetWriteFunc(pCon,SCWriteJSON_String); + break; case 0: /* default = psi_sics */ default: SCSetWriteFunc(pCon,pPro->defaultWriter); @@ -288,9 +292,10 @@ static int ProtocolSet(SConnection* pCon, Protocol* pPro, char *pProName) } /*------------------------------------------------------------------------*/ -static int ProtocolGet(SConnection* pCon, Protocol* pPro, char *pProName, - int *pIndex) +int ProtocolGet(SConnection* pCon, void* pData, char *pProName, int len) { + int Index; + Protocol *pPro = (Protocol *)pData; if(!SCVerifyConnection(pCon)) { return 0; @@ -303,24 +308,27 @@ static int ProtocolGet(SConnection* pCon, Protocol* pPro, char *pProName, pPro->isDefaultSet = 1; pCon->iProtocolID = 0; } - - *pIndex = (int)malloc(sizeof(int)); - *pIndex = pCon->iProtocolID; + strncpy(pProName, pPro->pProList[pCon->iProtocolID], len); + return 1; +#if 0 + Index = pCon->iProtocolID; /* check list of protocols for valid name */ - switch(*pIndex) + switch(Index) { case 0: /* default = psi_sics */ case 1: /* normal (connection start default) */ case 2: /* outcodes */ case 3: /* sycamore */ - pProName = strdup(pPro->pProList[*pIndex]); + case 4: /* json */ + pProName = pPro->pProList[Index]; return 1; break; default: return 0; break; } +#endif } /*------------------------------------------------------------------------*/ @@ -351,10 +359,10 @@ int ProtocolAction(SConnection *pCon, SicsInterp *pSics, void *pData, {NULL} }; - assert(pCon); - assert(pSics); + assert(pCon != NULL); + assert(pSics != NULL); pPro = (pProtocol)pData; - assert(pPro); + assert(pPro != NULL); /* You need to have User level access rights to use this facility */ if(!SCMatchRights(pCon,usSpy)) @@ -427,8 +435,6 @@ static int InitDefaultProtocol(SConnection* pCon, Protocol *pPro) } /*---------------------------------------------------------------------*/ void sycformat(char *tag, OutCode msgFlag, pDynString msgString, pDynString msgOut) { - char typePrefix[] = "type."; - char statusPrefix[] = "status."; DynStringConcat(msgOut," "); switch (msgFlag) { eEvent: @@ -445,19 +451,13 @@ void sycformat(char *tag, OutCode msgFlag, pDynString msgString, pDynString msgO } int SCWriteSycamore(SConnection *pCon, char *pBuffer, int iOut) { - int i, iPtr, iRet; - int bDevIDdone = 0; - int bFlagDone = 0; + int iRet; char pBueffel[MAXMSG], *pBufferFrom, *pBufferTo; long taskID = 0; /* char pPrefix[40];*/ pDynString pMsg = NULL; pDynString pMsgString = NULL; - SicsInterp *pSics; - TokenList *pList = NULL; - TokenList *pCurrent; commandContext comCon; - char *savedTclResult = NULL; if (strlen(pBuffer) == 0) { @@ -517,11 +517,6 @@ int SCWriteSycamore(SConnection *pCon, char *pBuffer, int iOut) return 0; } - /* - build the Tcl-command to execute for formatting the - data into a sycamore string - */ - pSics = GetInterpreter(); taskID = comCon.transID; pMsg = CreateDynString(INIT_STR_SIZE, STR_RESIZE_LENGTH); @@ -552,9 +547,14 @@ int SCWriteSycamore(SConnection *pCon, char *pBuffer, int iOut) if (iOut == eEvent) { DynStringConcat(pMsgString, " type="); - DynStringConcat(pMsgString, pEventType[pCon->conEventType]); + /* Default type to VALUECHANGE if conEventType not set */ + if (-1 == pCon->conEventType) + DynStringConcat(pMsgString, pEventType[0]); + else + DynStringConcat(pMsgString, pEventType[pCon->conEventType]); /* DynStringConcat(pMsgString, " status="); DynStringConcat(pMsgString, pStatus[pCon->conStatus]);*/ + DynStringConcat(pMsgString,","); } DynStringConcat(pMsgString," "); DynStringConcat(pMsgString,pBuffer); @@ -577,6 +577,163 @@ int SCWriteSycamore(SConnection *pCon, char *pBuffer, int iOut) return 1; } +/* Only work for hipadaba commands, hlist, hset, hget, hnotify + * A multiline string (ie have crnl) will be converted to an array. + * Strings with '=' will be converted to name value pairs + */ +struct json_object *mkJSON_Object(SConnection *pCon, char *pBuffer, int iOut) +{ + int linenum = __LINE__; + char pBueffel[MAXMSG], *pBufferFrom, *pBufferTo; + long taskID = 0; + struct json_object *msg_json=NULL, *tmp_json=NULL; + + commandContext comCon; + char pError[256]; + pError[0]='\0'; + + + if (strlen(pBuffer) == 0) { + return 0; + } + + if(!SCVerifyConnection(pCon)) + { + return 0; + } + comCon = SCGetContext(pCon); + + /* Return 0 without dying if no message data */ + if(pBuffer == NULL) + { + return 0; + } + + /* + build the Tcl-command to execute for formatting the + data into a sycamore string + */ + taskID = comCon.transID; + + pBueffel[0] = '\0'; + msg_json = json_object_new_object(); + if (is_error(msg_json)) { linenum = __LINE__; goto reporterr; } +/* field 1: connID */ + json_object_object_add(msg_json, "con", json_object_new_int(pCon->ident)); +/* field 2: taskID */ + json_object_object_add(msg_json, "trans", json_object_new_int(taskID)); + /* deviceID */ + json_object_object_add(msg_json, "object", json_object_new_string(comCon.deviceID)); + + /* msgFlag */ + switch(iOut) { + case 5: /* eValue */ + json_object_object_add(msg_json, "flag", json_object_new_string("out")); + break; + default: + json_object_object_add(msg_json, "flag", json_object_new_string(pCode[iOut])); + break; + } + if (iOut == eHdbValue || iOut == eHdbEvent) { + tmp_json = json_tokener_parse(pBuffer); + if (is_error(tmp_json)) { linenum = __LINE__; goto reporterr; } + } else { + /* Strip \r and \n */ + for (pBufferFrom=pBufferTo=pBuffer; ; pBufferFrom++) { + if (*pBufferFrom == '\r' || *pBufferFrom == '\n') + continue; + pBufferTo = pBufferFrom; + if (*pBufferTo == '\0') + break; + pBufferTo++; + } + tmp_json = json_object_new_string(pBuffer); + if (is_error(tmp_json)) { linenum = __LINE__; goto reporterr; } + } + json_object_object_add(msg_json, "data", tmp_json); + return msg_json; + +reporterr: + SCSetWriteFunc(pCon,SCNormalWrite); + snprintf(pError, 256,"{\"ERROR\": \"%s:%d Error making json object\"}", __FILE__, linenum); + SCWrite(pCon,pError,eError); + SCSetWriteFunc(pCon,SCWriteJSON_String); +cleanup: + if (tmp_json != NULL && !is_error(tmp_json)) + json_object_put(tmp_json); + if (msg_json != NULL && !is_error(msg_json)) + json_object_put(msg_json); + return NULL; +} + +int SCWriteJSON_String(SConnection *pCon, char *pBuffer, int iOut) +{ + struct json_object *my_object=NULL, *tmp_json=NULL; + char pBueffel[MAXMSG], errBuff[MAXMSG]; + int iRet, errLen = MAXMSG; + + if (strlen(pBuffer) == 0) + return 1; + + /* log it for any case */ + if(pCon->pSock) + { + iRet = pCon->pSock->sockid; + } + else + { + iRet = 0; + } + sprintf(pBueffel,"Next line intended for socket: %d",iRet); + SICSLogWrite(pBueffel,eInternal); + SICSLogWrite(pBuffer,iOut); + + /* write to commandlog if user or manager privilege */ + if(SCGetRights(pCon) <= usUser) + { + if(pCon->iMacro != 1) + { + sprintf(pBueffel,"To sock %d :",iRet); + WriteToCommandLog(pBueffel,pBuffer); + } + else + { + if(iOut == eError || iOut == eWarning) + { + sprintf(pBueffel,"To sock %d :",iRet); + WriteToCommandLog(pBueffel,pBuffer); + } + } + } + + if(SCinMacro(pCon)) + { + InterpWrite(pServ->pSics,pBuffer); + /* print it to client if error message */ + if((iOut== eError) || (iOut == eWarning) ) + { + tmp_json = json_object_new_string(pBuffer); + iRet = SCDoSockWrite(pCon,json_object_to_json_string(tmp_json)); + } + } else { + if ((my_object = mkJSON_Object(pCon, pBuffer, iOut)) == NULL) { + snprintf(errBuff, errLen, "failed to make JSON object from, %s", pBuffer); + tmp_json = json_object_new_string(errBuff); + my_object = json_object_new_object(); + json_object_object_add(my_object, "ERROR", tmp_json); + SCDoSockWrite(pCon,json_object_to_json_string(my_object)); + iRet = 0; + } else { + iRet = SCDoSockWrite(pCon,json_object_to_json_string(my_object)); + SCWriteToLogFiles(pCon,pBuffer); + } + } + if (tmp_json != NULL && !is_error(tmp_json)) + json_object_put(tmp_json); + if (my_object != NULL && !is_error(my_object)) + json_object_put(my_object); + return iRet; +} /*------------------------------------------------------------------------*/ /* Protocol API */ char * GetProtocolName(SConnection* pCon) @@ -604,6 +761,7 @@ char * GetProtocolName(SConnection* pCon) case 1: /* normal (connection start default) */ case 2: /* outcodes */ case 3: /* sycamore */ + case 4: /* json */ return strdup(pPro->pProList[pCon->iProtocolID]); break; default: diff --git a/protocol.h b/protocol.h index c3b8c585..ff00e813 100644 --- a/protocol.h +++ b/protocol.h @@ -30,5 +30,6 @@ int SCWriteSycamore(SConnection *pCon, char *pBuffer, int iOut); /*--------------------- implement protocol API -----------------------*/ char * GetProtocolName(SConnection *pCon); int GetProtocolID(SConnection *pCon); +int ProtocolGet(SConnection* pCon, void* pData, char *pProName, int len); /*-----------------------------------------------------------------------*/ #endif diff --git a/sicshipadaba.c b/sicshipadaba.c index 8fad3f76..2a1897d6 100644 --- a/sicshipadaba.c +++ b/sicshipadaba.c @@ -23,6 +23,7 @@ #include "sicspoll.h" #include #include +#include "protocol.h" /*== there can be only hipadaba in SICS, some globals to care for that == */ static pHdb root = NULL; @@ -147,6 +148,53 @@ typedef struct { SConnection *pCon; commandContext context; }HdbCBInfo; + +static int isJSON(SConnection *pCon) { + char proName[128]; + void *pData; + + if(SCinMacro(pCon)){ + return 0; + } + pData = FindCommandData(pServ->pSics, "protocol","Protocol"); + ProtocolGet(pCon, pData, proName, 128); + if (strcmp(proName, "json") == 0) + return 1; + else + return 0; +} + +int formatNameValue(int jsonSet, char *name, char *value, pDynString result) { + if (name == NULL) { + if (jsonSet) { + } else { + } + } else if (value == NULL) { + if (jsonSet) { + DynStringInsert(result,"\": ", 0); + DynStringInsert(result,name,0); + DynStringInsert(result,"{\"", 0); + DynStringConcat(result,"}"); + } else { + DynStringInsert(result," =",0); + DynStringInsert(result,name,0); + } + } else { + if (jsonSet) { + DynStringCopy(result,"{\""); + DynStringConcat(result,name); + DynStringConcat(result,"\": "); + DynStringConcat(result,value); + DynStringConcat(result,"}"); + } else { + DynStringCopy(result,name); + DynStringConcat(result," = "); + DynStringConcat(result,value); + } + } + return jsonSet; +} + /*----------------------------------------------------------------------------------------*/ static int SICSNotifyCallback(void *userData, void *callData, pHdb node, hdbValue v){ @@ -154,10 +202,16 @@ static int SICSNotifyCallback(void *userData, void *callData, pHdb node, pDynString printedData = NULL; pDynString result = NULL; char *pPath = NULL; + int protocol = 0, outCode; cbInfo = (HdbCBInfo *)userData; pPath = GetHipadabaPath(node); result = CreateDynString(128,128); + if ((protocol = isJSON(cbInfo->pCon)) == 1) + outCode = eHdbEvent; + else + outCode = eEvent; + if(v.arrayLength < 100){ printedData = formatValue(v); if(pPath == NULL || printedData == NULL || result == NULL){ @@ -169,17 +223,14 @@ static int SICSNotifyCallback(void *userData, void *callData, pHdb node, */ return 1; } - DynStringCopy(result,pPath); - DynStringConcat(result," = "); - DynStringConcat(result,GetCharArray(printedData)); + formatNameValue(protocol, pPath, GetCharArray(printedData), result); SCWriteInContext(cbInfo->pCon,GetCharArray(result), - eEvent,cbInfo->context); + outCode,cbInfo->context); DeleteDynString(printedData); } else { - DynStringCopy(result,"!!datachange!! = "); - DynStringConcat(result,pPath); + formatNameValue(protocol,"!!datachange!!", pPath, result); SCWriteInContext(cbInfo->pCon,GetCharArray(result), - eEvent,cbInfo->context); + outCode,cbInfo->context); } free(pPath); DeleteDynString(result); @@ -203,12 +254,21 @@ static int TreeChangeCallback(void *userData, void *callData, pHdb node, hdbValue v){ char *path = NULL; char buffer[1024]; + pDynString result = NULL; + int protocol = 0, outCode; + + result = CreateDynString(128,128); HdbCBInfo *cbInfo = (HdbCBInfo *)userData; if(cbInfo != NULL && cbInfo->pCon != NULL){ path = GetHipadabaPath(node); - snprintf(buffer,1023,"treechange = %s", path); - SCWriteInContext(cbInfo->pCon,buffer,eEvent,cbInfo->context); + if ((protocol = isJSON(cbInfo->pCon)) == 1) + outCode = eHdbEvent; + else + outCode = eEvent; + formatNameValue(protocol, "treechange", path, result); + SCWriteInContext(cbInfo->pCon,GetCharArray(result),outCode,cbInfo->context); + DeleteDynString(result); free(path); } return 1; @@ -1668,6 +1728,7 @@ static int GetHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, pDynString parData = NULL; char error[512], oriPath[512];; int i, status; + int protocol = 0, outCode; if(argc < 2) { SCWrite(pCon,"ERROR: need path to node to print",eError); @@ -1686,9 +1747,13 @@ static int GetHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, SCWrite(pCon,"ERROR: out of memory formatting data",eError); return 0; } - DynStringInsert(parData," =",0); - DynStringInsert(parData,oriPath,0); - SCWrite(pCon,GetCharArray(parData),eValue); + if ((protocol = isJSON(pCon)) == 1) + outCode = eHdbEvent; + else + outCode = eEvent; + + formatNameValue(protocol, oriPath, NULL, parData); + SCWrite(pCon,GetCharArray(parData),outCode); DeleteDynString(parData); ReleaseHdbValue(&newValue); @@ -1811,7 +1876,7 @@ static int HdbNodeVal(SConnection *pCon, SicsInterp *pSics, void *pData, SCWrite(pCon,"ERROR: out of memory formatting data",eError); return 0; } - SCWrite(pCon,GetCharArray(parData),eValue); + SCWrite(pCon,GetCharArray(parData),eHdbValue); DeleteDynString(parData); ReleaseHdbValue(&newValue); @@ -1850,6 +1915,47 @@ static pDynString formatPlainList(pHdb node){ return result; } /*---------------------------------------------------------------------------*/ +static pDynString formatJSONList(pHdb node){ + pHdb current; + pDynString result = NULL; + pDynString data = NULL; + + if (node->child == NULL) return NULL; + result = CreateDynString(128,128); + if(result == NULL){ + return NULL; + } + + if(node->child->value.dataType == HIPNONE) + DynStringCopy(result,"["); + else + DynStringCopy(result,"{"); + + current = node->child; + while(current != NULL){ + DynStringConcat(result,"\""); + DynStringConcat(result,current->name); + DynStringConcat(result,"\""); + if(current->value.dataType != HIPNONE){ + data = formatValue(current->value); + if(data != NULL){ + DynStringConcat(result,": "); + DynStringConcat(result,GetCharArray(data)); + DeleteDynString(data); + } + } + if (current->next != NULL) DynStringConcat(result,", "); + current = current->next; + } + + if(node->child->value.dataType == HIPNONE) + DynStringConcat(result,"]"); + else + DynStringConcat(result,"}"); + + return result; +} +/*---------------------------------------------------------------------------*/ static pDynString formatListWithVal(pHdb node){ pHdb current; pDynString result = NULL; @@ -1952,6 +2058,7 @@ static int ListHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, pHdb node = NULL; int pathArg = 1; pDynString listData = NULL; + int protocol = 0, outCode; if(argc < 2) { SCWrite(pCon,"ERROR: need path to node to print",eError); @@ -1979,14 +2086,24 @@ static int ListHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, } else if(strcmp(argv[1],"-cli") == 0){ listData = formatClientList(node); } else { + if ((protocol = isJSON(pCon)) == 1) { + listData = formatJSONList(node); + outCode = eHdbEvent; + } else { listData = formatPlainList(node); + outCode = eEvent; + } } if(listData == NULL){ SCWrite(pCon,"ERROR: failed to format list", eError); return 0; } - SCWrite(pCon,GetCharArray(listData),eValue); + if( (strcmp(argv[1],"-val") == 0) || (strcmp(argv[1],"-cli") == 0) ){ + SCWrite(pCon,GetCharArray(listData),eValue); + } else { + SCWrite(pCon,GetCharArray(listData),outCode); + } DeleteDynString(listData); return 1; }