#include <../../nrnconf.h> // bug in the osx 10.2 environment #if defined(__POWERPC__) && defined(__APPLE__) #undef HAVE_LOCKF #endif #include #include #include #include #include #include #include #include //extern "C" { extern int mkdir(const char*, int); } #include #include #include "nrnbbs.h" #if !defined(HAVE_LOCKF) #include #endif #define HISTORY 0 #define NRNBBSTMP "nrnbbs" #define NOTIFY "notify" #define NRNBBS "nrnbbs" #define LOCKFILE "lock" #define TMPFILE "temp" #define NOTIFY_SIGNAL SIGUSR1 class NrnBBSCallbackItem { public: NrnBBSCallbackItem(const char*, NrnBBSCallback); virtual ~NrnBBSCallbackItem(); boolean equal(const char*); void execute(); private: CopyString s_; NrnBBSCallback cb_; }; static const char* fname(const char* name); static void history(const char* s1, const char* s2, const char* s3) { #if HISTORY FILE*f; if ((f = fopen(fname("history"), "a")) != (FILE*)0) { fprintf(f, "%5d %s |%s| |%s|\n", getpid(), s1, s2, s3); fclose(f); } #endif } static void history(const char* s1) { history(s1, "", ""); } static void history(const char* s1, const char* s2) { history (s1, s2, ""); } static void history(const char* s1, int i) { char buf[20]; sprintf(buf, "%d", i); history(s1, buf, ""); } declarePtrList(NrnBBSCallbackList, NrnBBSCallbackItem) implementPtrList(NrnBBSCallbackList, NrnBBSCallbackItem) static NrnBBSCallbackList* cblist_; static FILE* lockfile_; static void get_lock() { #if !defined(HAVE_LOCKF) while (flock(fileno(lockfile_), LOCK_EX) != 0) { #else while (lockf(fileno(lockfile_), F_LOCK, 0) != 0) { #endif history("lockf returned non zero"); } //printf("got lock for %d\n", getpid()); } static void release_lock() { #if !defined(HAVE_LOCKF) flock(fileno(lockfile_), LOCK_UN); #else lockf(fileno(lockfile_), F_ULOCK, 0); #endif //printf("released lock for %d\n", getpid()); } static const char* nrnbbsdir() { static char* d ; if (!d) { char buf[256]; char* tmpdir; tmpdir = getenv("TMPDIR"); if (!tmpdir) { tmpdir = "/tmp"; } sprintf(buf, "%s/%s_%s", tmpdir, getenv("USER"), NRNBBSTMP); d = new char[strlen(buf)+1]; strcpy(d, buf); mkdir(d, 0777); } return d; } static const char* fname(const char* name) { static char buf[2][256]; static int i = 0; i = (i+1)%2; sprintf(buf[i], "%s/%s", nrnbbsdir(), name); return buf[i]; } static boolean connected_; boolean nrnbbs_connect() { if (!lockfile_) { const char* lfile = fname(LOCKFILE); lockfile_ = fopen(lfile, "w"); if (!lockfile_) { connected_ = false; return connected_; } } connected_ = true; history("connect"); return connected_; } void nrnbbs_disconnect() { connected_ = false; history("disconnect"); if (cblist_) { get_lock(); int pid = getpid(); FILE* f = fopen(fname(NOTIFY), "r"); if (f) { char buf[256]; int id; FILE* f2 = fopen(fname(TMPFILE), "w"); if (!f2) { fprintf(stderr, "can't open %s\n", fname(TMPFILE)); } while (fgets(buf, 256, f)) { buf[strlen(buf) - 1] = '\0'; fscanf(f, "%d\n", &id); if (id != pid) { fprintf(f2, "%s\n%d\n", buf, id); } } fclose(f2); fclose(f); rename(fname(TMPFILE), fname(NOTIFY)); } release_lock(); for (long i=0; i < cblist_->count(); ++i) { delete cblist_->item(i); } delete cblist_; cblist_ = nil; } if (lockfile_) { fclose(lockfile_); lockfile_ = (FILE*)0; } } boolean nrnbbs_connected() { return connected_; } void nrnbbs_wait(boolean* pflag) { boolean f = false; boolean *pf; pf = (pflag) ? pflag : &f; while (!(*pf) && nrnbbs_connected()) { f = true; // once only if no arg pause(); } } void nrnbbs_post(const char* key) { nrnbbs_post_string(key, ""); } void nrnbbs_post_int(const char* key, int ival) { char buf[30]; sprintf(buf, "%d", ival); nrnbbs_post_string(key, buf); } void nrnbbs_post_string(const char* key, const char* sval) { history("post", key, sval); get_lock(); FILE* f = fopen(fname(NRNBBS), "a"); fprintf(f, "%s\n%s\n", key, sval); FILE* f2 = fopen(fname(NOTIFY), "r"); char name[256]; int i, n, id[10]; n = 0; if (f2) { while( fgets(name, 256, f2) && n < 10) { name[strlen(name) - 1] = '\0'; fscanf(f2, "%d\n", &i); if (strcmp(name, key) == 0) { id[n++] = i; fprintf(f, "nrnbbs_notifying %s\n\n", key); } } fclose(f2); } fclose(f); release_lock(); for (i=0; i < n; ++i) { history(" notify", id[i]); kill(id[i], NOTIFY_SIGNAL); } } boolean nrnbbs_take(const char* key) { char buf[256]; return nrnbbs_take_string(key, buf); } boolean nrnbbs_take_int(const char* key, int* ipval) { char buf[256]; boolean b = nrnbbs_take_string(key, buf); if (b) { b = (sscanf(buf, "%d\n", ipval) == 1) ? true : false; } return b; } boolean nrnbbs_take_string(const char* key, char* sval) { history("take", key); get_lock(); boolean b = false; FILE* f = fopen(fname(NRNBBS), "r"); if (f != (FILE*)0) { char name[256], val[256]; FILE* f2 = fopen(fname(TMPFILE), "w"); while (fgets(name, 256, f)) { name[strlen(name) -1] = '\0'; if (name[0] == '\0') { continue; } fgets(val, 256, f); val[strlen(val) - 1] = '\0'; if (!b && strcmp(name, key) == 0) { history(" found", val); b = true; strcpy(sval, val); continue; } fprintf(f2, "%s\n%s\n", name, val); } fclose(f2); fclose(f); if (b) { rename(fname(TMPFILE), fname(NRNBBS)); } }else{ b = false; } release_lock(); return b; } boolean nrnbbs_look(const char* key) { history("look", key); get_lock(); boolean b = false; FILE* f = fopen(fname(NRNBBS), "r"); if (f != (FILE*)0) { char name[256], val[256]; while (fgets(name, 256, f)) { name[strlen(name) - 1] = '\0'; fgets(val, 256, f); if (strcmp(name, key) == 0) { history(" found"); b = true; break; } } fclose(f); }else{ b = false; } release_lock(); return b; } void nrnbbs_exec(const char* cmd) { history("exec", cmd); char buf[256]; sprintf(buf,"%s&", cmd); system(buf); } static RETSIGTYPE nrnbbs_handler(int) { long i; #if defined(SIGNAL_CAST) signal(NOTIFY_SIGNAL, (SIGNAL_CAST)nrnbbs_handler); #else signal(NOTIFY_SIGNAL, nrnbbs_handler); #endif for (i = 0; i < cblist_->count(); ++i) { cblist_->item(i)->execute(); } } void nrnbbs_notify(const char* key, NrnBBSCallback cb){ history("nrnbbs_notify", key); if (!cblist_) { cblist_ = new NrnBBSCallbackList(); } cblist_->append(new NrnBBSCallbackItem(key, cb)); get_lock(); FILE* f = fopen(fname(NOTIFY), "a"); if (!f) { fprintf(stderr, "can't open %s\n", fname(NOTIFY)); return; } fprintf(f, "%s\n%d\n", key, getpid()); fclose(f); release_lock(); #if defined(SIGNAL_CAST) signal(NOTIFY_SIGNAL, (SIGNAL_CAST)nrnbbs_handler); #else signal(NOTIFY_SIGNAL, nrnbbs_handler); #endif } NrnBBSCallbackItem::NrnBBSCallbackItem(const char* s, NrnBBSCallback cb) { cb_ = cb; s_ = s; } NrnBBSCallbackItem::~NrnBBSCallbackItem() {} boolean NrnBBSCallbackItem::equal(const char* s) { return (strcmp(s_.string(), s) == 0) ? true : false; } void NrnBBSCallbackItem::execute() { char buf[256]; sprintf(buf, "nrnbbs_notifying %s", s_.string()); if (nrnbbs_take(buf)) { (*cb_)(s_.string()); } }