int pdict_ent_remove(pdict_t *pd, const char *k, char **ovp) { pdict_ent_t *n; pu_log(PUL_VERB, 0, "Removing in key pdict_ent_remove: %s", k); if (!ptree_remove((void *)&k, &pd->pd_ents, pdecmp, (void *)&n)) { //pu_log(PUL_INFO, 0, "Failed to remove key in pdict_ent_remove: %s", k); return 0; } _pdict_ent_notify(n, PDR_ENTRY_REMOVING, n->pde_val); if (ovp) *ovp = (char *)n->pde_val; else { free((void *)n->pde_val); } free((void *)n->pde_key); pdict_ent_remove_change_listeners(n); free(n); return 1; }
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); }