/* Parse a quoted string ("-some-data") from the given position. * Leading whitespace before the first quote is skipped. During * parsing, escape sequences are detected and converted: * \\ - backslash character * \" - quote character * any other value \<somechar> is reserved for future use. * * After return, the parse pointer is paced after the trailing * quote. * * Output: * ppCStr Pointer to the parsed string - must be freed by caller and * does NOT include the quotes. * rgerhards, 2005-09-19 */ rsRetVal parsQuotedCStr(rsParsObj *pThis, cstr_t **ppCStr) { register unsigned char *pC; cstr_t *pCStr = NULL; DEFiRet; rsCHECKVALIDOBJECT(pThis, OIDrsPars); CHKiRet(parsSkipAfterChar(pThis, '"')); pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos; /* OK, we most probably can obtain a value... */ CHKiRet(cstrConstruct(&pCStr)); while(pThis->iCurrPos < cstrLen(pThis->pCStr)) { if(*pC == '"') { break; /* we are done! */ } else if(*pC == '\\') { ++pThis->iCurrPos; ++pC; if(pThis->iCurrPos < cstrLen(pThis->pCStr)) { /* in this case, we copy the escaped character * to the output buffer (but do not rely on this, * we might later introduce other things, like \007! */ CHKiRet(cstrAppendChar(pCStr, *pC)); } } else { /* regular character */ CHKiRet(cstrAppendChar(pCStr, *pC)); } ++pThis->iCurrPos; ++pC; } if(*pC == '"') { ++pThis->iCurrPos; /* 'eat' trailing quote */ } else { /* error - improperly quoted string! */ cstrDestruct(&pCStr); ABORT_FINALIZE(RS_RET_MISSING_TRAIL_QUOTE); } /* We got the string, let's finish it... */ CHKiRet(cstrFinalize(pCStr)); /* done! */ *ppCStr = pCStr; finalize_it: if(iRet != RS_RET_OK) { if(pCStr != NULL) cstrDestruct(&pCStr); } RETiRet; }
/* helper to ochAddLine. Parses a comma-delimited field * The field is delimited by SP or comma. Leading whitespace * is "eaten" and does not become part of the field content. */ static rsRetVal get_Field(uchar **pp, uchar **pField) { DEFiRet; register uchar *p; cstr_t *pStrB = NULL; assert(pp != NULL); assert(*pp != NULL); assert(pField != NULL); skip_Comma((char**)pp); p = *pp; CHKiRet(cstrConstruct(&pStrB)); /* copy the field */ while(*p && *p != ' ' && *p != ',') { CHKiRet(cstrAppendChar(pStrB, *p++)); } *pp = p; CHKiRet(cstrFinalize(pStrB)); CHKiRet(cstrConvSzStrAndDestruct(pStrB, pField, 0)); finalize_it: if(iRet != RS_RET_OK) { if(pStrB != NULL) cstrDestruct(&pStrB); } RETiRet; }
/* helper to ochAddLine. Parses everything from the * current position to the end of line and returns it * to the caller. Leading white space is removed, but * not trailing. */ static inline rsRetVal get_restOfLine(uchar **pp, uchar **pBuf) { DEFiRet; register uchar *p; cstr_t *pStrB = NULL; assert(pp != NULL); assert(*pp != NULL); assert(pBuf != NULL); skip_Comma((char**)pp); p = *pp; CHKiRet(cstrConstruct(&pStrB)); /* copy the field */ while(*p) { CHKiRet(cstrAppendChar(pStrB, *p++)); } *pp = p; CHKiRet(cstrFinalize(pStrB)); CHKiRet(cstrConvSzStrAndDestruct(pStrB, pBuf, 0)); finalize_it: if(iRet != RS_RET_OK) { if(pStrB != NULL) cstrDestruct(&pStrB); } RETiRet; }
/* Parse and a word config line option. A word is a consequtive * sequence of non-whitespace characters. pVal must be * a pointer to a string which is to receive the option * value. The returned string must be freed by the caller. * rgerhards, 2007-09-07 * To facilitate multiple instances of the same command line * directive, doGetWord() now checks if pVal is already a * non-NULL pointer. If so, we assume it was created by a previous * incarnation and is automatically freed. This happens only when * no custom handler is defined. If it is, the customer handler * must do the cleanup. I have checked and this was al also memory * leak with some code. Obviously, not a large one. -- rgerhards, 2007-12-20 * Just to clarify: if pVal is parsed to a custom handler, this handler * is responsible for freeing pVal. -- rgerhards, 2008-03-20 */ static rsRetVal doGetWord(uchar **pp, rsRetVal (*pSetHdlr)(void*, uchar*), void *pVal) { DEFiRet; cstr_t *pStrB = NULL; uchar *pNewVal; ASSERT(pp != NULL); ASSERT(*pp != NULL); CHKiRet(getWord(pp, &pStrB)); CHKiRet(cstrConvSzStrAndDestruct(&pStrB, &pNewVal, 0)); DBGPRINTF("doGetWord: get newval '%s' (len %d), hdlr %p\n", pNewVal, (int) ustrlen(pNewVal), pSetHdlr); /* we got the word, now set it */ if(pSetHdlr == NULL) { /* we should set value directly to var */ if(*((uchar**)pVal) != NULL) free(*((uchar**)pVal)); /* free previous entry */ *((uchar**)pVal) = pNewVal; /* set new one */ } else { /* we set value via a set function */ CHKiRet(pSetHdlr(pVal, pNewVal)); } skipWhiteSpace(pp); /* skip over any whitespace */ finalize_it: if(iRet != RS_RET_OK) { if(pStrB != NULL) cstrDestruct(&pStrB); } RETiRet; }
/* free the whole function registry */ static void rsfrRemoveAll(void) { rsf_entry_t *pEntry; rsf_entry_t *pEntryDel; BEGINfunc pEntry = funcRegRoot; while(pEntry != NULL) { pEntryDel = pEntry; pEntry = pEntry->pNext; cstrDestruct(&pEntryDel->pName); free(pEntryDel); } funcRegRoot = NULL; ENDfunc }
/* get all the object's countes together as CEE. */ static rsRetVal getStatsLineCEE(statsobj_t *pThis, cstr_t **ppcstr, const statsFmtType_t fmt, const int8_t bResetCtrs) { cstr_t *pcstr = NULL; ctr_t *pCtr; json_object *root, *values; int locked = 0; DEFiRet; root = values = NULL; CHKiRet(cstrConstruct(&pcstr)); if (fmt == statsFmt_CEE) CHKiRet(rsCStrAppendStrWithLen(pcstr, UCHAR_CONSTANT(CONST_CEE_COOKIE" "), CONST_LEN_CEE_COOKIE + 1)); CHKmalloc(root = json_object_new_object()); CHKiRet(addContextForReporting(root, UCHAR_CONSTANT("name"), pThis->name)); if(pThis->origin != NULL) { CHKiRet(addContextForReporting(root, UCHAR_CONSTANT("origin"), pThis->origin)); } if (pThis->reporting_ns == NULL) { values = json_object_get(root); } else { CHKmalloc(values = json_object_new_object()); json_object_object_add(root, (const char*) pThis->reporting_ns, json_object_get(values)); } /* now add all counters to this line */ pthread_mutex_lock(&pThis->mutCtr); locked = 1; for(pCtr = pThis->ctrRoot ; pCtr != NULL ; pCtr = pCtr->next) { if (fmt == statsFmt_JSON_ES) { /* work-around for broken Elasticsearch JSON implementation: * we need to replace dots by a different char, we use bang. * Note: ES 2.0 does not longer accept dot in name */ uchar esbuf[256]; strncpy((char*)esbuf, (char*)pCtr->name, sizeof(esbuf)-1); esbuf[sizeof(esbuf)-1] = '\0'; for(uchar *c = esbuf ; *c ; ++c) { if(*c == '.') *c = '!'; } CHKiRet(addCtrForReporting(values, esbuf, accumulatedValue(pCtr))); } else { CHKiRet(addCtrForReporting(values, pCtr->name, accumulatedValue(pCtr))); } resetResettableCtr(pCtr, bResetCtrs); } pthread_mutex_unlock(&pThis->mutCtr); locked = 0; CHKiRet(rsCStrAppendStr(pcstr, (const uchar*) json_object_to_json_string(root))); cstrFinalize(pcstr); *ppcstr = pcstr; pcstr = NULL; finalize_it: if(locked) { pthread_mutex_unlock(&pThis->mutCtr); } if (pcstr != NULL) { cstrDestruct(&pcstr); } if (root != NULL) { json_object_put(root); } if (values != NULL) { json_object_put(values); } RETiRet; }
rsRetVal parsAddrWithBits(rsParsObj *pThis, struct NetAddr **pIP, int *pBits) { register uchar *pC; uchar *pszIP; uchar *pszTmp; struct addrinfo hints, *res = NULL; cstr_t *pCStr; DEFiRet; rsCHECKVALIDOBJECT(pThis, OIDrsPars); assert(pIP != NULL); assert(pBits != NULL); CHKiRet(cstrConstruct(&pCStr)); parsSkipWhitespace(pThis); pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos; /* we parse everything until either '/', ',' or * whitespace. Validity will be checked down below. */ while(pThis->iCurrPos < rsCStrLen(pThis->pCStr) && *pC != '/' && *pC != ',' && !isspace((int)*pC)) { if((iRet = cstrAppendChar(pCStr, *pC)) != RS_RET_OK) { cstrDestruct (&pCStr); FINALIZE; } ++pThis->iCurrPos; ++pC; } /* We got the string, let's finish it... */ if((iRet = cstrFinalize(pCStr)) != RS_RET_OK) { cstrDestruct(&pCStr); FINALIZE; } /* now we have the string and must check/convert it to * an NetAddr structure. */ CHKiRet(cstrConvSzStrAndDestruct(pCStr, &pszIP, 0)); *pIP = calloc(1, sizeof(struct NetAddr)); if (*((char*)pszIP) == '[') { pszTmp = (uchar*)strchr ((char*)pszIP, ']'); if (pszTmp == NULL) { free (pszIP); ABORT_FINALIZE(RS_RET_INVALID_IP); } *pszTmp = '\0'; memset (&hints, 0, sizeof (struct addrinfo)); hints.ai_family = AF_INET6; # ifdef AI_ADDRCONFIG hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST; # else hints.ai_flags = AI_NUMERICHOST; # endif switch(getaddrinfo ((char*)pszIP+1, NULL, &hints, &res)) { case 0: (*pIP)->addr.NetAddr = MALLOC (res->ai_addrlen); memcpy ((*pIP)->addr.NetAddr, res->ai_addr, res->ai_addrlen); freeaddrinfo (res); break; case EAI_NONAME: F_SET((*pIP)->flags, ADDR_NAME|ADDR_PRI6); (*pIP)->addr.HostWildcard = strdup ((const char*)pszIP+1); break; default: free (pszIP); free (*pIP); ABORT_FINALIZE(RS_RET_ERR); } if(*pC == '/') { /* mask bits follow, let's parse them! */ ++pThis->iCurrPos; /* eat slash */ if((iRet = parsInt(pThis, pBits)) != RS_RET_OK) { free (pszIP); free (*pIP); FINALIZE; } /* we need to refresh pointer (changed by parsInt()) */ pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos; } else { /* no slash, so we assume a single host (/128) */ *pBits = 128; } } else { /* now parse IPv4 */ memset (&hints, 0, sizeof (struct addrinfo)); hints.ai_family = AF_INET; # ifdef AI_ADDRCONFIG hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST; # else hints.ai_flags = AI_NUMERICHOST; # endif switch(getaddrinfo ((char*)pszIP, NULL, &hints, &res)) { case 0: (*pIP)->addr.NetAddr = MALLOC (res->ai_addrlen); memcpy ((*pIP)->addr.NetAddr, res->ai_addr, res->ai_addrlen); freeaddrinfo (res); break; case EAI_NONAME: F_SET((*pIP)->flags, ADDR_NAME); (*pIP)->addr.HostWildcard = strdup ((const char*)pszIP); break; default: free (pszIP); free (*pIP); ABORT_FINALIZE(RS_RET_ERR); } if(*pC == '/') { /* mask bits follow, let's parse them! */ ++pThis->iCurrPos; /* eat slash */ if((iRet = parsInt(pThis, pBits)) != RS_RET_OK) { free (pszIP); free (*pIP); FINALIZE; } /* we need to refresh pointer (changed by parsInt()) */ pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos; } else { /* no slash, so we assume a single host (/32) */ *pBits = 32; } } free(pszIP); /* no longer needed */ /* skip to next processable character */ while(pThis->iCurrPos < rsCStrLen(pThis->pCStr) && (*pC == ',' || isspace((int)*pC))) { ++pThis->iCurrPos; ++pC; } iRet = RS_RET_OK; finalize_it: RETiRet; }