static int _pdict_ent_add_persistent_change_listeners(pdict_t *pd, pdict_ent_t *pde) { if (!plist_walk(pd->pd_persistent_listeners, pdict_ent_add_persistent_change_listener_cb, pde)) { plist_walk(pd->pd_persistent_listeners, pdict_ent_remove_persistent_change_listener_cb, pde); pu_log(PUL_WARN, 0, "Failed to add persistent change listener in _pdict_ent_add_persistent_change_listeners."); return 0; } return 1; }
static int pdict_ent_remove_change_listeners(pdict_ent_t *pde) { plist_walk(pde->pde_listeners, pdict_ent_remove_change_listeners_cb, 0); plist_clear(&pde->pde_listeners); return 1; }
static void _pdict_ent_notify(pdict_ent_t *pde, int reason, const char *ov) { pdict_ent_notify_cb_args_t penca = { pde, reason, ov }; plist_walk(pde->pde_listeners, pdict_ent_notify_cb, &penca); }
static ptree_walk_res_t free_na_cb(const void *v1, int level, void *a, void *pwra) { notify_arg_t *na = (notify_arg_t *)v1; plist_walk(na->na_pd_ids, remove_persistent_change_listener_cb, na->na_pdss->pdss_pd); free((void *)na->na_listenid); na->na_listenid = NULL; plist_clear(&na->na_pd_ids); free(na); na = NULL; return PTREE_WALK_CONTINUE; }
static int _pdict_ent_remove_change_listener(pdict_ent_t *pde, pdl_notify_func_t notify, void *a) { void *arg[3]; arg[0] = (void *)notify; arg[1] = a; arg[2] = NULL; plist_walk(pde->pde_listeners, pdict_ent_remove_change_listener_cb, arg); if (arg[2]) { plist_remove(arg[2], &pde->pde_listeners, NULL); free(arg[2]); arg[2] = NULL; return 1; } return 0; }
static ptree_walk_res_t free_na_cb(const void *v1, int level, void *a, void *pwra) { pds_session_t *pdss = (pds_session_t *)a; notify_arg_t *na = (notify_arg_t *)v1; void *ov; ptree_inorder_walk_remove(&pdss->pdss_notify_args, &ov, pwra, nacmp); assert(na == ov); plist_walk(na->na_pd_ids, remove_persistent_change_listener_cb, na->na_pdss->pdss_pd); free((void *)na->na_listenid); na->na_listenid = NULL; plist_clear(&na->na_pd_ids); free(ov); ov = NULL; return PTREE_WALK_CONTINUE; }
/* * This is started by accept_cb as a thread on a new connection. * Calls pd_getline and sends the data it gets to pds_process_line * until pd_getline > 0 and !pdss->pdss_should_close */ int pds_session_serve(const pds_session_t *arg) { pds_session_t *pdss = (pds_session_t *)arg; char *line = NULL; int res; #ifdef _MACOSX signal (SIGPIPE, SIG_IGN); #endif DPRINT(PUL_INFO, "Started new pds_session_serve thread"); pdss->pdss_errdesc[0] = 0; /* first thing - Authenticate */ if(pdss->pdss_auth) { if(pdss->pdss_auth((pds_session_t *)pdss)){ pu_log(PUL_WARN, pdss->pdss_id, "Authentication failed or bad version - closing connection"); goto authfailed; } } while ((res = pd_getline(pdss->pdss_readbuf, sizeof (pdss->pdss_readbuf), &pdss->pdss_bufcur, &pdss->pdss_buflen, pdss->pdss_read, pdss->pdss_close, pdss->pdss_rfd, &line, pdss->pdss_errdesc, sizeof (pdss->pdss_errdesc))) > 0 && !pdss->pdss_should_close) { pds_process_line((pds_session_t *)pdss, line); free(line); line=NULL; } authfailed: free(line); line=NULL; //Shut down the report thread pdss->pdss_should_close = 1; pthread_mutex_lock(&pdss->pdss_lock); if (pdss->pdss_report_thread) { void *status; //pthread_cond_wait(&pdss->pdss_report_cv, &pdss->pdss_lock); pthread_mutex_unlock(&pdss->pdss_lock); pthread_join(pdss->pdss_report_thread, &status); pthread_mutex_lock(&pdss->pdss_lock); } /* remove keys set to expire at end of session */ pdss->pdss_pd_lock(pdss->pdss_pd_lock_arg); plist_walk(pdss->pdss_expire, expired_key_cb, pdss->pdss_pd); plist_clear(&pdss->pdss_expire); /* write_pending will free pending notifications - it will NOT send them because we freed pdss_write */ pdss->pdss_write = NULL; ptree_walk(pdss->pdss_pending, PTREE_POSTORDER, write_pending, ipmcmp, pdss); assert(!pdss->pdss_pending); //ptree_clear(&pdss->pdss_pending); //pdss->pdss_pending = NULL; //clear the listener list - need to lock the dictionary, //because an add/remove could be enumerating the list as we free it otherwise. ptree_walk(pdss->pdss_notify_args, PTREE_POSTORDER, free_na_cb, nacmp, pdss); //ptree_clear(&pdss->pdss_notify_args); assert(!pdss->pdss_notify_args); //Close the socket pdss->pdss_close(pdss->pdss_wfd, NULL, 0); if(pdss->pdss_wfd != pdss->pdss_rfd) pdss->pdss_close(pdss->pdss_rfd, NULL, 0); pdss->pdss_wfd = pdss->pdss_rfd = INVALID_SOCKET; pdss->pdss_close = NULL; pu_log(PUL_INFO, pdss->pdss_id, "done - session closed"); pdss->pdss_pd_unlock(pdss->pdss_pd_lock_arg); pthread_mutex_unlock(&pdss->pdss_lock); //make sure no cb threads are running while(pdss->cb_threads_count) SLEEP(10); /* now free the pdss!! */ pds_session_free(pdss); pu_log(PUL_INFO, 0, "Exiting pds_session_serve thread"); return 0; }
void pds_process_line(pds_session_t *pdss, char *line) { regmatch_t pmatch[9]; char *cmdtag = NULL; char *cmdstr = NULL; char *key = NULL; char *val = NULL; char *buf = NULL; char *listenid = NULL; int reportperiod; int forsession; int res; //DPRINT(line); if ((res = regexec(&setex, line, 7, pmatch, 0)) == 0) { getmatchsub(line, &cmdtag, pmatch, 1); if (cmdtag && strcmp(cmdtag, "unknown") == 0) { result(pdss, cmdtag, "304 unknown is a reserved command tag"); free(cmdtag); cmdtag = NULL; return; } if (!getmatchsub(line, &key, pmatch, 2) || !key) goto fail; if (!getmatchsub(line, &val, pmatch, 5) && !getmatchsub(line, &val, pmatch, 4)) goto fail; if (!val) goto fail; if ((forsession = getmatchsub(line, NULL, pmatch, 6)) > 0) { /* mark for expiration, but make sure it's only added once! */ if(plist_walk(pdss->pdss_expire, is_key_in_list, key)) { char *e; if (!(e = strdup(key))) goto fail; plist_add(e, NULL, &pdss->pdss_expire); } } pdss->pdss_pd_lock(pdss->pdss_pd_lock_arg); res = pdict_add(pdss->pdss_pd, key, val, NULL); pdss->pdss_pd_unlock(pdss->pdss_pd_lock_arg); if (!res) result(pdss, cmdtag, "304 set failed"); else result(pdss, cmdtag, "200 set successful"); if (cmdtag) { free(cmdtag); cmdtag = NULL; } free(key); key = NULL; free(val); val = NULL; return; } if ((res = regexec(&listenex, line, 6, pmatch, 0)) == 0) { notify_arg_t *nap; notify_arg_t na; getmatchsub(line, &cmdtag, pmatch, 1); if (cmdtag && strcmp(cmdtag, "unknown") == 0) { result(pdss, cmdtag, "304 unknown is a reserved command tag"); free(cmdtag); cmdtag = NULL; return; } if ((!getmatchsub(line, &buf, pmatch, 4) && !getmatchsub(line, &buf, pmatch, 3)) || !buf) goto fail; getmatchsub(line, &listenid, pmatch, 5); na.na_pdss = pdss; na.na_listenid = listenid; pthread_mutex_lock(&pdss->pdss_lock); pdss->pdss_pd_lock(pdss->pdss_pd_lock_arg); if (!ptree_contains(&na, pdss->pdss_notify_args, nacmp, (void **)&nap)) { if (!(nap = malloc(sizeof (*nap)))) { pu_log(PUL_WARN, pdss->pdss_id, "insufficient memory"); pdss->pdss_pd_unlock(pdss->pdss_pd_lock_arg); pthread_mutex_unlock(&pdss->pdss_lock); goto fail; } nap->na_pdss = pdss; nap->na_listenid = listenid; nap->na_pd_ids = NULL; if (!ptree_replace(nap, &pdss->pdss_notify_args, nacmp, NULL)) { free(nap); nap = NULL; pu_log(PUL_WARN, pdss->pdss_id, "insufficient memory"); pdss->pdss_pd_unlock(pdss->pdss_pd_lock_arg); pthread_mutex_unlock(&pdss->pdss_lock); free(listenid); listenid = NULL; free(buf); buf = NULL; goto fail; } } if (!(res = pdict_add_persistent_change_listener(pdss->pdss_pd, buf, notify, (void *)nap))) { if (!nap->na_pd_ids) { ptree_remove(nap, &pdss->pdss_notify_args, nacmp, NULL); free((void *)nap->na_listenid); nap->na_listenid = NULL; free(nap); nap = NULL; } result(pdss, cmdtag, "303 listen not established--bad pattern?"); } else { if (!plist_add((void *)res, NULL, &nap->na_pd_ids)) { pdict_remove_persistent_change_listener(pdss->pdss_pd, res); if (!nap->na_pd_ids) { ptree_remove(nap, &pdss->pdss_notify_args, nacmp, NULL); free((void *)nap->na_listenid); nap->na_listenid = NULL; free(nap); nap = NULL; } free(buf); buf = NULL; if (cmdtag) { free(cmdtag); cmdtag = NULL; } pdss->pdss_pd_unlock(pdss->pdss_pd_lock_arg); pthread_mutex_unlock(&pdss->pdss_lock); goto fail; } else { result(pdss, cmdtag,"200 listening, id %s", listenid); } } pdss->pdss_pd_unlock(pdss->pdss_pd_lock_arg); pthread_mutex_unlock(&pdss->pdss_lock); free(buf); buf = NULL; if (cmdtag) { free(cmdtag); cmdtag = NULL; } return; } if ((res = regexec(&reportex, line, 5, pmatch, 0)) == 0) { getmatchsub(line, &cmdtag, pmatch, 1); if (cmdtag && strcmp(cmdtag, "unknown") == 0) { result(pdss, cmdtag, "304 unknown is a reserved command tag"); free(cmdtag); cmdtag = NULL; return; } if (!getmatchsub(line, &buf, pmatch, 2) || !buf) goto fail; if ((reportperiod = atoi(buf)) < 0 || reportperiod > 10000) { result(pdss, cmdtag, "301 invalid report/wait period" "--specify milliseconds or 0 for off (max 10s)"); if (cmdtag) { free(cmdtag); cmdtag = NULL; } free(buf); buf = NULL; return; } free(buf); buf = NULL; getmatchsub(line, &buf, pmatch, 3); set_report_period(pdss, cmdtag, buf, reportperiod); if (cmdtag) { free(cmdtag); cmdtag = NULL; } if (buf) { free(buf); buf = NULL; } return; } if ((res = regexec(&waitex, line, 5, pmatch, 0)) == 0) { getmatchsub(line, &cmdtag, pmatch, 1); if (cmdtag && strcmp(cmdtag, "unknown") == 0) { result(pdss, cmdtag, "304 unknown is a reserved command tag"); free(cmdtag); cmdtag = NULL; return; } if (!getmatchsub(line, &buf, pmatch, 2) || !buf) goto fail; if (atoi(buf) < 0 || atoi(buf) > 10000) { result(pdss, cmdtag, "301 invalid wait period" "--specify milliseconds (max 10s)"); if (cmdtag) { free(cmdtag); cmdtag = NULL; } return; } usleep(atoi(buf) * 1000); result(pdss, cmdtag, "200 nothin' doin'"); if (cmdtag) { free(cmdtag); cmdtag = NULL; } return; } if ((res = regexec(&flushex, line, 5, pmatch, 0)) == 0) { getmatchsub(line, &cmdtag, pmatch, 1); if (cmdtag && strcmp(cmdtag, "unknown") == 0) { result(pdss, cmdtag, "304 unknown is a reserved command tag"); free(cmdtag); cmdtag = NULL; return; } pthread_mutex_lock(&pdss->pdss_lock); pdss->pdss_pd_lock(pdss->pdss_pd_lock_arg); _flush(pdss); pdss->pdss_pd_unlock(pdss->pdss_pd_lock_arg); pthread_mutex_unlock(&pdss->pdss_lock); result(pdss, cmdtag, "200 glug glug"); if (cmdtag) { free(cmdtag); cmdtag = NULL; } return; } if ((res = regexec(&walkex, line, 5, pmatch, 0)) == 0) { wa_t wa; getmatchsub(line, &cmdtag, pmatch, 1); if (cmdtag && strcmp(cmdtag, "unknown") == 0) { result(pdss, cmdtag, "304 unknown is a reserved command tag"); free(cmdtag); cmdtag = NULL; return; } if (!getmatchsub(line, &cmdstr, pmatch, 2) || !cmdstr) goto fail; if (!getmatchsub(line, &buf, pmatch, 3) || !buf) { free(cmdstr); cmdstr = NULL; goto fail; } if ((regcomp(&wa.wa_regex, buf, REG_EXTENDED)) != 0) { free(cmdstr); cmdstr = NULL; free(buf); buf = NULL; result(pdss, cmdtag, "305 expression error"); if (cmdtag) { free(cmdtag); cmdtag = NULL; } return; } wa.wa_pdss = pdss; wa.wa_cmdtag = cmdtag; wa.wa_l = NULL; pdss->pdss_pd_lock(pdss->pdss_pd_lock_arg); if (!pdict_walk(pdss->pdss_pd, add_to_wa_list, &wa)) { int e = errno; pu_log(PUL_WARN, pdss->pdss_id, "temporary failure: %s", strerror(e)); result(pdss, cmdtag, "300 temporary failure: %s", strerror(e)); } else { if (strcmp(cmdstr, "remove") == 0) plist_walk(wa.wa_l, remove_wa_list, &wa); else plist_walk(wa.wa_l, print_wa_list, &wa); result(pdss, cmdtag, "200 done"); } plist_clear(&wa.wa_l); pdss->pdss_pd_unlock(pdss->pdss_pd_lock_arg); regfree(&wa.wa_regex); if (cmdtag) { free(cmdtag); cmdtag = NULL; } free(cmdstr); cmdstr = NULL; free(buf); buf = NULL; return; } if ((res = regexec(&ignoreex, line, 5, pmatch, 0)) == 0) { notify_arg_t *nap; notify_arg_t na; void *arg[2]; int n; getmatchsub(line, &cmdtag, pmatch, 1); if (cmdtag && strcmp(cmdtag, "unknown") == 0) { result(pdss, cmdtag, "304 unknown is a reserved command tag"); if (cmdtag) { free(cmdtag); cmdtag = NULL; } return; } if (!getmatchsub(line, &listenid, pmatch, 2) || !listenid) goto fail; pthread_mutex_lock(&pdss->pdss_lock); pdss->pdss_pd_lock(pdss->pdss_pd_lock_arg); na.na_pdss = pdss; na.na_listenid = listenid; if (!ptree_remove(&na, &pdss->pdss_notify_args, nacmp, (void **)&nap)) { pdss->pdss_pd_unlock(pdss->pdss_pd_lock_arg); pthread_mutex_unlock(&pdss->pdss_lock); result(pdss, cmdtag, "306 nonexistent key/id"); if (cmdtag) { free(cmdtag); cmdtag = NULL; } return; } n = 0; plist_walk(nap->na_pd_ids, _count, &n); plist_walk(nap->na_pd_ids, remove_persistent_change_listener_cb, pdss->pdss_pd); arg[0] = (void *)nap->na_listenid; arg[1] = &pdss->pdss_pending; ptree_walk(pdss->pdss_pending, PTREE_POSTORDER, remove_pending_id, ipmcmp, arg); free((void *)nap->na_listenid); nap->na_listenid = NULL; plist_clear(&nap->na_pd_ids); free(nap); nap = NULL; assert(!ptree_contains(&na, pdss->pdss_notify_args, nacmp, NULL)); pdss->pdss_pd_unlock(pdss->pdss_pd_lock_arg); pthread_mutex_unlock(&pdss->pdss_lock); result(pdss, cmdtag, "200 %d listener%s ignored", n, n > 1 ? "s" : ""); if (cmdtag) { free(cmdtag); cmdtag = NULL; } free(listenid); return; } if ((res = regexec(&quitex, line, 5, pmatch, 0)) == 0) { getmatchsub(line, &cmdtag, pmatch, 1); result(pdss, cmdtag, "200 goodbye"); pdss->pdss_should_close = 1; pdss->pdss_close(pdss->pdss_wfd, NULL, 0); if (cmdtag) { free(cmdtag); cmdtag = NULL; } return; } if ((res = regexec(&getidex, line, 5, pmatch, 0)) == 0) { getmatchsub(line, &cmdtag, pmatch, 1); result(pdss, cmdtag, "200 %d", pdss->pdss_id); if (cmdtag) { free(cmdtag); cmdtag = NULL; } return; } if ((res = regexec(&okex, line, 5, pmatch, 0)) == 0) { if (cmdtag) { free(cmdtag); cmdtag = NULL; } return; } result(pdss, NULL, "400 input unrecognized: %s", line); return; fail: result(pdss, cmdtag, "300 command failed: %s", strerror(errno)); if (cmdtag) free (cmdtag); }
static void _pdict_ent_listeners_copy(pdict_ent_t *pde, pdict_ent_t *pde_copy) { plist_walk(pde->pde_listeners, pdict_ent_listeners_copy_cb, pde_copy); }
/* * This is started by accept_cb as a thread on a new connection. * Calls pd_getline and sends the data it gets to pds_process_line * until pd_getline > 0 and !pdss->pdss_should_close */ int pds_session_serve(const pds_session_t *arg) { pds_session_t *pdss = (pds_session_t *)arg; char *line; int res; #ifdef _MACOSX signal (SIGPIPE, SIG_IGN); #endif pdss->pdss_errdesc[0] = 0; while ((res = pd_getline(pdss->pdss_readbuf, sizeof (pdss->pdss_readbuf), &pdss->pdss_bufcur, &pdss->pdss_buflen, pdss->pdss_read, pdss->pdss_close, pdss->pdss_rfd, &line, pdss->pdss_errdesc, sizeof (pdss->pdss_errdesc))) > 0 && !pdss->pdss_should_close) { pds_process_line((pds_session_t *)pdss, line); free(line); line=NULL; } free(line); line=NULL; pdss->pdss_should_close = 1; /*printf("Printing out expiring keys:\n"); plist_walk(pdss->pdss_expire, print_key, NULL); printf("DONE\n");*/ /* remove keys set to expire at end of session */ pdss->pdss_pd_lock(pdss->pdss_pd_lock_arg); plist_walk(pdss->pdss_expire, expired_key_cb, pdss->pdss_pd); plist_clear(&pdss->pdss_expire); pdss->pdss_pd_unlock(pdss->pdss_pd_lock_arg); pthread_mutex_lock(&pdss->pdss_lock); if (pdss->pdss_report_thread) { void *status; //pthread_cond_wait(&pdss->pdss_report_cv, &pdss->pdss_lock); pthread_mutex_unlock(&pdss->pdss_lock); pthread_join(pdss->pdss_report_thread, &status); pthread_mutex_lock(&pdss->pdss_lock); } ptree_walk(pdss->pdss_notify_args, PTREE_INORDER, free_na_cb, NULL); ptree_clear(&pdss->pdss_notify_args); pthread_mutex_unlock(&pdss->pdss_lock); /* write_pending will free pending notifications */ pdss->pdss_write = NULL; ptree_walk(pdss->pdss_pending, PTREE_INORDER, write_pending, pdss); ptree_clear(&pdss->pdss_pending); assert(!pdss->pdss_pending); assert(!pdss->pdss_notify_args); pu_log(PUL_INFO, pdss->pdss_id, "done - session closed"); /* now free the pdss!! */ pds_session_free(pdss); return res; }