Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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);
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
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;
}
Esempio n. 6
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;
}
Esempio n. 7
0
/*
 * 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;
}
Esempio n. 8
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);
}
Esempio n. 9
0
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);
}
Esempio n. 10
0
/*
 * 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;
}