/** * @brief removes all traces of host 'ip' from lastseen DB * * @param[in] ip : either in (SHA/MD5 format) * @param[in,out] digest: return corresponding digest of input host. * If NULL, return nothing * @retval true if entry was deleted, false otherwise */ bool DeleteIpFromLastSeen(const char *ip, char *digest) { DBHandle *db; bool res = false; if (!OpenDB(&db, dbid_lastseen)) { Log(LOG_LEVEL_ERR, "Unable to open lastseen database"); return false; } char bufkey[CF_BUFSIZE + 1]; char bufhost[CF_BUFSIZE + 1]; strcpy(bufhost, "a"); strlcat(bufhost, ip, CF_BUFSIZE); char key[CF_BUFSIZE]; if (ReadDB(db, bufhost, &key, sizeof(key)) == true) { strcpy(bufkey, "k"); strlcat(bufkey, key, CF_BUFSIZE); if (HasKeyDB(db, bufkey, strlen(bufkey) + 1) == false) { res = false; goto clean; } else { if (digest != NULL) { strcpy(digest, bufkey); } DeleteDB(db, bufkey); DeleteDB(db, bufhost); res = true; } } else { res = false; goto clean; } strcpy(bufkey, "qi"); strlcat(bufkey, key, CF_BUFSIZE); DeleteDB(db, bufkey); strcpy(bufkey, "qo"); strlcat(bufkey, key, CF_BUFSIZE); DeleteDB(db, bufkey); clean: CloseDB(db); return res; }
bool RemoveHostFromLastSeen(const char *hostkey) { DBHandle *db; if (!OpenDB(&db, dbid_lastseen)) { CfOut(cf_error, "", "Unable to open lastseen database"); return false; } /* Lookup corresponding address entry */ char hostkey_key[CF_BUFSIZE]; snprintf(hostkey_key, CF_BUFSIZE, "k%s", hostkey); char address[CF_BUFSIZE]; if (ReadDB(db, hostkey_key, &address, sizeof(address)) == true) { /* Remove address entry */ char address_key[CF_BUFSIZE]; snprintf(address_key, CF_BUFSIZE, "a%s", address); DeleteDB(db, address_key); } /* Remove quality-of-connection entries */ char quality_key[CF_BUFSIZE]; snprintf(quality_key, CF_BUFSIZE, "qi%s", hostkey); DeleteDB(db, quality_key); snprintf(quality_key, CF_BUFSIZE, "qo%s", hostkey); DeleteDB(db, quality_key); /* Remove main entry */ DeleteDB(db, hostkey_key); CloseDB(db); return true; }
static void NotePerformance(char *eventname, time_t t, double value) { CF_DB *dbp; Event e, newe; double lastseen; int lsea = SECONDS_PER_WEEK; time_t now = time(NULL); CfDebug("PerformanceEvent(%s,%.1f s)\n", eventname, value); if (!OpenDB(&dbp, dbid_performance)) { return; } if (ReadDB(dbp, eventname, &e, sizeof(e))) { lastseen = now - e.t; newe.t = t; newe.Q = QAverage(e.Q, value, 0.3); /* Have to kickstart variance computation, assume 1% to start */ if (newe.Q.var <= 0.0009) { newe.Q.var = newe.Q.expect / 100.0; } } else { lastseen = 0.0; newe.t = t; newe.Q.q = value; newe.Q.dq = 0; newe.Q.expect = value; newe.Q.var = 0.001; } if (lastseen > (double) lsea) { CfDebug("Performance record %s expired\n", eventname); DeleteDB(dbp, eventname); } else { CfOut(cf_verbose, "", "Performance(%s): time=%.4lf secs, av=%.4lf +/- %.4lf\n", eventname, value, newe.Q.expect, sqrt(newe.Q.var)); WriteDB(dbp, eventname, &newe, sizeof(newe)); } CloseDB(dbp); }
void EvalContextHeapPersistentRemove(const char *context) { CF_DB *dbp; if (!OpenDB(&dbp, dbid_state)) { return; } DeleteDB(dbp, context); Log(LOG_LEVEL_DEBUG, "Deleted persistent class '%s'", context); CloseDB(dbp); }
void EvalContextHeapPersistentRemove(const char *context) { CF_DB *dbp; if (!OpenDB(&dbp, dbid_state)) { return; } DeleteDB(dbp, context); CfDebug("Deleted any persistent state %s\n", context); CloseDB(dbp); }
static bool Address2HostkeyInDB(DBHandle *db, const char *address, char *result) { char address_key[CF_BUFSIZE]; char hostkey[CF_BUFSIZE]; /* Address key: "a" + address */ snprintf(address_key, CF_BUFSIZE, "a%s", address); if (!ReadDB(db, address_key, &hostkey, sizeof(hostkey))) { return false; } char hostkey_key[CF_BUFSIZE]; char back_address[CF_BUFSIZE]; /* Hostkey key: "k" + hostkey */ snprintf(hostkey_key, CF_BUFSIZE, "k%s", hostkey); if (!ReadDB(db, hostkey_key, &back_address, sizeof(back_address))) { /* There is no key -> address mapping. Remove reverse mapping and return failure. */ DeleteDB(db, address_key); return false; } if (strcmp(address, back_address) != 0) { /* Forward and reverse mappings do not match. Remove reverse mapping and return failure. */ DeleteDB(db, address_key); return false; } strlcpy(result, hostkey, CF_BUFSIZE); return true; }
static int RemoveLock(char *name) { CF_DB *dbp; if ((dbp = OpenLock()) == NULL) { return -1; } ThreadLock(cft_lock); DeleteDB(dbp, name); ThreadUnlock(cft_lock); CloseLock(dbp); return 0; }
int main(int argc, char *argv[]) { int err = 0; char path[] = "database.sqlite3"; sqlite3 * db; err = sqlite3_open(path, &db); if(SQLITE_OK != err) { return -1; } SelectDB(db, "select str from xx"); InsertDB(db, "insert or replace into xx values ('007','kkk','5pp')"); UpdateDB(db, "update xx set str='007' where sss='lll'"); DeleteDB(db, "delete from xx where str='789'"); printf("----------!!----------\n"); OperateDB(db, "create table if not exists nimei(woqu TEXT)"); SelectDB(db, "select * from xx"); return 0; }
static void test_reverse_missing_forward(void **context) { setup(); UpdateLastSawHost("SHA-12345", "127.0.0.64", true, 555); DBHandle *db; OpenDB(&db, dbid_lastseen); assert_int_equal(DeleteDB(db, "kSHA-12345"), true); /* Check that resolution return false */ char result[CF_BUFSIZE]; assert_int_equal(Address2Hostkey("127.0.0.64", result), false); /* Check that entry is removed */ assert_int_equal(HasKeyDB(db, "a127.0.0.64", strlen("a127.0.0.64") + 1), false); CloseDB(db); }
void PurgeHashes(char *path, Attributes attr, Promise *pp) /* Go through the database and purge records about non-existent files */ { CF_DB *dbp; CF_DBC *dbcp; struct stat statbuf; int ksize, vsize; char *key; void *value; if (!OpenDB(&dbp,dbid_checksums)) { return; } if (path) { if (cfstat(path, &statbuf) == -1) { DeleteDB(dbp, path); } CloseDB(dbp); return; } /* Acquire a cursor for the database. */ if (!NewDBCursor(dbp, &dbcp)) { CfOut(OUTPUT_LEVEL_INFORM, "", " !! Unable to scan hash database"); CloseDB(dbp); return; } /* Walk through the database and print out the key/data pairs. */ while (NextDB(dbp, dbcp, &key, &ksize, &value, &vsize)) { char *obj = (char *) key + CF_INDEX_OFFSET; if (cfstat(obj, &statbuf) == -1) { if (attr.change.update) { DBCursorDeleteEntry(dbcp); } else { cfPS(OUTPUT_LEVEL_ERROR, CF_WARN, "", pp, attr, "ALERT: File %s no longer exists!", obj); } LogHashChange(obj, cf_file_removed, "File removed", pp); } memset(&key, 0, sizeof(key)); memset(&value, 0, sizeof(value)); } DeleteDBCursor(dbp, dbcp); CloseDB(dbp); }
void NoteClassUsage(AlphaList baselist, int purge) { CF_DB *dbp; CF_DBC *dbcp; void *stored; char *key; int ksize, vsize; Event e, entry, newe; double lsea = SECONDS_PER_WEEK * 52; /* expire after (about) a year */ time_t now = time(NULL); Item *list = NULL; const Item *ip; double lastseen; double vtrue = 1.0; /* end with a rough probability */ /* Only do this for the default policy, too much "downgrading" otherwise */ if (MINUSF) { return; } AlphaListIterator it = AlphaListIteratorInit(&baselist); for (ip = AlphaListIteratorNext(&it); ip != NULL; ip = AlphaListIteratorNext(&it)) { if ((IGNORECLASS(ip->name))) { CfDebug("Ignoring class %s (not packing)", ip->name); continue; } IdempPrependItem(&list, ip->name, NULL); } if (!OpenDB(&dbp, dbid_classes)) { return; } /* First record the classes that are in use */ for (ip = list; ip != NULL; ip = ip->next) { if (ReadDB(dbp, ip->name, &e, sizeof(e))) { CfDebug("FOUND %s with %lf\n", ip->name, e.Q.expect); lastseen = now - e.t; newe.t = now; newe.Q = QAverage(e.Q, vtrue, 0.7); } else { lastseen = 0.0; newe.t = now; /* With no data it's 50/50 what we can say */ newe.Q = QDefinite(0.5 * vtrue); } if (lastseen > lsea) { CfDebug("Class usage record %s expired\n", ip->name); DeleteDB(dbp, ip->name); } else { WriteDB(dbp, ip->name, &newe, sizeof(newe)); } } /* Then update with zero the ones we know about that are not active */ if (purge) { /* Acquire a cursor for the database and downgrade classes that did not get defined this time*/ if (!NewDBCursor(dbp, &dbcp)) { CfOut(cf_inform, "", " !! Unable to scan class db"); CloseDB(dbp); DeleteItemList(list); return; } memset(&entry, 0, sizeof(entry)); while (NextDB(dbp, dbcp, &key, &ksize, &stored, &vsize)) { time_t then; char eventname[CF_BUFSIZE]; memset(eventname, 0, CF_BUFSIZE); strncpy(eventname, (char *) key, ksize); if (stored != NULL) { memcpy(&entry, stored, sizeof(entry)); then = entry.t; lastseen = now - then; if (lastseen > lsea) { CfDebug("Class usage record %s expired\n", eventname); DBCursorDeleteEntry(dbcp); } else if (!IsItemIn(list, eventname)) { newe.t = then; newe.Q = QAverage(entry.Q, 0, 0.5); if (newe.Q.expect <= 0.0001) { CfDebug("Deleting class %s as %lf is zero\n", eventname, newe.Q.expect); DBCursorDeleteEntry(dbcp); } else { CfDebug("Downgrading class %s from %lf to %lf\n", eventname, entry.Q.expect, newe.Q.expect); DBCursorWriteEntry(dbcp, &newe, sizeof(newe)); } } } } DeleteDBCursor(dbp, dbcp); } CloseDB(dbp); DeleteItemList(list); }
PromiseResult PurgeHashes(EvalContext *ctx, char *path, Attributes attr, const Promise *pp) /* Go through the database and purge records about non-existent files */ { CF_DB *dbp; CF_DBC *dbcp; struct stat statbuf; int ksize, vsize; char *key; void *value; if (!OpenDB(&dbp,dbid_checksums)) { return PROMISE_RESULT_NOOP; } if (path) { if (stat(path, &statbuf) == -1) { DeleteDB(dbp, path); } CloseDB(dbp); return PROMISE_RESULT_NOOP; } /* Acquire a cursor for the database. */ if (!NewDBCursor(dbp, &dbcp)) { Log(LOG_LEVEL_INFO, "Unable to scan hash database"); CloseDB(dbp); return PROMISE_RESULT_NOOP; } /* Walk through the database and print out the key/data pairs. */ PromiseResult result = PROMISE_RESULT_NOOP; while (NextDB(dbcp, &key, &ksize, &value, &vsize)) { char *obj = (char *) key + CF_INDEX_OFFSET; if (stat(obj, &statbuf) == -1) { if (attr.change.update) { DBCursorDeleteEntry(dbcp); } else { cfPS(ctx, LOG_LEVEL_NOTICE, PROMISE_RESULT_WARN, pp, attr, "File '%s' no longer exists", obj); result = PromiseResultUpdate(result, PROMISE_RESULT_WARN); } LogHashChange(obj, FILE_STATE_REMOVED, "File removed", pp); } } DeleteDBCursor(dbcp); CloseDB(dbp); return result; }
void RecordPerformance(char *eventname,time_t t,double value) { DB *dbp; DB_ENV *dbenv = NULL; char name[CF_BUFSIZE]; struct Event e,newe; double lastseen,delta2; int lsea = CF_WEEK; time_t now = time(NULL); Debug("PerformanceEvent(%s,%.1f s)\n",eventname,value); snprintf(name,CF_BUFSIZE-1,"%s/%s",CFWORKDIR,CF_PERFORMANCE); if ((errno = db_create(&dbp,dbenv,0)) != 0) { snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't open performance database %s\n",name); CfLog(cferror,OUTPUT,"db_open"); return; } #ifdef CF_OLD_DB if ((errno = (dbp->open)(dbp,name,NULL,DB_BTREE,DB_CREATE,0644)) != 0) #else if ((errno = (dbp->open)(dbp,NULL,name,NULL,DB_BTREE,DB_CREATE,0644)) != 0) #endif { snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't open performance database %s\n",name); CfLog(cferror,OUTPUT,"db_open"); return; } if (ReadDB(dbp,eventname,&e,sizeof(e))) { lastseen = now - e.t; newe.t = t; newe.Q.q = value; newe.Q.expect = GAverage(value,e.Q.expect,0.3); delta2 = (value - e.Q.expect)*(value - e.Q.expect); newe.Q.var = GAverage(delta2,e.Q.var,0.3); /* Have to kickstart variance computation, assume 1% to start */ if (newe.Q.var <= 0.0009) { newe.Q.var = newe.Q.expect / 100.0; } } else { lastseen = 0.0; newe.t = t; newe.Q.q = value; newe.Q.expect = value; newe.Q.var = 0.001; } if (lastseen > (double)lsea) { Verbose("Performance record %s expired\n",eventname); DeleteDB(dbp,eventname); } else { Verbose("Performance(%s): time=%.4f secs, av=%.4f +/- %.4f\n",eventname,value,newe.Q.expect,sqrt(newe.Q.var)); WriteDB(dbp,eventname,&newe,sizeof(newe)); } dbp->close(dbp,0); }
void CheckFriendConnections(int hours) /* Go through the database of recent connections and check for Long Time No See ...*/ { DBT key,value; DB *dbp; DBC *dbcp; DB_ENV *dbenv = NULL; int ret, secs = CF_TICKS_PER_HOUR*hours, criterion, overdue, regex=false; time_t now = time(NULL),lsea = -1, tthen, then = 0; char name[CF_BUFSIZE],hostname[CF_BUFSIZE],datebuf[CF_MAXVARSIZE]; char addr[CF_BUFSIZE],type[CF_BUFSIZE], *regexp; struct QPoint entry; double average = 0.0, var = 0.0, ticksperminute = 60.0; double ticksperhour = (double)CF_TICKS_PER_HOUR,ticksperday = (double)CF_TICKS_PER_DAY; regex_t rx,rxcache; regmatch_t pmatch; if (regexp = GetMacroValue(CONTEXTID,"IgnoreFriendRegex")) { Verbose("IgnoreFriendRegex %s\n\n",regexp); if ((ret = regcomp(&rx,regexp,REG_EXTENDED)) != 0) { regerror(ret,&rx,name,1023); snprintf(OUTPUT,CF_BUFSIZE,"Regular expression error %d for %s: %s\n",ret,regexp,name); CfLog(cfinform,OUTPUT,""); regex = false; } else { regex = true; } } Verbose("CheckFriendConnections(%d)\n",hours); snprintf(name,CF_BUFSIZE-1,"%s/%s",CFWORKDIR,CF_LASTDB_FILE); if ((errno = db_create(&dbp,dbenv,0)) != 0) { snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't open last-seen database %s\n",name); CfLog(cferror,OUTPUT,"db_open"); return; } #ifdef CF_OLD_DB if ((errno = (dbp->open)(dbp,name,NULL,DB_BTREE,DB_CREATE,0644)) != 0) #else if ((errno = (dbp->open)(dbp,NULL,name,NULL,DB_BTREE,DB_CREATE,0644)) != 0) #endif { snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't open last-seen database %s\n",name); CfLog(cferror,OUTPUT,"db_open"); return; } /* Acquire a cursor for the database. */ if ((ret = dbp->cursor(dbp, NULL, &dbcp, 0)) != 0) { CfLog(cferror,"Error reading from last-seen database",""); dbp->err(dbp, ret, "DB->cursor"); return; } /* Walk through the database and print out the key/data pairs. */ memset(&key, 0, sizeof(key)); memset(&value, 0, sizeof(value)); while (dbcp->c_get(dbcp, &key, &value, DB_NEXT) == 0) { memset(&entry, 0, sizeof(entry)); strcpy(hostname,(char *)key.data); if (value.data != NULL) { memcpy(&entry,value.data,sizeof(entry)); then = (time_t)entry.q; average = (double)entry.expect; var = (double)entry.var; } else { continue; } /* Got data, now get expiry criterion */ if (secs == 0) { /* Twice the average delta is significant */ criterion = (now - then > (int)(average+2.0*sqrt(var)+0.5)); overdue = now - then - (int)(average); } else { criterion = (now - then > secs); overdue = (now - then - secs); } if (GetMacroValue(CONTEXTID,"LastSeenExpireAfter")) { lsea = atoi(GetMacroValue(CONTEXTID,"LastSeenExpireAfter")); lsea *= CF_TICKS_PER_DAY; } if (lsea < 0) { lsea = (time_t)CF_WEEK/7; } if (regex) { if (regexec(&rx,IPString2Hostname(hostname+1),1,&pmatch,0) == 0) { if ((pmatch.rm_so == 0) && (pmatch.rm_eo == strlen(hostname+1))) { Verbose("Not judging friend %s\n",hostname); criterion = false; lsea = CF_INFINITY; } } } tthen = (time_t)then; snprintf(datebuf,CF_BUFSIZE-1,"%s",ctime(&tthen)); datebuf[strlen(datebuf)-9] = '\0'; /* Chop off second and year */ snprintf(addr,15,"%s",hostname+1); switch(*hostname) { case '+': snprintf(type,CF_BUFSIZE,"last responded to hails"); break; case'-': snprintf(type,CF_BUFSIZE,"last hailed us"); break; } snprintf(OUTPUT,CF_BUFSIZE,"Host %s i.e. %s %s @ [%s] (overdue by %d mins)", IPString2Hostname(hostname+1), addr, type, datebuf, overdue/(int)ticksperminute); if (criterion) { CfLog(cferror,OUTPUT,""); } else { CfLog(cfverbose,OUTPUT,""); } snprintf(OUTPUT,CF_BUFSIZE,"i.e. (%.2f) hrs ago, Av %.2f +/- %.2f hrs\n", ((double)(now-then))/ticksperhour, average/ticksperhour, sqrt(var)/ticksperhour); if (criterion) { CfLog(cferror,OUTPUT,""); } else { CfLog(cfverbose,OUTPUT,""); } if ((now-then) > lsea) { snprintf(OUTPUT,CF_BUFSIZE,"Giving up on host %s -- too long since last seen",IPString2Hostname(hostname+1)); CfLog(cferror,OUTPUT,""); DeleteDB(dbp,hostname); } memset(&value,0,sizeof(value)); memset(&key,0,sizeof(key)); } dbcp->c_close(dbcp); dbp->close(dbp,0); }
void LastSeen(char *hostname,enum roles role) { DB *dbp,*dbpent; DB_ENV *dbenv = NULL, *dbenv2 = NULL; char name[CF_BUFSIZE],databuf[CF_BUFSIZE]; time_t now = time(NULL); struct QPoint q,newq; double lastseen,delta2; int lsea = -1; if (strlen(hostname) == 0) { snprintf(OUTPUT,CF_BUFSIZE,"LastSeen registry for empty hostname with role %d",role); CfLog(cflogonly,OUTPUT,""); return; } Debug("LastSeen(%s) reg\n",hostname); /* Tidy old versions - temporary */ snprintf(name,CF_BUFSIZE-1,"%s/%s",CFWORKDIR,CF_OLDLASTDB_FILE); unlink(name); if ((errno = db_create(&dbp,dbenv,0)) != 0) { snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't init last-seen database %s\n",name); CfLog(cferror,OUTPUT,"db_open"); return; } snprintf(name,CF_BUFSIZE-1,"%s/%s",CFWORKDIR,CF_LASTDB_FILE); #ifdef CF_OLD_DB if ((errno = (dbp->open)(dbp,name,NULL,DB_BTREE,DB_CREATE,0644)) != 0) #else if ((errno = (dbp->open)(dbp,NULL,name,NULL,DB_BTREE,DB_CREATE,0644)) != 0) #endif { snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't open last-seen database %s\n",name); CfLog(cferror,OUTPUT,"db_open"); return; } /* Now open special file for peer entropy record - INRIA intermittency */ snprintf(name,CF_BUFSIZE-1,"%s/%s.%s",CFWORKDIR,CF_LASTDB_FILE,hostname); if ((errno = db_create(&dbpent,dbenv2,0)) != 0) { snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't init last-seen database %s\n",name); CfLog(cferror,OUTPUT,"db_open"); return; } #ifdef CF_OLD_DB if ((errno = (dbpent->open)(dbpent,name,NULL,DB_BTREE,DB_CREATE,0644)) != 0) #else if ((errno = (dbpent->open)(dbpent,NULL,name,NULL,DB_BTREE,DB_CREATE,0644)) != 0) #endif { snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't open last-seen database %s\n",name); CfLog(cferror,OUTPUT,"db_open"); return; } #ifdef HAVE_PTHREAD_H if (pthread_mutex_lock(&MUTEX_GETADDR) != 0) { CfLog(cferror,"pthread_mutex_lock failed","unlock"); exit(1); } #endif switch (role) { case cf_accept: snprintf(databuf,CF_BUFSIZE-1,"-%s",Hostname2IPString(hostname)); break; case cf_connect: snprintf(databuf,CF_BUFSIZE-1,"+%s",Hostname2IPString(hostname)); break; } #ifdef HAVE_PTHREAD_H if (pthread_mutex_unlock(&MUTEX_GETADDR) != 0) { CfLog(cferror,"pthread_mutex_unlock failed","unlock"); exit(1); } #endif if (GetMacroValue(CONTEXTID,"LastSeenExpireAfter")) { lsea = atoi(GetMacroValue(CONTEXTID,"LastSeenExpireAfter")); lsea *= CF_TICKS_PER_DAY; } if (lsea < 0) { lsea = CF_WEEK; } if (ReadDB(dbp,databuf,&q,sizeof(q))) { lastseen = (double)now - q.q; newq.q = (double)now; /* Last seen is now-then */ newq.expect = GAverage(lastseen,q.expect,0.3); delta2 = (lastseen - q.expect)*(lastseen - q.expect); newq.var = GAverage(delta2,q.var,0.3); } else { lastseen = 0.0; newq.q = (double)now; newq.expect = 0.0; newq.var = 0.0; } #ifdef HAVE_PTHREAD_H if (pthread_mutex_lock(&MUTEX_GETADDR) != 0) { CfLog(cferror,"pthread_mutex_lock failed","unlock"); exit(1); } #endif if (lastseen > (double)lsea) { Verbose("Last seen %s expired\n",databuf); DeleteDB(dbp,databuf); } else { WriteDB(dbp,databuf,&newq,sizeof(newq)); WriteDB(dbpent,GenTimeKey(now),&newq,sizeof(newq)); } #ifdef HAVE_PTHREAD_H if (pthread_mutex_unlock(&MUTEX_GETADDR) != 0) { CfLog(cferror,"pthread_mutex_unlock failed","unlock"); exit(1); } #endif dbp->close(dbp,0); dbpent->close(dbpent,0); }
void RecordClassUsage() { DB *dbp; DB_ENV *dbenv = NULL; DBC *dbcp; DBT key,stored; char name[CF_BUFSIZE]; struct Event e,entry,newe; double lsea = CF_WEEK * 52; /* expire after a year */ time_t now = time(NULL); struct Item *ip,*list = NULL; double lastseen,delta2; double vtrue = 1.0; /* end with a rough probability */ Debug("RecordClassUsage\n"); for (ip = VHEAP; ip != NULL; ip=ip->next) { if (!IsItemIn(list,ip->name)) { PrependItem(&list,ip->name,NULL); } } for (ip = VALLADDCLASSES; ip != NULL; ip=ip->next) { if (!IsItemIn(list,ip->name)) { PrependItem(&list,ip->name,NULL); } } snprintf(name,CF_BUFSIZE-1,"%s/%s",CFWORKDIR,CF_CLASSUSAGE); if ((errno = db_create(&dbp,dbenv,0)) != 0) { snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't open performance database %s\n",name); CfLog(cferror,OUTPUT,"db_open"); return; } #ifdef CF_OLD_DB if ((errno = (dbp->open)(dbp,name,NULL,DB_BTREE,DB_CREATE,0644)) != 0) #else if ((errno = (dbp->open)(dbp,NULL,name,NULL,DB_BTREE,DB_CREATE,0644)) != 0) #endif { snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't open performance database %s\n",name); CfLog(cferror,OUTPUT,"db_open"); return; } /* First record the classes that are in use */ for (ip = list; ip != NULL; ip=ip->next) { if (ReadDB(dbp,ip->name,&e,sizeof(e))) { lastseen = now - e.t; newe.t = now; newe.Q.q = vtrue; newe.Q.expect = GAverage(vtrue,e.Q.expect,0.5); delta2 = (vtrue - e.Q.expect)*(vtrue - e.Q.expect); newe.Q.var = GAverage(delta2,e.Q.var,0.5); } else { lastseen = 0.0; newe.t = now; newe.Q.q = 0.5*vtrue; newe.Q.expect = 0.5*vtrue; /* With no data it's 50/50 what we can say */ newe.Q.var = 0.000; } if (lastseen > lsea) { Verbose("Class usage record %s expired\n",ip->name); DeleteDB(dbp,ip->name); } else { Debug("Upgrading %s %f\n",ip->name,newe.Q.expect); WriteDB(dbp,ip->name,&newe,sizeof(newe)); } } /* Then update with zero the ones we know about that are not active */ /* Acquire a cursor for the database. */ if ((errno = dbp->cursor(dbp, NULL, &dbcp, 0)) != 0) { Debug("Error reading from class database: "); dbp->err(dbp, errno, "DB->cursor"); return; } /* Initialize the key/data return pair. */ memset(&key, 0, sizeof(key)); memset(&stored, 0, sizeof(stored)); memset(&entry, 0, sizeof(entry)); while (dbcp->c_get(dbcp, &key, &stored, DB_NEXT) == 0) { double measure,av,var; time_t then; char tbuf[CF_BUFSIZE],eventname[CF_BUFSIZE]; strcpy(eventname,(char *)key.data); if (stored.data != NULL) { memcpy(&entry,stored.data,sizeof(entry)); then = entry.t; measure = entry.Q.q; av = entry.Q.expect; var = entry.Q.var; lastseen = now - then; snprintf(tbuf,CF_BUFSIZE-1,"%s",ctime(&then)); tbuf[strlen(tbuf)-9] = '\0'; /* Chop off second and year */ if (lastseen > lsea) { Verbose("Class usage record %s expired\n",eventname); DeleteDB(dbp,eventname); } else if (!IsItemIn(list,eventname)) { newe.t = then; newe.Q.q = 0; newe.Q.expect = GAverage(0.0,av,0.5); delta2 = av*av; newe.Q.var = GAverage(delta2,var,0.5); Debug("Downgrading class %s from %lf to %lf\n",eventname,entry.Q.expect,newe.Q.expect); WriteDB(dbp,eventname,&newe,sizeof(newe)); } } } dbp->close(dbp,0); }
void UpdateLastSeen() // This function is temporarily or permanently deprecated { double lsea = LASTSEENEXPIREAFTER; int intermittency = false,qsize,ksize; struct CfKeyHostSeen q,newq; double lastseen,delta2; void *stored; CF_DB *dbp = NULL,*dbpent = NULL; CF_DBC *dbcp; char name[CF_BUFSIZE],*key; struct Rlist *rp; struct CfKeyBinding *kp; time_t now = time(NULL); static time_t then; if (now < then + 300 && then > 0 && then <= now + 300) { // Rate limiter return; } then = now; CfOut(cf_verbose,""," -> Writing last-seen observations"); ThreadLock(cft_server_keyseen); if (SERVER_KEYSEEN == NULL) { ThreadUnlock(cft_server_keyseen); CfOut(cf_verbose,""," -> Keyring is empty"); return; } if (BooleanControl("control_agent",CFA_CONTROLBODY[cfa_intermittency].lval)) { CfOut(cf_inform,""," -> Recording intermittency"); intermittency = true; } snprintf(name,CF_BUFSIZE-1,"%s/%s",CFWORKDIR,CF_LASTDB_FILE); MapName(name); if (!OpenDB(name,&dbp)) { ThreadUnlock(cft_server_keyseen); return; } /* First scan for hosts that have moved address and purge their records so that the database always has a 1:1 relationship between keyhash and IP address */ if (!NewDBCursor(dbp,&dbcp)) { ThreadUnlock(cft_server_keyseen); CfOut(cf_inform,""," !! Unable to scan class db"); return; } while(NextDB(dbp,dbcp,&key,&ksize,&stored,&qsize)) { memcpy(&q,stored,sizeof(q)); lastseen = (double)now - q.Q.q; if (lastseen > lsea) { CfOut(cf_verbose,""," -> Last-seen record for %s expired after %.1lf > %.1lf hours\n",key,lastseen/3600,lsea/3600); DeleteDB(dbp,key); } for (rp = SERVER_KEYSEEN; rp != NULL; rp=rp->next) { kp = (struct CfKeyBinding *) rp->item; if ((strcmp(q.address,kp->address) == 0) && (strcmp(key+1,kp->name+1) != 0)) { CfOut(cf_verbose,""," ! Deleting %s's address (%s=%d) as this host %s seems to have moved elsewhere (%s=5d)",key,kp->address,strlen(kp->address),kp->name,q.address,strlen(q.address)); DeleteDB(dbp,key); } } } DeleteDBCursor(dbp,dbcp); /* Now perform updates with the latest data */ for (rp = SERVER_KEYSEEN; rp != NULL; rp=rp->next) { kp = (struct CfKeyBinding *) rp->item; now = kp->timestamp; if (intermittency) { /* Open special file for peer entropy record - INRIA intermittency */ snprintf(name,CF_BUFSIZE-1,"%s/lastseen/%s.%s",CFWORKDIR,CF_LASTDB_FILE,kp->name); MapName(name); if (!OpenDB(name,&dbpent)) { continue; } } if (ReadDB(dbp,kp->name,&q,sizeof(q))) { lastseen = (double)now - q.Q.q; if (q.Q.q <= 0) { lastseen = 300; q.Q.expect = 0; q.Q.var = 0; } newq.Q.q = (double)now; newq.Q.expect = GAverage(lastseen,q.Q.expect,0.4); delta2 = (lastseen - q.Q.expect)*(lastseen - q.Q.expect); newq.Q.var = GAverage(delta2,q.Q.var,0.4); strncpy(newq.address,kp->address,CF_ADDRSIZE-1); } else { lastseen = 0.0; newq.Q.q = (double)now; newq.Q.expect = 0.0; newq.Q.var = 0.0; strncpy(newq.address,kp->address,CF_ADDRSIZE-1); } if (lastseen > lsea) { CfOut(cf_verbose,""," -> Last-seen record for %s expired after %.1lf > %.1lf hours\n",kp->name,lastseen/3600,lsea/3600); DeleteDB(dbp,kp->name); } else { char timebuf[26]; CfOut(cf_verbose,""," -> Last saw %s (alias %s) at %s (noexpiry %.1lf <= %.1lf)\n",kp->name,kp->address,cf_strtimestamp_local(now,timebuf),lastseen/3600,lsea/3600); WriteDB(dbp,kp->name,&newq,sizeof(newq)); if (intermittency) { WriteDB(dbpent,GenTimeKey(now),&newq,sizeof(newq)); } } if (intermittency && dbpent) { CloseDB(dbpent); } } ThreadUnlock(cft_server_keyseen); }
static void VerifyFriendConnections(int hours,struct Attributes a,struct Promise *pp) /* Go through the database of recent connections and check for Long Time No See ...*/ { CF_DB *dbp; CF_DBC *dbcp; char *key; void *value; int ksize,vsize; int secs = SECONDS_PER_HOUR*hours, criterion, overdue; time_t now = time(NULL),lsea = (time_t)CF_WEEK, tthen, then; char name[CF_BUFSIZE],hostname[CF_BUFSIZE],datebuf[CF_MAXVARSIZE]; char addr[CF_BUFSIZE],type[CF_BUFSIZE],output[CF_BUFSIZE]; struct QPoint entry; double average = 0.0, var = 0.0, ticksperminute = 60.0; double ticksperhour = (double)SECONDS_PER_HOUR; CfOut(cf_verbose,"","CheckFriendConnections(%d)\n",hours); snprintf(name,CF_BUFSIZE-1,"%s/lastseen/%s",CFWORKDIR,CF_LASTDB_FILE); MapName(name); if (!OpenDB(name,&dbp)) { return; } /* Acquire a cursor for the database. */ if (!NewDBCursor(dbp,&dbcp)) { CfOut(cf_inform,""," !! Unable to scan friend db"); return; } /* Walk through the database and print out the key/data pairs. */ while(NextDB(dbp,dbcp,&key,&ksize,&value,&vsize)) { memset(&entry, 0, sizeof(entry)); strncpy(hostname,(char *)key,ksize); if (value != NULL) { memcpy(&entry,value,sizeof(entry)); then = (time_t)entry.q; average = (double)entry.expect; var = (double)entry.var; } else { continue; } if (then == 0) { continue; // No data } /* Got data, now get expiry criterion */ if (secs == 0) { /* Twice the average delta is significant */ criterion = (now - then > (int)(average+2.0*sqrt(var)+0.5)); overdue = now - then - (int)(average); } else { criterion = (now - then > secs); overdue = (now - then - secs); } if (LASTSEENEXPIREAFTER < 0) { lsea = (time_t)CF_WEEK; } else { lsea = LASTSEENEXPIREAFTER; } if (a.report.friend_pattern) { if (FullTextMatch(a.report.friend_pattern,IPString2Hostname(hostname+1))) { CfOut(cf_verbose,"","Not judging friend %s\n",hostname); criterion = false; lsea = CF_INFINITY; } } tthen = (time_t)then; snprintf(datebuf,CF_MAXVARSIZE-1,"%s",cf_ctime(&tthen)); datebuf[strlen(datebuf)-9] = '\0'; /* Chop off second and year */ snprintf(addr,15,"%s",hostname+1); switch(*hostname) { case '+': snprintf(type,CF_BUFSIZE,"last responded to hails"); break; case'-': snprintf(type,CF_BUFSIZE,"last hailed us"); break; } snprintf(output,CF_BUFSIZE,"Host %s i.e. %s %s @ [%s] (overdue by %d mins)", IPString2Hostname(hostname+1), addr, type, datebuf, overdue/(int)ticksperminute); if (criterion) { CfOut(cf_error,"",output); } else { CfOut(cf_verbose,"",output); } snprintf(output,CF_BUFSIZE,"i.e. (%.2f) hrs ago, Av %.2f +/- %.2f hrs\n", ((double)(now-then))/ticksperhour, average/ticksperhour, sqrt(var)/ticksperhour); if (criterion) { CfOut(cf_error,"",output); } else { CfOut(cf_verbose,"",output); } if (now - then > lsea) { CfOut(cf_error,"","Giving up on host %s -- %d hours since last seen",IPString2Hostname(hostname+1),hours); DeleteDB(dbp,hostname); } memset(&value,0,sizeof(value)); memset(&key,0,sizeof(key)); } DeleteDBCursor(dbp,dbcp); CloseDB(dbp); }