static inline rsRetVal addEntry(struct sockaddr_storage *addr, dnscache_entry_t **pEtry) { int r; struct sockaddr_storage *keybuf; dnscache_entry_t *etry = NULL; DEFiRet; CHKmalloc(etry = MALLOC(sizeof(dnscache_entry_t))); CHKiRet(resolveAddr(addr, etry)); memcpy(&etry->addr, addr, SALEN((struct sockaddr*) addr)); etry->nUsed = 0; *pEtry = etry; CHKmalloc(keybuf = malloc(sizeof(struct sockaddr_storage))); memcpy(keybuf, addr, sizeof(struct sockaddr_storage)); pthread_rwlock_unlock(&dnsCache.rwlock); /* release read lock */ pthread_rwlock_wrlock(&dnsCache.rwlock); /* and re-aquire for writing */ r = hashtable_insert(dnsCache.ht, keybuf, *pEtry); if(r == 0) { DBGPRINTF("dnscache: inserting element failed\n"); } pthread_rwlock_unlock(&dnsCache.rwlock); pthread_rwlock_rdlock(&dnsCache.rwlock); /* we need this again */ finalize_it: if(iRet != RS_RET_OK && etry != NULL) { /* Note: sub-fields cannot be populated in this case */ free(etry); } RETiRet; }
addEntry(struct sockaddr_storage *const addr, dnscache_entry_t **const pEtry) { int r; dnscache_entry_t *etry = NULL; DEFiRet; /* entry still does not exist, so add it */ struct sockaddr_storage *const keybuf = malloc(sizeof(struct sockaddr_storage)); CHKmalloc(keybuf); CHKmalloc(etry = malloc(sizeof(dnscache_entry_t))); resolveAddr(addr, etry); assert(etry != NULL); memcpy(&etry->addr, addr, SALEN((struct sockaddr*) addr)); etry->nUsed = 0; if(dnscacheEnableTTL) { etry->validUntil = time(NULL) + dnscacheDefaultTTL; } memcpy(keybuf, addr, sizeof(struct sockaddr_storage)); r = hashtable_insert(dnsCache.ht, keybuf, etry); if(r == 0) { DBGPRINTF("dnscache: inserting element failed\n"); } *pEtry = etry; finalize_it: if(iRet != RS_RET_OK) { free(keybuf); } RETiRet; }
/* add a counter to an object * ctrName is duplicated, caller must free it if requried * NOTE: The counter is READ-ONLY and MUST NOT be modified (most * importantly, it must not be initialized, so the caller must * ensure the counter is properly initialized before AddCounter() * is called. */ static rsRetVal addCounter(statsobj_t *pThis, uchar *ctrName, statsCtrType_t ctrType, int8_t flags, void *pCtr) { ctr_t *ctr; DEFiRet; CHKmalloc(ctr = malloc(sizeof(ctr_t))); ctr->next = NULL; ctr->prev = NULL; CHKmalloc(ctr->name = ustrdup(ctrName)); ctr->flags = flags; ctr->ctrType = ctrType; switch(ctrType) { case ctrType_IntCtr: ctr->val.pIntCtr = (intctr_t*) pCtr; break; case ctrType_Int: ctr->val.pInt = (int*) pCtr; break; } addCtrToList(pThis, ctr); finalize_it: RETiRet; }
/* create a new lookup table object AND include it in our list of * lookup tables. */ rsRetVal lookupNew(lookup_ref_t **ppThis) { lookup_ref_t *pThis = NULL; lookup_t *t = NULL; DEFiRet; CHKmalloc(pThis = calloc(1, sizeof(lookup_ref_t))); CHKmalloc(t = calloc(1, sizeof(lookup_t))); pthread_rwlock_init(&pThis->rwlock, NULL); pthread_mutex_init(&pThis->reloader_mut, NULL); pthread_cond_init(&pThis->run_reloader, NULL); pthread_attr_init(&pThis->reloader_thd_attr); pThis->do_reload = pThis->do_stop = 0; pThis->reload_on_hup = 1; /*DO reload on HUP (default)*/ pthread_create(&pThis->reloader, &pThis->reloader_thd_attr, lookupTableReloader, pThis); pThis->next = NULL; if(loadConf->lu_tabs.root == NULL) { loadConf->lu_tabs.root = pThis; } else { loadConf->lu_tabs.last->next = pThis; } loadConf->lu_tabs.last = pThis; pThis->self = t; *ppThis = pThis; finalize_it: if(iRet != RS_RET_OK) { free(t); free(pThis); } RETiRet; }
/* this reloads a lookup table. This is done while the engine is running, * as such the function must ensure proper locking and proper order of * operations (so that nothing can interfere). If the table cannot be loaded, * the old table is continued to be used. */ static rsRetVal lookupReload(lookup_t *pThis) { uint32_t i; lookup_t newlu; /* dummy to be able to use support functions without affecting current settings. */ DEFiRet; DBGPRINTF("reload requested for lookup table '%s'\n", pThis->name); memset(&newlu, 0, sizeof(newlu)); CHKmalloc(newlu.name = ustrdup(pThis->name)); CHKmalloc(newlu.filename = ustrdup(pThis->filename)); CHKiRet(lookupReadFile(&newlu)); /* all went well, copy over data members */ pthread_rwlock_wrlock(&pThis->rwlock); for(i = 0 ; i < pThis->nmemb ; ++i) { free(pThis->d.strtab[i].key), /* we don't care about exec order of frees */ free(pThis->d.strtab[i].val); } free(pThis->d.strtab); pThis->d.strtab = newlu.d.strtab; /* hand table AND ALL STRINGS over! */ pthread_rwlock_unlock(&pThis->rwlock); errmsg.LogError(0, RS_RET_OK, "lookup table '%s' reloaded from file '%s'", pThis->name, pThis->filename); finalize_it: free(newlu.name); free(newlu.filename); RETiRet; }
/* ConstructionFinalizer */ static rsRetVal tcpsrvConstructFinalize(tcpsrv_t *pThis) { DEFiRet; ISOBJ_TYPE_assert(pThis, tcpsrv); /* prepare network stream subsystem */ CHKiRet(netstrms.Construct(&pThis->pNS)); if(pThis->pszDrvrName != NULL) CHKiRet(netstrms.SetDrvrName(pThis->pNS, pThis->pszDrvrName)); CHKiRet(netstrms.SetDrvrMode(pThis->pNS, pThis->iDrvrMode)); if(pThis->pszDrvrAuthMode != NULL) CHKiRet(netstrms.SetDrvrAuthMode(pThis->pNS, pThis->pszDrvrAuthMode)); if(pThis->pPermPeers != NULL) CHKiRet(netstrms.SetDrvrPermPeers(pThis->pNS, pThis->pPermPeers)); CHKiRet(netstrms.ConstructFinalize(pThis->pNS)); /* set up listeners */ CHKmalloc(pThis->ppLstn = calloc(pThis->iLstnMax, sizeof(netstrm_t*))); CHKmalloc(pThis->ppLstnPort = calloc(pThis->iLstnMax, sizeof(tcpLstnPortList_t*))); iRet = pThis->OpenLstnSocks(pThis); finalize_it: if(iRet != RS_RET_OK) { if(pThis->pNS != NULL) netstrms.Destruct(&pThis->pNS); errmsg.LogError(0, iRet, "tcpsrv could not create listener (inputname: '%s')", (pThis->pszInputName == NULL) ? (uchar*)"*UNSET*" : pThis->pszInputName); } RETiRet; }
/* get the name of the local host. A pointer to a character pointer is passed * in, which on exit points to the local hostname. This buffer is dynamically * allocated and must be free()ed by the caller. If the functions returns an * error, the pointer is NULL. This function is based on GNU/Hurd's localhostname * function. * rgerhards, 20080-04-10 */ static rsRetVal getLocalHostname(uchar **ppName) { DEFiRet; uchar *buf = NULL; size_t buf_len = 0; assert(ppName != NULL); do { if(buf == NULL) { buf_len = 128; /* Initial guess */ CHKmalloc(buf = MALLOC(buf_len)); } else { uchar *p; buf_len += buf_len; CHKmalloc(p = realloc (buf, buf_len)); buf = p; } } while((gethostname((char*)buf, buf_len) == 0 && !memchr (buf, '\0', buf_len)) || errno == ENAMETOOLONG); *ppName = buf; buf = NULL; finalize_it: if(iRet != RS_RET_OK) { if(buf != NULL) free(buf); } RETiRet; }
/* get the name of the local host. A pointer to a character pointer is passed * in, which on exit points to the local hostname. This buffer is dynamically * allocated and must be free()ed by the caller. If the functions returns an * error, the pointer is NULL. * This function always tries to return a FQDN, even so be quering DNS. So it * is safe to assume for the caller that when the function does not return * a FQDN, it simply is not available. The domain part of that string is * normalized to lower case. The hostname is kept in mixed case for historic * reasons. */ static rsRetVal getLocalHostname(uchar **ppName) { DEFiRet; char hnbuf[8192]; uchar *fqdn = NULL; if(gethostname(hnbuf, sizeof(hnbuf)) != 0) { strcpy(hnbuf, "localhost"); } else { hnbuf[sizeof(hnbuf)-1] = '\0'; /* be on the safe side... */ } char *dot = strstr(hnbuf, "."); if(dot == NULL) { /* we need to (try) to find the real name via resolver */ struct hostent *hent = gethostbyname((char*)hnbuf); if(hent) { int i = 0; if(hent->h_aliases) { const size_t hnlen = strlen(hnbuf); for(i = 0; hent->h_aliases[i]; i++) { if(!strncmp(hent->h_aliases[i], hnbuf, hnlen) && hent->h_aliases[i][hnlen] == '.') { break; /* match! */ } } } if(hent->h_aliases && hent->h_aliases[i]) { CHKmalloc(fqdn = (uchar*)strdup(hent->h_aliases[i])); } else { CHKmalloc(fqdn = (uchar*)strdup(hent->h_name)); } dot = strstr((char*)fqdn, "."); } } if(fqdn == NULL) { /* already was FQDN or we could not obtain a better one */ CHKmalloc(fqdn = (uchar*) strdup(hnbuf)); } if(dot != NULL) for(char *p = dot+1 ; *p ; ++p) *p = tolower(*p); *ppName = fqdn; finalize_it: RETiRet; }
/* add new listener port to listener port list * rgerhards, 2009-05-21 */ static inline rsRetVal addNewLstnPort(tcpsrv_t *pThis, uchar *pszPort, int bSuppOctetFram, uchar *pszAddr) { tcpLstnPortList_t *pEntry; uchar statname[64]; DEFiRet; ISOBJ_TYPE_assert(pThis, tcpsrv); /* create entry */ CHKmalloc(pEntry = MALLOC(sizeof(tcpLstnPortList_t))); CHKmalloc(pEntry->pszPort = ustrdup(pszPort)); pEntry->pszAddr = NULL; // Initalize address to null /* only if a bind adress is defined copy it in struct */ if (pszAddr != NULL) CHKmalloc(pEntry->pszAddr = ustrdup(pszAddr)); strcpy((char*)pEntry->dfltTZ, (char*)pThis->dfltTZ); pEntry->bSPFramingFix = pThis->bSPFramingFix; pEntry->pSrv = pThis; pEntry->pRuleset = pThis->pRuleset; pEntry->bSuppOctetFram = bSuppOctetFram; /* we need to create a property */ CHKiRet(prop.Construct(&pEntry->pInputName)); CHKiRet(prop.SetString(pEntry->pInputName, pThis->pszInputName, ustrlen(pThis->pszInputName))); CHKiRet(prop.ConstructFinalize(pEntry->pInputName)); /* and add to list */ pEntry->pNext = pThis->pLstnPorts; pThis->pLstnPorts = pEntry; /* support statistics gathering */ CHKiRet(statsobj.Construct(&(pEntry->stats))); snprintf((char*)statname, sizeof(statname), "%s(%s)", pThis->pszInputName, pszPort); statname[sizeof(statname)-1] = '\0'; /* just to be on the save side... */ CHKiRet(statsobj.SetName(pEntry->stats, statname)); CHKiRet(statsobj.SetOrigin(pEntry->stats, pThis->pszOrigin)); CHKiRet(ratelimitNew(&pEntry->ratelimiter, "tcperver", NULL)); ratelimitSetLinuxLike(pEntry->ratelimiter, pThis->ratelimitInterval, pThis->ratelimitBurst); ratelimitSetThreadSafe(pEntry->ratelimiter); STATSCOUNTER_INIT(pEntry->ctrSubmit, pEntry->mutCtrSubmit); CHKiRet(statsobj.AddCounter(pEntry->stats, UCHAR_CONSTANT("submitted"), ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pEntry->ctrSubmit))); CHKiRet(statsobj.ConstructFinalize(pEntry->stats)); finalize_it: RETiRet; }
/* extract a groupname and return its gid. * rgerhards, 2007-07-17 */ static rsRetVal doGetGID(uchar **pp, rsRetVal (*pSetHdlr)(void*, uid_t), void *pVal) { struct group *pgBuf = NULL; struct group gBuf; DEFiRet; uchar szName[256]; int bufSize = 2048; char * stringBuf = NULL; assert(pp != NULL); assert(*pp != NULL); if(getSubString(pp, (char*) szName, sizeof(szName) / sizeof(uchar), ' ') != 0) { errmsg.LogError(0, RS_RET_NOT_FOUND, "could not extract group name"); ABORT_FINALIZE(RS_RET_NOT_FOUND); } CHKmalloc(stringBuf = malloc(bufSize)); while(pgBuf == NULL) { errno = 0; getgrnam_r((char*)szName, &gBuf, stringBuf, bufSize, &pgBuf); if((pgBuf == NULL) && (errno == ERANGE)) { /* Increase bufsize and try again.*/ bufSize *= 2; CHKmalloc(stringBuf = realloc(stringBuf, bufSize)); } } if(pgBuf == NULL) { errmsg.LogError(0, RS_RET_NOT_FOUND, "ID for group '%s' could not be found or error", (char*)szName); iRet = RS_RET_NOT_FOUND; } else { if(pSetHdlr == NULL) { /* we should set value directly to var */ *((gid_t*)pVal) = pgBuf->gr_gid; } else { /* we set value via a set function */ CHKiRet(pSetHdlr(pVal, pgBuf->gr_gid)); } dbgprintf("gid %d obtained for group '%s'\n", (int) pgBuf->gr_gid, szName); } skipWhiteSpace(pp); /* skip over any whitespace */ finalize_it: free(stringBuf); RETiRet; }
/* create a new lookup table object AND include it in our list of * lookup tables. */ static rsRetVal lookupNew(lookup_ref_t **ppThis) { lookup_ref_t *pThis = NULL; lookup_t *t = NULL; int initialized = 0; DEFiRet; CHKmalloc(pThis = calloc(1, sizeof(lookup_ref_t))); CHKmalloc(t = calloc(1, sizeof(lookup_t))); CHKiConcCtrl(pthread_rwlock_init(&pThis->rwlock, NULL)); initialized++; /*1*/ CHKiConcCtrl(pthread_mutex_init(&pThis->reloader_mut, NULL)); initialized++; /*2*/ CHKiConcCtrl(pthread_cond_init(&pThis->run_reloader, NULL)); initialized++; /*3*/ CHKiConcCtrl(pthread_attr_init(&pThis->reloader_thd_attr)); initialized++; /*4*/ pThis->do_reload = pThis->do_stop = 0; pThis->reload_on_hup = 1; /*DO reload on HUP (default)*/ CHKiConcCtrl(pthread_create(&pThis->reloader, &pThis->reloader_thd_attr, lookupTableReloader, pThis)); initialized++; /*5*/ pThis->next = NULL; if(loadConf->lu_tabs.root == NULL) { loadConf->lu_tabs.root = pThis; } else { loadConf->lu_tabs.last->next = pThis; } loadConf->lu_tabs.last = pThis; pThis->self = t; *ppThis = pThis; finalize_it: if(iRet != RS_RET_OK) { errmsg.LogError(errno, iRet, "a lookup table could not be initialized: failed at init-step %d " "(please enable debug logs for details)", initialized); if (initialized > 4) lookupStopReloader(pThis); if (initialized > 3) pthread_attr_destroy(&pThis->reloader_thd_attr); if (initialized > 2) pthread_cond_destroy(&pThis->run_reloader); if (initialized > 1) pthread_mutex_destroy(&pThis->reloader_mut); if (initialized > 0) pthread_rwlock_destroy(&pThis->rwlock); free(t); free(pThis); } RETiRet; }
/* add new entry to list. We assume that the fd is not already present and DO NOT check this! * Returns newly created entry in pEvtLst. * Note that we currently need to use level-triggered mode, because the upper layers do not work * in parallel. As such, in edge-triggered mode we may not get notified, because new data comes * in after we have read everything that was present. To use ET mode, we need to change the upper * peers so that they immediately start a new wait before processing the data read. That obviously * requires more elaborate redesign and we postpone this until the current more simplictic mode has * been proven OK in practice. * rgerhards, 2009-11-18 */ static inline rsRetVal addEvent(nsdpoll_ptcp_t *pThis, int id, void *pUsr, int mode, nsd_ptcp_t *pSock, nsdpoll_epollevt_lst_t **pEvtLst) { nsdpoll_epollevt_lst_t *pNew; DEFiRet; CHKmalloc(pNew = (nsdpoll_epollevt_lst_t*) calloc(1, sizeof(nsdpoll_epollevt_lst_t))); pNew->id = id; pNew->pUsr = pUsr; pNew->pSock = pSock; pNew->event.events = 0; /* TODO: at some time we should be able to use EPOLLET */ //pNew->event.events = EPOLLET; if(mode & NSDPOLL_IN) pNew->event.events |= EPOLLIN; if(mode & NSDPOLL_OUT) pNew->event.events |= EPOLLOUT; pNew->event.data.ptr = pNew; pthread_mutex_lock(&pThis->mutEvtLst); pNew->pNext = pThis->pRoot; pThis->pRoot = pNew; pthread_mutex_unlock(&pThis->mutEvtLst); *pEvtLst = pNew; finalize_it: RETiRet; }
/* Add a parser to the list. We use a VERY simple and ineffcient algorithm, * but it is employed only for a few milliseconds during config processing. So * I prefer to keep it very simple and with simple data structures. Unfortunately, * we need to preserve the order, but I don't like to add a tail pointer as that * would require a container object. So I do the extra work to skip to the tail * when adding elements... * rgerhards, 2009-11-03 */ static rsRetVal AddParserToList(parserList_t **ppListRoot, parser_t *pParser) { parserList_t *pThis; parserList_t *pTail; DEFiRet; CHKmalloc(pThis = MALLOC(sizeof(parserList_t))); pThis->pParser = pParser; pThis->pNext = NULL; if(*ppListRoot == NULL) { pThis->pNext = *ppListRoot; *ppListRoot = pThis; } else { /* find tail first */ for(pTail = *ppListRoot ; pTail->pNext != NULL ; pTail = pTail->pNext) /* just search, do nothing else */; /* add at tail */ pTail->pNext = pThis; } DBGPRINTF("DDDDD: added parser '%s' to list %p\n", pParser->pName, ppListRoot); finalize_it: RETiRet; }
/* add a function to the function registry. * The handed-over cstr_t* object must no longer be used by the caller. * A duplicate function name is an error. * rgerhards, 2009-04-06 */ static rsRetVal rsfrAddFunction(uchar *szName, prsf_t rsf) { rsf_entry_t *pEntry; size_t lenName; DEFiRet; assert(szName != NULL); assert(rsf != NULL); /* first check if we have a duplicate name, with the current approach this means * we need to go through the whole list. */ lenName = strlen((char*)szName); for(pEntry = funcRegRoot ; pEntry != NULL ; pEntry = pEntry->pNext) if(!rsCStrSzStrCmp(pEntry->pName, szName, lenName)) ABORT_FINALIZE(RS_RET_DUP_FUNC_NAME); /* unique name, so add to head of list */ CHKmalloc(pEntry = calloc(1, sizeof(rsf_entry_t))); CHKiRet(rsCStrConstructFromszStr(&pEntry->pName, szName)); CHKiRet(cstrFinalize(pEntry->pName)); pEntry->rsf = rsf; pEntry->pNext = funcRegRoot; funcRegRoot = pEntry; finalize_it: if(iRet != RS_RET_OK && iRet != RS_RET_DUP_FUNC_NAME) free(pEntry); RETiRet; }
/* Add a strgen to the list. We use a VERY simple and ineffcient algorithm, * but it is employed only for a few milliseconds during config processing. So * I prefer to keep it very simple and with simple data structures. Unfortunately, * we need to preserve the order, but I don't like to add a tail pointer as that * would require a container object. So I do the extra work to skip to the tail * when adding elements... */ static rsRetVal AddStrgenToList(strgenList_t **ppListRoot, strgen_t *pStrgen) { strgenList_t *pThis; strgenList_t *pTail; DEFiRet; CHKmalloc(pThis = MALLOC(sizeof(strgenList_t))); pThis->pStrgen = pStrgen; pThis->pNext = NULL; if(*ppListRoot == NULL) { pThis->pNext = *ppListRoot; *ppListRoot = pThis; } else { /* find tail first */ for(pTail = *ppListRoot ; pTail->pNext != NULL ; pTail = pTail->pNext) /* just search, do nothing else */; /* add at tail */ pTail->pNext = pThis; } finalize_it: RETiRet; }
/* Construction finalizer * rgerhards, 2008-01-17 */ rsRetVal wtiConstructFinalize(wti_t *pThis) { DEFiRet; int iDeqBatchSize; ISOBJ_TYPE_assert(pThis, wti); DBGPRINTF("%s: finalizing construction of worker instance data (for %d actions)\n", wtiGetDbgHdr(pThis), iActionNbr); /* initialize our thread instance descriptor (no concurrency here) */ pThis->bIsRunning = WRKTHRD_STOPPED; /* must use calloc as we need zero-init */ CHKmalloc(pThis->actWrkrInfo = calloc(iActionNbr, sizeof(actWrkrInfo_t))); if(pThis->pWtp == NULL) { dbgprintf("wtiConstructFinalize: pWtp not set, this may be intentional\n"); FINALIZE; } /* we now alloc the array for user pointers. We obtain the max from the queue itself. */ CHKiRet(pThis->pWtp->pfGetDeqBatchSize(pThis->pWtp->pUsr, &iDeqBatchSize)); CHKiRet(batchInit(&pThis->batch, iDeqBatchSize)); finalize_it: RETiRet; }
/* note: this function is only called once in action.c */ rsRetVal wtiNewIParam(wti_t *const pWti, action_t *const pAction, actWrkrIParams_t **piparams) { actWrkrInfo_t *const wrkrInfo = &(pWti->actWrkrInfo[pAction->iActionNbr]); actWrkrIParams_t *iparams; int newMax; DEFiRet; if(wrkrInfo->p.tx.currIParam == wrkrInfo->p.tx.maxIParams) { /* we need to extend */ newMax = (wrkrInfo->p.tx.maxIParams == 0) ? CONF_IPARAMS_BUFSIZE : 2 * wrkrInfo->p.tx.maxIParams; CHKmalloc(iparams = realloc(wrkrInfo->p.tx.iparams, sizeof(actWrkrIParams_t) * pAction->iNumTpls * newMax)); memset(iparams + (wrkrInfo->p.tx.currIParam * pAction->iNumTpls), 0, sizeof(actWrkrIParams_t) * pAction->iNumTpls * (newMax - wrkrInfo->p.tx.maxIParams)); wrkrInfo->p.tx.iparams = iparams; wrkrInfo->p.tx.maxIParams = newMax; } *piparams = wrkrInfo->p.tx.iparams + wrkrInfo->p.tx.currIParam * pAction->iNumTpls; ++wrkrInfo->p.tx.currIParam; finalize_it: RETiRet; }
/* create a new lookup table object AND include it in our list of * lookup tables. */ rsRetVal lookupNew(lookup_t **ppThis) { lookup_t *pThis = NULL; DEFiRet; CHKmalloc(pThis = malloc(sizeof(lookup_t))); pthread_rwlock_init(&pThis->rwlock, NULL); pThis->name = NULL; if(loadConf->lu_tabs.root == NULL) { loadConf->lu_tabs.root = pThis; pThis->next = NULL; } else { pThis->next = loadConf->lu_tabs.last; } loadConf->lu_tabs.last = pThis; *ppThis = pThis; finalize_it: if(iRet != RS_RET_OK) { free(pThis); } RETiRet; }
/* extend the string buffer if its size is insufficient. * Param iMinNeeded is the minumum free space needed. If it is larger * than the default alloc increment, space for at least this amount is * allocated. In practice, a bit more is allocated because we envision that * some more characters may be added after these. * rgerhards, 2008-01-07 * changed to utilized realloc() -- rgerhards, 2009-06-16 */ rsRetVal rsCStrExtendBuf(cstr_t *pThis, size_t iMinNeeded) { uchar *pNewBuf; size_t iNewSize; DEFiRet; /* first compute the new size needed */ if(iMinNeeded > RS_STRINGBUF_ALLOC_INCREMENT) { /* we allocate "n" ALLOC_INCREMENTs. Usually, that should * leave some room after the absolutely needed one. It also * reduces memory fragmentation. Note that all of this are * integer operations (very important to understand what is * going on)! Parenthesis are for better readibility. */ iNewSize = (iMinNeeded / RS_STRINGBUF_ALLOC_INCREMENT + 1) * RS_STRINGBUF_ALLOC_INCREMENT; } else { iNewSize = pThis->iBufSize + RS_STRINGBUF_ALLOC_INCREMENT; } iNewSize += pThis->iBufSize; /* add current size */ /* DEV debugging only: dbgprintf("extending string buffer, old %d, new %d\n", pThis->iBufSize, iNewSize); */ CHKmalloc(pNewBuf = (uchar*) realloc(pThis->pBuf, iNewSize * sizeof(uchar))); pThis->iBufSize = iNewSize; pThis->pBuf = pNewBuf; finalize_it: RETiRet; }
/* Converts the CStr object to a classical zero-terminated C string, * returns that string and destroys the CStr object. The returned string * MUST be freed by the caller. The function might return NULL if * no memory can be allocated. * * This is the NEW replacement for rsCStrConvSzStrAndDestruct which does * no longer utilize a special buffer but soley works on pBuf (and also * assumes that cstrFinalize had been called). * * Parameters are as follows: * pointer to the object, pointer to string-pointer to receive string and * bRetNULL: 0 - must not return NULL on empty string, return "" in that * case, 1 - return NULL instead of an empty string. * PLEASE NOTE: the caller must free the memory returned in ppSz in any case * (except, of course, if it is NULL). */ rsRetVal cstrConvSzStrAndDestruct(cstr_t *pThis, uchar **ppSz, int bRetNULL) { DEFiRet; uchar* pRetBuf; rsCHECKVALIDOBJECT(pThis, OIDrsCStr); assert(ppSz != NULL); assert(bRetNULL == 0 || bRetNULL == 1); if(pThis->pBuf == NULL) { if(bRetNULL == 0) { CHKmalloc(pRetBuf = MALLOC(sizeof(uchar))); *pRetBuf = '\0'; } else { pRetBuf = NULL; } } else pRetBuf = pThis->pBuf; *ppSz = pRetBuf; finalize_it: /* We got it, now free the object ourselfs. Please note * that we can NOT use the rsCStrDestruct function as it would * also free the sz String buffer, which we pass on to the user. */ RSFREEOBJ(pThis); RETiRet; }
/* load our low-level driver. This must be done before any * driver-specific functions (allmost all...) can be carried * out. Note that the driver's .ifIsLoaded is correctly * initialized by calloc() and we depend on that. * WARNING: this code is mostly identical to similar code in * nssel.c - TODO: abstract it and move it to some common place. * rgerhards, 2008-04-18 */ static rsRetVal loadDrvr(netstrms_t *pThis) { DEFiRet; uchar *pBaseDrvrName; uchar szDrvrName[48]; /* 48 shall be large enough */ pBaseDrvrName = pThis->pBaseDrvrName; if(pBaseDrvrName == NULL) /* if no drvr name is set, use system default */ pBaseDrvrName = glbl.GetDfltNetstrmDrvr(); if(snprintf((char*)szDrvrName, sizeof(szDrvrName), "lmnsd_%s", pBaseDrvrName) == sizeof(szDrvrName)) ABORT_FINALIZE(RS_RET_DRVRNAME_TOO_LONG); CHKmalloc(pThis->pDrvrName = (uchar*) strdup((char*)szDrvrName)); pThis->Drvr.ifVersion = nsdCURR_IF_VERSION; /* The pDrvrName+2 below is a hack to obtain the object name. It * safes us to have yet another variable with the name without "lm" in * front of it. If we change the module load interface, we may re-think * about this hack, but for the time being it is efficient and clean * enough. -- rgerhards, 2008-04-18 */ CHKiRet(obj.UseObj(__FILE__, szDrvrName+2, szDrvrName, (void*) &pThis->Drvr)); finalize_it: if(iRet != RS_RET_OK) { if(pThis->pDrvrName != NULL) free(pThis->pDrvrName); pThis->pDrvrName = NULL; } RETiRet; }
static rsRetVal setReportingNamespace(statsobj_t *pThis, uchar *ns) { DEFiRet; CHKmalloc(pThis->reporting_ns = ustrdup(ns)); finalize_it: RETiRet; }
/* set name. Note that we make our own copy of the memory, caller is * responsible to free up name it passes in (if required). */ static rsRetVal setName(statsobj_t *pThis, uchar *name) { DEFiRet; CHKmalloc(pThis->name = ustrdup(name)); finalize_it: RETiRet; }
/* set origin (module name, etc). * Note that we make our own copy of the memory, caller is * responsible to free up name it passes in (if required). */ static rsRetVal setOrigin(statsobj_t *pThis, uchar *origin) { DEFiRet; CHKmalloc(pThis->origin = ustrdup(origin)); finalize_it: RETiRet; }
static rsRetVal /* assumes exclusive access to bucket */ dynstats_rebuildSurvivorTable(dynstats_bucket_t *b) { htable *survivor_table = NULL; htable *new_table = NULL; size_t htab_sz; DEFiRet; htab_sz = (size_t) (DYNSTATS_HASHTABLE_SIZE_OVERPROVISIONING * b->maxCardinality + 1); if (b->table == NULL) { CHKmalloc(survivor_table = create_hashtable(htab_sz, hash_from_string, key_equals_string, no_op_free)); } CHKmalloc(new_table = create_hashtable(htab_sz, hash_from_string, key_equals_string, no_op_free)); statsobj.UnlinkAllCounters(b->stats); if (b->survivor_table != NULL) { dynstats_destroyCountersIn(b, b->survivor_table, b->survivor_ctrs); } b->survivor_table = (b->table == NULL) ? survivor_table : b->table; b->survivor_ctrs = b->ctrs; b->table = new_table; b->ctrs = NULL; finalize_it: if (iRet != RS_RET_OK) { LogError(errno, RS_RET_INTERNAL_ERROR, "error trying to evict " "TTL-expired metrics of dyn-stats bucket named: %s", b->name); if (new_table == NULL) { LogError(errno, RS_RET_INTERNAL_ERROR, "error trying to " "initialize hash-table for dyn-stats bucket named: %s", b->name); } else { assert(0); /* "can" not happen -- triggers Coverity CID 184307: hashtable_destroy(new_table, 0); We keep this as guard should code above change in the future */ } if (b->table == NULL) { if (survivor_table == NULL) { LogError(errno, RS_RET_INTERNAL_ERROR, "error trying to initialize " "ttl-survivor hash-table for dyn-stats bucket named: %s", b->name); } else { hashtable_destroy(survivor_table, 0); } } } RETiRet; }
// in case existing buffer too small static rsRetVal _grow_buffer(protocolState_t *pState) { DEFiRet; pState->buffer_size *= 2; free(pState->encode_buffer); pState->encode_buffer = (char *)malloc(pState->buffer_size); CHKmalloc(pState->encode_buffer); finalize_it: RETiRet; }
static rsRetVal addContextForReporting(json_object *to, const uchar* field_name, const uchar* value) { json_object *v; DEFiRet; CHKmalloc(v = json_object_new_string((const char*) value)); json_object_object_add(to, (const char*) field_name, v); finalize_it: RETiRet; }
addEntry(struct sockaddr_storage *const addr, dnscache_entry_t **const pEtry) { int r; struct sockaddr_storage *keybuf = NULL; dnscache_entry_t *etry = NULL; DEFiRet; pthread_rwlock_wrlock(&dnsCache.rwlock); /* first check, if the entry was added in the mean time */ etry = findEntry(addr); if(etry != NULL) { FINALIZE; } /* entry still does not exist, so add it */ CHKmalloc(etry = malloc(sizeof(dnscache_entry_t))); CHKmalloc(keybuf = malloc(sizeof(struct sockaddr_storage))); CHKiRet(resolveAddr(addr, etry)); memcpy(&etry->addr, addr, SALEN((struct sockaddr*) addr)); etry->nUsed = 0; memcpy(keybuf, addr, sizeof(struct sockaddr_storage)); r = hashtable_insert(dnsCache.ht, keybuf, etry); keybuf = NULL; if(r == 0) { DBGPRINTF("dnscache: inserting element failed\n"); } finalize_it: pthread_rwlock_unlock(&dnsCache.rwlock); if(iRet == RS_RET_OK) { *pEtry = etry; } else { free(keybuf); free(etry); /* Note: sub-fields cannot be populated in this case */ } RETiRet; }
/* Called by strmsrv on acceptance of a new session. This allocates our * own session data. * rgerhards, 2009-06-02 */ static rsRetVal OnSessConstructFinalize(void *pUsr) { diis_sess_t *pData; DEFiRet; assert(pUsr != NULL); CHKmalloc(pData = calloc(1, sizeof(diis_sess_t))); pData->state = DIIS_IN_HDR; *((diis_sess_t**) pUsr) = pData; finalize_it: RETiRet; }
rsRetVal lookupBuildTable(lookup_t *pThis, struct json_object *jroot) { //struct json_object *jversion, *jnomatch, *jtype, *jtab; struct json_object *jtab; struct json_object *jrow, *jindex, *jvalue; uint32_t i; uint32_t maxStrSize; DEFiRet; #if 0 // enable when we continue to work on this module jversion = json_object_object_get(jroot, "version"); jnomatch = json_object_object_get(jroot, "nomatch"); jtype = json_object_object_get(jroot, "type"); #endif jtab = json_object_object_get(jroot, "table"); pThis->nmemb = json_object_array_length(jtab); CHKmalloc(pThis->d.strtab = malloc(pThis->nmemb * sizeof(lookup_string_tab_etry_t))); maxStrSize = 0; for(i = 0 ; i < pThis->nmemb ; ++i) { jrow = json_object_array_get_idx(jtab, i); jindex = json_object_object_get(jrow, "index"); jvalue = json_object_object_get(jrow, "value"); CHKmalloc(pThis->d.strtab[i].key = (uchar*) strdup(json_object_get_string(jindex))); CHKmalloc(pThis->d.strtab[i].val = (uchar*) strdup(json_object_get_string(jvalue))); maxStrSize += ustrlen(pThis->d.strtab[i].val); } qsort(pThis->d.strtab, pThis->nmemb, sizeof(lookup_string_tab_etry_t), qs_arrcmp_strtab); dbgprintf("DDDD: table loaded (max size %u):\n", maxStrSize); for(i = 0 ; i < pThis->nmemb ; ++i) dbgprintf("key: '%s', val: '%s'\n", pThis->d.strtab[i].key, pThis->d.strtab[i].val); finalize_it: RETiRet; }