All of lore.kernel.org
 help / color / mirror / Atom feed
* [Patch 1/1] CLD: Introduce the "New CLD" API
@ 2010-02-07 19:15 Pete Zaitcev
  2010-02-07 22:26 ` Jeff Garzik
                   ` (2 more replies)
  0 siblings, 3 replies; 17+ messages in thread
From: Pete Zaitcev @ 2010-02-07 19:15 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: Project Hail List

The "traditional" CLD API is too difficult to program. In particular,
switching from a rigid "Group" policy to arbitrary paths in existing
clients in Chunk and tabled turned out to be next to impossible.
The issue is due to the fundamental nature of the API as based on very
fine-grained events.

So, in the interests of clients, introduce the "new" API. Its basic
definition is in <ncld.h>. It presents a filesystem-like interface,
extended with event callbacks for coarse events, such as an end of
CLD session.

The patch converts all in-tree clients from cldc_xxx to ncld_xxx and
discards some of code that became unused (test/util.c).

Signed-Off-By: Pete Zaitcev <zaitcev@redhat.com>

---
 include/Makefile.am    |    2 
 include/ncld.h         |   88 ++
 lib/cldc-dns.c         |   92 +-
 lib/cldc.c             |  856 ++++++++++++++++++++++++++
 test/Makefile.am       |    5 
 test/it-works.c        |  125 ---
 test/load-file-event.c |  244 +------
 test/lock-file-event.c |  269 +-------
 test/save-file-event.c |  245 -------
 test/test.h            |    5 
 test/util.c            |   79 --
 tools/cldcli.c         | 1249 ++++++++++-----------------------------
 12 files changed, 1433 insertions(+), 1826 deletions(-)

diff --git a/include/Makefile.am b/include/Makefile.am
index 533f51d..cb82261 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -1,5 +1,5 @@
 
 EXTRA_DIST = cld-private.h
 
-include_HEADERS = cldc.h hail_log.h cld_common.h
+include_HEADERS = cldc.h hail_log.h cld_common.h ncld.h
 
diff --git a/include/ncld.h b/include/ncld.h
new file mode 100644
index 0000000..8592f2d
--- /dev/null
+++ b/include/ncld.h
@@ -0,0 +1,88 @@
+#ifndef __NCLD_H__
+#define __NCLD_H__
+
+/*
+ * Copyright 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+/*
+ * The ncld.h API is a replacement for cldc.h. Do not include both.
+ *
+ * We do not believe into making "internal" structures "opaque"
+ * with pointers to void. Therefore, this header might want include
+ * some legacy definitions or whatnot, but users do not need to.
+ */
+#include <stdbool.h>
+#include <glib.h>
+#include <cldc.h>
+
+struct ncld_sess {
+	char *host;
+	unsigned short port;
+	GMutex *mutex;
+	GCond *cond;
+	GThread *thread;
+	bool is_up;
+	int errc;
+	GList *handles;
+	int to_thread[2];
+	struct cldc_udp *udp;
+	struct cld_timer udp_timer;
+	struct cld_timer_list tlist;
+	void (*event)(void *, unsigned int);
+	void *event_arg;
+};
+
+struct ncld_fh {
+	struct ncld_sess *ses;
+	struct cldc_fh *fh;		/* FIXME cldc_open2 take direct & */
+	bool is_open;
+	int errc;
+	int nios;
+	unsigned int event_mask;
+	void (*event_func)(void *, unsigned int);
+	void *event_arg;
+};
+
+struct ncld_read {
+	/* public to application */
+	const void *ptr;
+	long length;
+
+	struct ncld_fh *fh;
+	/* GCond *cond;   -- abusing the conditional of file handle for now */
+	bool is_done;
+	int errc;
+};
+
+extern struct ncld_sess *ncld_sess_open(const char *host, int port,
+	int *error, void (*event)(void *, unsigned int), void *ev_arg,
+	const char *cld_user, const char *cld_key);
+extern struct ncld_fh *ncld_open(struct ncld_sess *s, const char *fname,
+	unsigned int mode, int *error, unsigned int events,
+	void (*event)(void *, unsigned int), void *ev_arg);
+extern int ncld_del(struct ncld_sess *nsp, const char *fname);
+extern struct ncld_read *ncld_get(struct ncld_fh *fhp, int *error);
+extern void ncld_read_free(struct ncld_read *rp);
+extern int ncld_write(struct ncld_fh *, const void *data, long len);
+extern int ncld_trylock(struct ncld_fh *);
+extern int ncld_qlock(struct ncld_fh *);
+extern int ncld_unlock(struct ncld_fh *);
+extern void ncld_close(struct ncld_fh *);
+extern void ncld_sess_close(struct ncld_sess *s);
+extern void ncld_init(void);
+
+#endif /* __NCLD_H__ */
diff --git a/lib/cldc-dns.c b/lib/cldc-dns.c
index b534015..d67d941 100644
--- a/lib/cldc-dns.c
+++ b/lib/cldc-dns.c
@@ -67,9 +67,7 @@ int cldc_saveaddr(struct cldc_host *hp,
 
 	rc = getaddrinfo(hostname, portstr, &hints, &res0);
 	if (rc) {
-		HAIL_ERR(log, "getaddrinfo(%s,%s) failed: %s",
-			 hostname, portstr, gai_strerror(rc));
-		rc = -EINVAL;
+		rc = -(rc + 1200);
 		goto err_addr;
 	}
 
@@ -86,9 +84,7 @@ int cldc_saveaddr(struct cldc_host *hp,
 	}
 
 	if (!something_suitable) {
-		HAIL_ERR(log, "Host %s port %u has no addresses",
-			 hostname, port);
-		rc = -EINVAL;
+		rc = -1031;
 		goto err_suitable;
 	}
 
@@ -97,9 +93,6 @@ int cldc_saveaddr(struct cldc_host *hp,
 	hp->prio = priority;
 	hp->weight = weight;
 
-	HAIL_DEBUG(log, "%s: found CLD host %s prio %d weight %d",
-		   __func__, hostname, priority, weight);
-
 	freeaddrinfo(res0);
 	return 0;
 
@@ -117,35 +110,25 @@ err_name:
  * on YP-driven networks with nonqualified hostnames (at least for now).
  */
 static int cldc_make_fqdn(char *buf, int size, const char *srvname,
-			  const char *thishost, struct hail_log *log)
+			  const char *thishost)
 {
 	char *s;
 	int nlen;
 	int dlen;
 
 	nlen = strlen(srvname);
-	if (nlen >= size-20) {
-		HAIL_INFO(log, "%s: internal error (nlen %d size %d)",
-			  __func__, nlen, size);
+	if (nlen >= size-20)
 		return -1;
-	}
 
-	if (thishost == NULL) {
-		HAIL_INFO(log, "%s: internal error (null hostname)", __func__);
+	if (thishost == NULL)
 		return -1;
-	}
-	if ((s = strchr(thishost, '.')) == NULL) {
-		HAIL_INFO(log, "%s: hostname is not FQDN: \"%s\"",
-			  __func__, thishost);
+	if ((s = strchr(thishost, '.')) == NULL)
 		return -1;
-	}
 	s++;
 
 	dlen = strlen(s);
-	if (nlen + 1 + dlen + 1 > size) {
-		HAIL_INFO(log, "%s: domain is too long: \"%s\"", __func__, s);
+	if (nlen + 1 + dlen + 1 > size)
 		return -1;
-	}
 
 	memcpy(buf, srvname, nlen);
 	buf[nlen] = '.';
@@ -173,8 +156,7 @@ static void push_host(GList **host_list, struct cldc_host *hp_in)
  * This is not reentrant.  Better be called before any other threads
  * are started.
  */
-int cldc_getaddr(GList **host_list, const char *thishost,
-		struct hail_log *log)
+int cldc_getaddr(GList **host_list, const char *thishost, struct hail_log *log)
 {
 	enum { hostsz = 64 };
 	char cldb[hostsz];
@@ -195,19 +177,26 @@ int cldc_getaddr(GList **host_list, const char *thishost,
 	 * is a lookup in the DNS root (probably the standard-compliant
 	 * dot between "_cld" and "_udp" hurts us here).
 	 */
-	if (cldc_make_fqdn(cldb, hostsz, "_cld._udp", thishost, log) != 0)
+	if (cldc_make_fqdn(cldb, hostsz, "_cld._udp", thishost) != 0) {
+		if (log)
+			HAIL_INFO(log, "internal error in cldc_make_fqdn(%s)",
+				  thishost);
 		return -1;
+	}
 
 do_try_again:
 	rc = res_search(cldb, ns_c_in, ns_t_srv, resp, 512);
 	if (rc < 0) {
 		switch (h_errno) {
 		case HOST_NOT_FOUND:
-			HAIL_INFO(log, "%s: No _cld._udp SRV record", __func__);
+			if (log)
+				HAIL_INFO(log, "%s: No _cld._udp SRV record",
+					  __func__);
 			return -1;
 		case NO_DATA:
-			HAIL_INFO(log, "%s: Cannot find _cld._udp SRV record",
-				  __func__);
+			if (log)
+				HAIL_INFO(log, "%s: Cannot find _cld._udp"
+					  " SRV record", __func__);
 			return -1;
 		case TRY_AGAIN:
 			if (search_retries-- > 0)
@@ -215,20 +204,24 @@ do_try_again:
 			/* fall through */
 		case NO_RECOVERY:
 		default:
-			HAIL_ERR(log, "%s: res_search error (%d): %s",
-				 __func__, h_errno, hstrerror(h_errno));
+			if (log)
+				HAIL_ERR(log, "%s: res_search error (%d): %s",
+					 __func__, h_errno, hstrerror(h_errno));
 			return -1;
 		}
 	}
 	rlen = rc;
 
 	if (rlen == 0) {
-		HAIL_INFO(log, "%s: res_search returned empty reply", __func__);
+		if (log)
+			HAIL_INFO(log, "%s: res_search returned empty reply",
+				  __func__);
 		return -1;
 	}
 
 	if (ns_initparse(resp, rlen, &nsb) < 0) {
-		HAIL_ERR(log, "%s: ns_initparse error", __func__);
+		if (log)
+			HAIL_ERR(log, "%s: ns_initparse error", __func__);
 		return -1;
 	}
 
@@ -246,33 +239,46 @@ do_try_again:
 		case ns_t_srv:
 			rrlen = ns_rr_rdlen(rrb);
 			if (rrlen < 8) {	/* 2+2+2 and 2 for host */
-				HAIL_DEBUG(log, "%s: SRV len %d",
-					   __func__, rrlen);
+				if (log)
+					HAIL_DEBUG(log, "%s: SRV len %d",
+						   __func__, rrlen);
 				break;
 			}
 			p = ns_rr_rdata(rrb);
 			rc = dn_expand(resp, resp+rlen, p+6, hostb, hostsz);
 			if (rc < 0) {
-				HAIL_DEBUG(log, "%s: dn_expand error %d",
-					   __func__, rc);
+				if (log)
+					HAIL_DEBUG(log,
+						   "%s: dn_expand error %d",
+						   __func__, rc);
 				break;
 			}
 			if (rc < 2) {
-				HAIL_DEBUG(log, "%s: dn_expand short %d",
-					   __func__, rc);
+				if (log)
+					HAIL_DEBUG(log,
+						   "%s: dn_expand short %d",
+						   __func__, rc);
 				break;
 			}
 
 			if (cldc_saveaddr(&hp, ns_get16(p+0),
 					  ns_get16(p+2), ns_get16(p+4),
-					  rc, hostb, log))
+					  rc, hostb, NULL))
 				break;
 
+			if (log)
+				HAIL_DEBUG(log, "%s: found CLD host %s port %u"
+					   " prio %d weight %d",
+					   __func__, hp.host, hp.port,
+					   hp.prio, hp.weight);
+
 			push_host(host_list, &hp);
 			break;
 		case ns_t_cname:	/* impossible, but */
-			HAIL_DEBUG(log, "%s: CNAME in SRV request, ignored",
-				   __func__);
+			if (log)
+				HAIL_DEBUG(log,
+					   "%s: CNAME in SRV request, ignored",
+					   __func__);
 			break;
 		default:
 			;
diff --git a/lib/cldc.c b/lib/cldc.c
index 592dfcc..07b0d1c 100644
--- a/lib/cldc.c
+++ b/lib/cldc.c
@@ -30,13 +30,17 @@
 #include <errno.h>
 #include <time.h>
 #include <stdarg.h>
+#include <syslog.h>
+#include <poll.h>
 #include <openssl/sha.h>
 #include <openssl/hmac.h>
 #include <glib.h>
 #include <cld-private.h>
 #include <cldc.h>
 #include <cld_msg_rpc.h>
-#include <syslog.h>
+#include <ncld.h>
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
 
 enum {
 	CLDC_MSG_EXPIRE		= 5 * 60,
@@ -656,7 +660,11 @@ static void sess_expire(struct cldc_session *sess)
 	sess->ops->timer_ctl(sess->private, false, NULL, NULL, 0);
 
 	sess->ops->event(sess->private, sess, NULL, CE_SESS_FAILED);
-	/* FIXME why not sess_free here */
+	/*
+	 * Do not do sess_free here, or else the application is bound to
+	 * step into use-after-free. Only call sess_free when requested.
+	 * However, it may be requested right from this callback. Or later.
+	 */
 }
 
 static int sess_send_pkt(struct cldc_session *sess,
@@ -1275,6 +1283,850 @@ char *cldc_dirent_name(struct cld_dirent_cur *dc)
 }
 
 /*
+ * On error, return the code (not negated code like a kernel function would).
+ */
+static int ncld_getsrv(char **hostp, unsigned short *portp)
+{
+	enum { hostsz = 64 };
+	char hostb[hostsz];
+	GList *host_list = NULL;
+	GList *tmp;
+	struct cldc_host *hp;
+
+	if (gethostname(hostb, hostsz-1) < 0)
+		return errno;
+	hostb[hostsz-1] = 0;
+
+	if (cldc_getaddr(&host_list, hostb, NULL))
+		return 1001;
+
+	/*
+	 * This is a good place to compare weights and priorities, maybe later.
+	 * For now, just grab first host in the list.
+	 */
+	hp = host_list->data;		/* cannot be NULL if success above */
+	*hostp = hp->host;
+	*portp = hp->port;
+
+	for (tmp = host_list; tmp; tmp = tmp->next) {
+		hp = tmp->data;
+		free(hp->host);
+		free(hp);
+	}
+	g_list_free(host_list);
+	return 0;
+}
+
+static int ncld_gethost(char **hostp, unsigned short *portp,
+			const char *hostname, int port)
+{
+	if (port <= 0 || port >= 65536)
+		return EINVAL;
+	*portp = port;
+
+	if (!(*hostp = strdup(hostname)))
+		return ENOMEM;
+
+	return 0;
+}
+
+static void ncld_udp_timer_event(struct cld_timer *timer)
+{
+	struct ncld_sess *nsp = timer->userdata;
+	struct cldc_udp *udp = nsp->udp;
+
+	if (udp->cb)
+		udp->cb(udp->sess, udp->cb_private);
+}
+
+enum {
+	NCLD_CMD_END = 0,
+	NCLD_CMD_SESEV		/* argument - 4 bytes in host order */
+};
+
+/*
+ * All the error printouts are likely to be lost for daemons, but it's
+ * not a big deal. We abort instead of exist to indicate that something
+ * went wrong, so system features should report it (usualy as a core).
+ * When debugging, strace or -F mode will capture the output.
+ */
+static void ncld_thread_command(struct ncld_sess *nsp)
+{
+	ssize_t rrc;
+	unsigned char cmd;
+	uint32_t what;
+
+	rrc = read(nsp->to_thread[0], &cmd, 1);
+	if (rrc < 0) {
+		fprintf(stderr, "read error: %s\n", strerror(errno));
+		abort();
+	}
+	if (rrc < 1) {
+		fprintf(stderr, "short read\n");
+		abort();
+	}
+
+	if (cmd == NCLD_CMD_END) {
+		/* No answer to requestor. Wait with g_thread_join. */
+		g_thread_exit(NULL);
+	} else if (cmd == NCLD_CMD_SESEV) {
+		rrc = read(nsp->to_thread[0], &what, sizeof(uint32_t));
+		if (rrc < sizeof(uint32_t)) {
+			fprintf(stderr, "bad read param\n");
+			g_thread_exit(NULL);
+		}
+		if (nsp->event)
+			(*nsp->event)(nsp->event_arg, what);
+	} else {
+		fprintf(stderr, "bad command 0x%x\n", cmd);
+		abort();
+	}
+}
+
+static gpointer ncld_sess_thr(gpointer data)
+{
+	struct ncld_sess *nsp = data;
+	struct pollfd pfd[2];
+	time_t tmo;
+	int i;
+	int rc;
+
+	for (;;) {
+		g_mutex_lock(nsp->mutex);
+		tmo = cld_timers_run(&nsp->tlist);
+		g_mutex_unlock(nsp->mutex);
+
+		memset(pfd, 0, sizeof(pfd));
+		pfd[0].fd = nsp->to_thread[0];
+		pfd[0].events = POLLIN;
+		pfd[1].fd = nsp->udp->fd;
+		pfd[1].events = POLLIN;
+
+		rc = poll(pfd, 2, tmo ? tmo*1000 : -1);
+		if (rc == 0)
+			continue;
+		if (rc < 0) {
+			fprintf(stderr, "poll error: %s\n", strerror(errno));
+			abort();
+		}
+
+		for (i = 0; i < ARRAY_SIZE(pfd); i++) {
+			if (pfd[i].revents) {
+				if (i == 0) {
+					ncld_thread_command(nsp);
+				} else {
+					g_mutex_lock(nsp->mutex);
+					cldc_udp_receive_pkt(nsp->udp);
+					g_mutex_unlock(nsp->mutex);
+				}
+			}
+		}
+	}
+
+	return NULL;
+}
+
+/*
+ * Ask the thread to exit and wait until it does.
+ */
+static void ncld_thr_end(struct ncld_sess *nsp)
+{
+	unsigned char cmd;
+
+	cmd = NCLD_CMD_END;
+	write(nsp->to_thread[1], &cmd, 1);
+	g_thread_join(nsp->thread);
+}
+
+static bool ncld_p_timer_ctl(void *priv, bool add,
+			     int (*cb)(struct cldc_session *, void *),
+			     void *cb_priv, time_t secs)
+{
+	struct ncld_sess *nsp = priv;
+	struct cldc_udp *udp = nsp->udp;
+
+	if (add) {
+		udp->cb = cb;
+		udp->cb_private = cb_priv;
+		cld_timer_add(&nsp->tlist, &nsp->udp_timer, time(NULL) + secs);
+	} else {
+		cld_timer_del(&nsp->tlist, &nsp->udp_timer);
+	}
+	return true;
+}
+
+static int ncld_p_pkt_send(void *priv, const void *addr, size_t addrlen,
+			       const void *buf, size_t buflen)
+{
+	struct ncld_sess *nsp = priv;
+	return cldc_udp_pkt_send(nsp->udp, addr, addrlen, buf, buflen);
+}
+
+static void ncld_p_event(void *priv, struct cldc_session *csp,
+			 struct cldc_fh *fh, uint32_t what)
+{
+	struct ncld_sess *nsp = priv;
+	unsigned char cmd;
+
+	if (what == CE_SESS_FAILED) {
+		if (nsp->udp->sess != csp)
+			abort();
+		nsp->is_up = false;
+		/* XXX wake up all I/O waiters here */
+		/*
+		 * This is a trick. As a direct callback from clcd layer,
+		 * we are running under nsp->mutex, so we cannot call back
+		 * into a user of ncld. If we do, it may invoke another
+		 * ncld operation and deadlock. So, bump session callbacks
+		 * into the part of the helper thread that runs unlocked.
+		 */
+		cmd = NCLD_CMD_SESEV;
+		write(nsp->to_thread[1], &cmd, 1);
+		write(nsp->to_thread[1], &what, sizeof(what));
+	}
+}
+
+static struct cldc_ops ncld_ops = {
+	.timer_ctl	= ncld_p_timer_ctl,
+	.pkt_send	= ncld_p_pkt_send,
+	.event		= ncld_p_event,
+	.errlog		= NULL,
+};
+
+static int ncld_new_sess(struct cldc_call_opts *copts, enum cle_err_codes errc)
+{
+	struct ncld_sess *nsp = copts->private;
+
+	/*
+	 * All callbacks from cldc layer run on the context of the thread
+	 * with nsp->mutex locked, so we don't lock it again here.
+	 */
+	nsp->errc = errc;
+	nsp->is_up = true;
+	g_cond_broadcast(nsp->cond);
+	return 0;
+}
+
+static int ncld_wait_session(struct ncld_sess *nsp)
+{
+	g_mutex_lock(nsp->mutex);
+	while (!nsp->is_up)
+		g_cond_wait(nsp->cond, nsp->mutex);
+	g_mutex_unlock(nsp->mutex);
+	return nsp->errc;
+}
+
+/*
+ * Initiating session may take a while, since we retry failures.
+ * We promise that eventually we return from this function.
+ *
+ * On error, returns NULL and sets the error code (system errno if below 1000,
+ * otherwise our own mysterious codes that you should just print in decimal).
+ *
+ * Keep in mind that the (*event)() is likely to be called on a context
+ * of the extra thread that we spawn. At least we won't steal some random
+ * context and monkey with signals. Also, (*event)() may be called before
+ * this function returns, with the session going down, for example.
+ * This is kind of dirty, but oh well. Maybe we'll fix this later.
+ *
+ * @param host Host name (NULL if resolving SRV records)
+ * @param port Port
+ * @param error Buffer for the error code
+ * @param ev_func Session event function (ok to be NULL)
+ * @param ev_arg User-supplied argument to the session event function
+ * @param cld_user The user identifier to be used to authentication
+ * @param cld_key The user key to be used to authentication
+ */
+struct ncld_sess *ncld_sess_open(const char *host, int port, int *error,
+	void (*ev_func)(void *, unsigned int), void *ev_arg,
+	const char *cld_user, const char *cld_key)
+{
+	struct ncld_sess *nsp;
+	struct cldc_call_opts copts;
+	int err;
+	GError *gerr;
+	int rc;
+
+	err = ENOMEM;
+	nsp = malloc(sizeof(struct ncld_sess));
+	if (!nsp)
+		goto out_sesalloc;
+	memset(nsp, 0, sizeof(struct ncld_sess));
+	cld_timer_init(&nsp->udp_timer, "nsp-udp-timer", ncld_udp_timer_event,
+		       nsp);
+	nsp->mutex = g_mutex_new();
+	if (!nsp->mutex)
+		goto out_mutex;
+	nsp->cond = g_cond_new();
+	if (!nsp->cond)
+		goto out_cond;
+
+	if (!host) {
+		err = ncld_getsrv(&nsp->host, &nsp->port);
+		if (err)
+			goto out_srv;
+	} else {
+		err = ncld_gethost(&nsp->host, &nsp->port, host, port);
+		if (err)
+			goto out_srv;
+	}
+
+	nsp->event = ev_func;
+	nsp->event_arg = ev_arg;
+
+	if (pipe(nsp->to_thread) < 0) {
+		err = errno;
+		goto out_pipe_to;
+	}
+
+	if (cldc_udp_new(nsp->host, nsp->port, &nsp->udp)) {
+		err = 1023;
+		goto out_udp;
+	}
+
+	nsp->thread = g_thread_create(ncld_sess_thr, nsp, TRUE, &gerr);
+	if (nsp->thread == NULL) {
+		err = 1022;
+		goto out_thread;
+	}
+
+	memset(&copts, 0, sizeof(copts));
+	copts.cb = ncld_new_sess;
+	copts.private = nsp;
+	if (cldc_new_sess(&ncld_ops, &copts, nsp->udp->addr, nsp->udp->addr_len,
+			  cld_user, cld_key, nsp, &nsp->udp->sess)) {
+		err = 1024;
+		goto out_session;
+	}
+
+	/* nsp->udp->sess->log.verbose = 1; */
+
+	rc = ncld_wait_session(nsp);
+	if (rc) {
+		err = 1100 + rc % 1000;
+		goto out_start;
+	}
+
+	return nsp;
+
+out_start:
+	cldc_kill_sess(nsp->udp->sess);
+out_session:
+	ncld_thr_end(nsp);
+out_thread:
+	cldc_udp_free(nsp->udp);
+out_udp:
+	close(nsp->to_thread[0]);
+	close(nsp->to_thread[1]);
+out_pipe_to:
+	free(nsp->host);
+out_srv:
+	g_cond_free(nsp->cond);
+out_cond:
+	g_mutex_free(nsp->mutex);
+out_mutex:
+	free(nsp);
+out_sesalloc:
+	*error = err;
+	return NULL;
+}
+
+static int ncld_open_cb(struct cldc_call_opts *copts, enum cle_err_codes errc)
+{
+	struct ncld_fh *fhp = copts->private;
+
+	fhp->errc = errc;
+	fhp->is_open = true;
+	g_cond_broadcast(fhp->ses->cond);
+	return 0;
+}
+
+static int ncld_wait_open(struct ncld_fh *fhp)
+{
+	struct ncld_sess *nsp = fhp->ses;
+
+	g_mutex_lock(nsp->mutex);
+	while (!fhp->is_open)
+		g_cond_wait(nsp->cond, nsp->mutex);
+	g_mutex_unlock(nsp->mutex);
+	return fhp->errc;
+}
+
+/*
+ * We do not provide anything like ncld_set_callback because it inevitably
+ * leads to lost events. Unused arguments are not too onerous, so just
+ * put zero into the events mask if you don't want notifications.
+ *
+ * FIXME It's a moot point for now anyway, since we don't have unlock-notify,
+ * or a waiting lock anyway.
+ *
+ * On error, return NULL and set the error code (can be errno or our own code).
+ */
+struct ncld_fh *ncld_open(struct ncld_sess *nsp, const char *fname,
+	unsigned int mode, int *error, unsigned int events,
+	void (*ev_func)(void *, unsigned int), void *ev_arg)
+{
+	struct ncld_fh *fhp;
+	struct cldc_call_opts copts;
+	int err;
+	int rc;
+
+	err = EBUSY;
+	if (!nsp->is_up)
+		goto out_session;
+
+	err = ENOMEM;
+	fhp = malloc(sizeof(struct ncld_fh));
+	if (!fhp)
+		goto out_alloc;
+	memset(fhp, 0, sizeof(struct ncld_fh));
+	fhp->ses = nsp;
+	fhp->event_mask = events;
+	fhp->event_func = ev_func;
+	fhp->event_arg = ev_arg;
+
+	g_mutex_lock(nsp->mutex);
+	memset(&copts, 0, sizeof(copts));
+	copts.cb = ncld_open_cb;
+	copts.private = fhp;
+	rc = cldc_open(nsp->udp->sess, &copts, fname, mode, events, &fhp->fh);
+	if (rc) {
+		err = -rc;
+		g_mutex_unlock(nsp->mutex);
+		goto out_open;
+	}
+	g_mutex_unlock(nsp->mutex);
+
+	rc = ncld_wait_open(fhp);
+	if (rc) {
+		err = 1100 + rc;
+		goto out_start;
+	}
+
+	nsp->handles = g_list_prepend(nsp->handles, fhp);
+	return fhp;
+
+out_start:
+	/*
+	 * This is screwy, but we do nothing here. There is no way to free
+	 * a cldc file handle that failed its open. It is stuck in the
+	 * array of handles until the session closes (although it can be
+	 * garbage-collected if we're lucky).
+	 */
+out_open:
+	free(fhp);
+out_alloc:
+out_session:
+	*error = err;
+	return NULL;
+}
+
+struct ncld_delio {
+	struct ncld_sess *ses;
+	bool is_done;
+	int errc;
+};
+
+static int ncld_del_cb(struct cldc_call_opts *copts, enum cle_err_codes errc)
+{
+	struct ncld_delio *dp = copts->private;
+	struct ncld_sess *nsp = dp->ses;
+
+	dp->errc = errc;
+	dp->is_done = true;
+	g_cond_broadcast(nsp->cond);
+	return 0;
+}
+
+static int ncld_wait_del(struct ncld_delio *dp)
+{
+	struct ncld_sess *nsp = dp->ses;
+
+	g_mutex_lock(nsp->mutex);
+	while (!dp->is_done)
+		g_cond_wait(nsp->cond, nsp->mutex);
+	g_mutex_unlock(nsp->mutex);
+	return dp->errc;
+}
+
+int ncld_del(struct ncld_sess *nsp, const char *fname)
+{
+	struct cldc_call_opts copts;
+	struct ncld_delio dpb;
+	int rc;
+
+	if (!nsp->is_up)
+		return -EBUSY;
+
+	memset(&dpb, 0, sizeof(struct ncld_delio));
+	dpb.ses = nsp;
+
+	g_mutex_lock(nsp->mutex);
+	memset(&copts, 0, sizeof(copts));
+	copts.cb = ncld_del_cb;
+	copts.private = &dpb;
+	rc = cldc_del(nsp->udp->sess, &copts, fname);
+	if (rc) {
+		g_mutex_unlock(nsp->mutex);
+		return -rc;
+	}
+	/* XXX A delete operation is not accounted for end-session */
+	g_mutex_unlock(nsp->mutex);
+
+	rc = ncld_wait_del(&dpb);
+	if (rc)
+		return rc + 1100;
+
+	return 0;
+}
+
+static int ncld_read_cb(struct cldc_call_opts *copts, enum cle_err_codes errc)
+{
+	struct ncld_read *rp = copts->private;
+	struct ncld_fh *fhp = rp->fh;
+
+	if (errc) {
+		rp->errc = errc;
+	} else {
+		char *p;
+		size_t l;
+		cldc_call_opts_get_data(copts, &p, &l);
+		/* use assignments to defeat dumb gcc warnings. */
+		rp->ptr = p;
+		rp->length = l;
+	}
+	rp->is_done = true;
+	g_cond_broadcast(fhp->ses->cond);
+	return 0;
+}
+
+static int ncld_wait_read(struct ncld_read *rp)
+{
+	struct ncld_fh *fhp = rp->fh;
+	struct ncld_sess *nsp = fhp->ses;
+
+	g_mutex_lock(nsp->mutex);
+	while (!rp->is_done)
+		g_cond_wait(nsp->cond, nsp->mutex);
+	--fhp->nios;
+	g_mutex_unlock(nsp->mutex);
+	return rp->errc;
+}
+
+/*
+ * @error Error code buffer.
+ * @return Pointer to struct ncld_read or NULL if error.
+ */
+struct ncld_read *ncld_get(struct ncld_fh *fhp, int *error)
+{
+	struct ncld_sess *nsp = fhp->ses;
+	struct ncld_read *rp;
+	struct cldc_call_opts copts;
+	int rc;
+
+	if (!fhp->is_open) {
+		*error = EBUSY;
+		return NULL;
+	}
+
+	rp = malloc(sizeof(struct ncld_read));
+	if (!rp) {
+		*error = ENOMEM;
+		return NULL;
+	}
+	memset(rp, 0, sizeof(struct ncld_read));
+	rp->fh = fhp;
+
+	g_mutex_lock(nsp->mutex);
+	memset(&copts, 0, sizeof(copts));
+	copts.cb = ncld_read_cb;
+	copts.private = rp;
+	rc = cldc_get(fhp->fh, &copts, false);
+	if (rc) {
+		g_mutex_unlock(nsp->mutex);
+		free(rp);
+		*error = -rc;
+		return NULL;
+	}
+	fhp->nios++;
+	g_mutex_unlock(nsp->mutex);
+
+	rc = ncld_wait_read(rp);
+	if (rc) {
+		free(rp);
+		*error = rc + 1100;
+		return NULL;
+	}
+
+	return rp;
+}
+
+void ncld_read_free(struct ncld_read *rp)
+{
+
+	/*
+	 * FIXME: Actually the rp->ptr points to sess->msg_buf, so we
+	 * cannot issue 2 cldc_get independently.
+	 */
+	/* free(rp->ptr); */
+
+	free(rp);
+}
+
+struct ncld_genio {
+	struct ncld_fh *fh;
+	bool is_done;
+	int errc;
+};
+
+static int ncld_genio_cb(struct cldc_call_opts *copts, enum cle_err_codes errc)
+{
+	struct ncld_genio *ap = copts->private;
+	struct ncld_fh *fhp = ap->fh;
+
+	ap->errc = errc;
+	ap->is_done = true;
+	g_cond_broadcast(fhp->ses->cond);
+	return 0;
+}
+
+static int ncld_wait_genio(struct ncld_genio *ap)
+{
+	struct ncld_fh *fhp = ap->fh;
+	struct ncld_sess *nsp = fhp->ses;
+
+	g_mutex_lock(nsp->mutex);
+	while (!ap->is_done)
+		g_cond_wait(nsp->cond, nsp->mutex);
+	--fhp->nios;
+	g_mutex_unlock(nsp->mutex);
+	return ap->errc;
+}
+
+/*
+ * @return: Zero or error code.
+ */
+int ncld_write(struct ncld_fh *fhp, const void *data, long len)
+{
+	struct ncld_sess *nsp = fhp->ses;
+	struct cldc_call_opts copts;
+	struct ncld_genio apb;
+	int rc;
+
+	if (!fhp->is_open)
+		return -EBUSY;
+
+	memset(&apb, 0, sizeof(struct ncld_genio));
+	apb.fh = fhp;
+
+	g_mutex_lock(nsp->mutex);
+	memset(&copts, 0, sizeof(copts));
+	copts.cb = ncld_genio_cb;
+	copts.private = &apb;
+	rc = cldc_put(fhp->fh, &copts, data, len);
+	if (rc) {
+		g_mutex_unlock(nsp->mutex);
+		return -rc;
+	}
+	fhp->nios++;
+	g_mutex_unlock(nsp->mutex);
+
+	rc = ncld_wait_genio(&apb);
+	if (rc)
+		return rc + 1100;
+
+	return 0;
+}
+
+int ncld_trylock(struct ncld_fh *fhp)
+{
+	struct ncld_sess *nsp = fhp->ses;
+	struct cldc_call_opts copts;
+	struct ncld_genio apb;
+	int rc;
+
+	if (!fhp->is_open)
+		return -EBUSY;
+
+	memset(&apb, 0, sizeof(struct ncld_genio));
+	apb.fh = fhp;
+
+	g_mutex_lock(nsp->mutex);
+	memset(&copts, 0, sizeof(copts));
+	copts.cb = ncld_genio_cb;
+	copts.private = &apb;
+	rc = cldc_lock(fhp->fh, &copts, 0, false);
+	if (rc) {
+		g_mutex_unlock(nsp->mutex);
+		return -rc;
+	}
+	fhp->nios++;
+	g_mutex_unlock(nsp->mutex);
+
+	rc = ncld_wait_genio(&apb);
+	if (rc)
+		return rc + 1100;
+
+	return 0;
+}
+
+int ncld_unlock(struct ncld_fh *fhp)
+{
+	struct ncld_sess *nsp = fhp->ses;
+	struct cldc_call_opts copts;
+	struct ncld_genio apb;
+	int rc;
+
+	if (!fhp->is_open)
+		return -EBUSY;
+
+	memset(&apb, 0, sizeof(struct ncld_genio));
+	apb.fh = fhp;
+
+	g_mutex_lock(nsp->mutex);
+	memset(&copts, 0, sizeof(copts));
+	copts.cb = ncld_genio_cb;
+	copts.private = &apb;
+	rc = cldc_unlock(fhp->fh, &copts);
+	if (rc) {
+		g_mutex_unlock(nsp->mutex);
+		return -rc;
+	}
+	fhp->nios++;
+	g_mutex_unlock(nsp->mutex);
+
+	rc = ncld_wait_genio(&apb);
+	if (rc)
+		return rc + 1100;
+
+	return 0;
+}
+
+/*
+ * This probably does not do what you expect (or anything useful actually).
+ * When locks conflict, instead of waiting until the lock is acquired,
+ * we return when it was put in the queue on the server (with code 1).
+ * Applications using this supply a callback and a mask to ncld_open.
+ * FIXME: This does not work at present, since server does not post them.
+ */
+int ncld_qlock(struct ncld_fh *fhp)
+{
+	struct ncld_sess *nsp = fhp->ses;
+	struct cldc_call_opts copts;
+	struct ncld_genio apb;
+	int rc;
+
+	if (!fhp->is_open)
+		return -EBUSY;
+
+	memset(&apb, 0, sizeof(struct ncld_genio));
+	apb.fh = fhp;
+
+	g_mutex_lock(nsp->mutex);
+	memset(&copts, 0, sizeof(copts));
+	copts.cb = ncld_genio_cb;
+	copts.private = &apb;
+	rc = cldc_lock(fhp->fh, &copts, 0, true);
+	if (rc) {
+		g_mutex_unlock(nsp->mutex);
+		return -rc;
+	}
+	fhp->nios++;
+	g_mutex_unlock(nsp->mutex);
+
+	rc = ncld_wait_genio(&apb);
+	if (rc) {
+		if (rc != CLE_LOCK_PENDING)
+			return rc + 1100;
+		rc = 1;
+	}
+	return rc;
+}
+
+static int ncld_close_cb(struct cldc_call_opts *copts, enum cle_err_codes errc)
+{
+	struct ncld_fh *fhp = copts->private;
+
+	fhp->errc = errc;
+	fhp->is_open = false;
+	g_cond_broadcast(fhp->ses->cond);
+	return 0;
+}
+
+/*
+ * The poisoning in ncld_close is mostly for bug-catching. Do not try to
+ * force-close file handles if other threads bomb them I/Os. This cannot work
+ * for us, because users keep pointers, not file descriptor numbers.
+ * Applications should stop application I/O first, then close.
+ */
+void ncld_close(struct ncld_fh *fhp)
+{
+	struct ncld_sess *nsp = fhp->ses;
+	struct cldc_call_opts copts;
+	int rc;
+
+	if (!fhp->is_open)
+		abort();
+
+	g_mutex_lock(nsp->mutex);
+	memset(&copts, 0, sizeof(copts));
+	copts.cb = ncld_close_cb;
+	copts.private = fhp;
+	rc = cldc_close(fhp->fh, &copts);
+	g_mutex_unlock(nsp->mutex);
+
+	if (rc == 0) {
+		g_mutex_lock(nsp->mutex);
+		while (fhp->is_open)
+			g_cond_wait(nsp->cond, nsp->mutex);
+		g_mutex_unlock(nsp->mutex);
+		/* At this point, we ignore fhp->errc. */
+	}
+
+	/*
+	 * The cldc layer dowes not allow us to kill handles willy-nilly,
+	 * so the only thing we can do is to wait for I/Os to terminate.
+	 *
+	 * N.B.: this is making use of the fact that we only have one
+	 * conditional per session, and therefore end-of-I/O pokes us here.
+	 */
+	g_mutex_lock(nsp->mutex);
+	while (fhp->nios)
+		g_cond_wait(nsp->cond, nsp->mutex);
+	g_mutex_unlock(nsp->mutex);
+
+	nsp->handles = g_list_remove_all(nsp->handles, fhp);
+	free(fhp);
+}
+
+static void ncld_func_close(gpointer data, gpointer priv)
+{
+	ncld_close(data);
+}
+
+void ncld_sess_close(struct ncld_sess *nsp)
+{
+
+	g_list_foreach(nsp->handles, ncld_func_close, NULL);
+	g_list_free(nsp->handles);
+
+	cldc_kill_sess(nsp->udp->sess);
+	ncld_thr_end(nsp);
+	cldc_udp_free(nsp->udp);
+	close(nsp->to_thread[0]);
+	close(nsp->to_thread[1]);
+	g_cond_free(nsp->cond);
+	g_mutex_free(nsp->mutex);
+	free(nsp->host);
+	free(nsp);
+}
+
+void ncld_init(void)
+{
+	cldc_init();
+}
+
+/*
  * For extra safety, call cldc_init after g_thread_init, if present.
  * Currently we just call srand(), but since we use GLib, we may need
  * to add some Glib stuff here and that must come after g_thread_init.
diff --git a/test/Makefile.am b/test/Makefile.am
index ff4d5c7..9e66458 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -26,15 +26,10 @@ check_PROGRAMS		= it-works \
 			  save-file-event load-file-event lock-file-event
 
 TESTLDADD		= ../lib/libcldc.la	\
-			  libtest.a		\
 			  @GLIB_LIBS@ @CRYPTO_LIBS@
 it_works_LDADD		= $(TESTLDADD)
 save_file_event_LDADD	= $(TESTLDADD)
 load_file_event_LDADD	= $(TESTLDADD)
 lock_file_event_LDADD	= $(TESTLDADD)
 
-noinst_LIBRARIES	= libtest.a
-
-libtest_a_SOURCES	= util.c
-
 TESTS_ENVIRONMENT=top_srcdir=$(top_srcdir)
diff --git a/test/it-works.c b/test/it-works.c
index 085ea6b..d8f9ec1 100644
--- a/test/it-works.c
+++ b/test/it-works.c
@@ -26,95 +26,17 @@
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
-#include <cldc.h>
+#include <ncld.h>
 #include "test.h"
 
-static struct cldc_udp *udp;
-static struct cld_timer udp_tm;
-static struct cld_timer_list tlist;
-
-static bool do_timer_ctl(void *priv, bool add,
-			 int (*cb)(struct cldc_session *, void *),
-			 void *cb_priv, time_t secs)
-{
-	if (priv != udp) {
-		fprintf(stderr, "IE0: misuse of timer\n");
-		exit(1);
-	}
-
-	if (add) {
-		udp->cb = cb;
-		udp->cb_private = cb_priv;
-		cld_timer_add(&tlist, &udp_tm, time(NULL) + secs);
-	} else {
-		cld_timer_del(&tlist, &udp_tm);
-	}
-
-	return true;
-}
-
-static void timer_udp_event(struct cld_timer *timer)
-{
-	if (timer->userdata != udp) {
-		fprintf(stderr, "IE1: misuse of timer\n");
-		exit(1);
-	}
-
-	if (udp->cb)
-		udp->cb(udp->sess, udp->cb_private);
-}
-
-static void do_event(void *private, struct cldc_session *sess,
-		     struct cldc_fh *fh, uint32_t event_mask)
-{
-	fprintf(stderr, "EVENT(%x)\n", event_mask);
-}
-
-static int end_sess_cb(struct cldc_call_opts *copts, enum cle_err_codes errc)
-{
-	if (errc != CLE_OK) {
-		fprintf(stderr, "end-sess failed: %d\n", errc);
-		exit(1);
-	}
-
-	/* session ended; success */
-	exit(0);
-	return 0;
-}
-
-static int new_sess_cb(struct cldc_call_opts *copts_in, enum cle_err_codes errc)
-{
-	struct cldc_call_opts copts;
-	int rc;
-
-	if (errc != CLE_OK) {
-		fprintf(stderr, "new-sess failed: %d\n", errc);
-		exit(1);
-	}
-
-	memset(&copts, 0, sizeof(copts));
-	copts.cb = end_sess_cb;
-
-	rc = cldc_end_sess(udp->sess, &copts);
-	if (rc) {
-		fprintf(stderr, "cldc_end_sess failed: %d\n", rc);
-		exit(1);
-	}
-
-	return 0;
-}
-
-static struct cldc_ops ops = {
-	.timer_ctl		= do_timer_ctl,
-	.pkt_send		= cldc_udp_pkt_send,
-	.event			= do_event,
-};
-
-static int init(void)
+int main (int argc, char *argv[])
 {
-	int rc;
+	struct ncld_sess *nsp;
+	int error;
 	int port;
-	struct cldc_call_opts copts;
+
+	g_thread_init(NULL);
+	ncld_init();
 
 	port = cld_readport(TEST_PORTFILE_CLD);
 	if (port < 0)
@@ -122,32 +44,15 @@ static int init(void)
 	if (port == 0)
 		return -1;
 
-	rc = cldc_udp_new("localhost", port, &udp);
-	if (rc)
-		return rc;
-
-	cld_timer_init(&udp_tm, "udp-timer", timer_udp_event, udp);
-
-	memset(&copts, 0, sizeof(copts));
-	copts.cb = new_sess_cb;
-
-	rc = cldc_new_sess(&ops, &copts, udp->addr, udp->addr_len,
-			   "testuser", "testuser", udp, &udp->sess);
-	if (rc)
-		return rc;
-
-	// udp->sess->verbose = true;
-
-	return 0;
-}
+	nsp = ncld_sess_open(TEST_HOST, port, &error, NULL, NULL,
+			     TEST_USER, TEST_USER_KEY);
+	if (!nsp) {
+		fprintf(stderr, "ncld_sess_open(host %s port %u) failed: %d\n",
+			TEST_HOST, port, error);
+		exit(1);
+	}
 
-int main (int argc, char *argv[])
-{
-	g_thread_init(NULL);
-	cldc_init();
-	if (init())
-		return 1;
-	test_loop(&tlist, udp);
+	ncld_sess_close(nsp);
 	return 0;
 }
 
diff --git a/test/load-file-event.c b/test/load-file-event.c
index c328744..a267075 100644
--- a/test/load-file-event.c
+++ b/test/load-file-event.c
@@ -18,7 +18,7 @@
  */
 
 /*
- * Load a file from CLD.
+ * Load a file from CLD (written there by the previous test).
  */
 
 #define _GNU_SOURCE
@@ -30,239 +30,61 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
-#include <cldc.h>
+#include <ncld.h>
 #include "test.h"
 
-struct run {
-	struct cldc_udp *udp;
-	struct cld_timer_list tlist;
-	struct cld_timer tmr_udp;
-	struct cldc_fh *fh;
-	char *fname;
-};
-
-static int new_sess_cb(struct cldc_call_opts *copts, enum cle_err_codes errc);
-static int open_1_cb(struct cldc_call_opts *coptarg, enum cle_err_codes errc);
-static int read_1_cb(struct cldc_call_opts *coptarg, enum cle_err_codes errc);
-static int close_1_cb(struct cldc_call_opts *coptarg, enum cle_err_codes errc);
-static int end_sess_cb(struct cldc_call_opts *copts, enum cle_err_codes errc);
-
-static bool do_timer_ctl(void *priv, bool add,
-			 int (*cb)(struct cldc_session *, void *),
-			 void *cb_priv, time_t secs)
-{
-	struct run *rp = priv;
-
-	if (add) {
-		rp->udp->cb = cb;
-		rp->udp->cb_private = cb_priv;
-		cld_timer_add(&rp->tlist, &rp->tmr_udp, time(NULL) + secs);
-	} else {
-		cld_timer_del(&rp->tlist, &rp->tmr_udp);
-	}
-
-	return true;
-}
-
-static int do_pkt_send(void *priv, const void *addr, size_t addrlen,
-		       const void *buf, size_t buflen)
-{
-	struct run *rp = priv;
-	return cldc_udp_pkt_send(rp->udp, addr, addrlen, buf, buflen);
-}
-
-static void timer_udp_event(struct cld_timer *timer)
-{
-	struct run *rp = timer->userdata;
-	struct cldc_udp *udp = rp->udp;
-
-	if (udp->cb)
-		udp->cb(udp->sess, udp->cb_private);
-}
-
-static void do_event(void *private, struct cldc_session *sess,
-		     struct cldc_fh *fh, uint32_t event_mask)
-{
-	fprintf(stderr, "EVENT(0x%x)\n", event_mask);
-}
-
-static int new_sess_cb(struct cldc_call_opts *coptarg, enum cle_err_codes errc)
+int main(int argc, char *argv[])
 {
-	struct run *rp = coptarg->private;
-	struct cldc_call_opts copts;
-	int rc;
-
-	if (errc != CLE_OK) {
-		fprintf(stderr, "new-sess failed: %d\n", errc);
-		exit(1);
-	}
+	struct ncld_sess *nsp;
+	struct ncld_fh *fhp;
+	struct ncld_read *rp;
+	int port;
+	int error;
 
-	/* We use a fixed file name because we contact a private copy of CLD */
-	memset(&copts, 0, sizeof(copts));
-	copts.cb = open_1_cb;
-	copts.private = rp;
-	rc = cldc_open(rp->udp->sess, &copts, rp->fname,
-		       COM_READ,
-		       CE_SESS_FAILED, &rp->fh);
-	if (rc) {
-		fprintf(stderr, "cldc_open call error %d\n", rc);
-		exit(1);
-	}
-	return 0;
-}
+	g_thread_init(NULL);
+	ncld_init();
 
-static int open_1_cb(struct cldc_call_opts *coptarg, enum cle_err_codes errc)
-{
-	struct run *rp = coptarg->private;
-	struct cldc_call_opts copts;
-	int rc;
+	port = cld_readport(TEST_PORTFILE_CLD);
+	if (port < 0)
+		return port;
+	if (port == 0)
+		return -1;
 
-	if (errc != CLE_OK) {
-		fprintf(stderr, "first-open failed: %d\n", errc);
-		exit(1);
-	}
-	if (rp->fh == NULL) {
-		fprintf(stderr, "first-open NULL fh\n");
-		exit(1);
-	}
-	if (!rp->fh->valid) {
-		fprintf(stderr, "first-open invalid fh\n");
+	nsp = ncld_sess_open(TEST_HOST, port, &error, NULL, NULL,
+			     TEST_USER, TEST_USER_KEY);
+	if (!nsp) {
+		fprintf(stderr, "ncld_sess_open(host %s port %u) failed: %d\n",
+			TEST_HOST, port, error);
 		exit(1);
 	}
 
-	memset(&copts, 0, sizeof(copts));
-	copts.cb = read_1_cb;
-	copts.private = rp;
-	rc = cldc_get(rp->fh, &copts, false);
-	if (rc) {
-		fprintf(stderr, "cldc_get call error %d\n", rc);
+	fhp = ncld_open(nsp, TFNAME, COM_READ, &error, 0, NULL, NULL);
+	if (!fhp) {
+		fprintf(stderr, "ncld_open(%s) failed: %d\n", TFNAME, error);
 		exit(1);
 	}
 
-	return 0;
-}
-
-static int read_1_cb(struct cldc_call_opts *coptarg, enum cle_err_codes errc)
-{
-	struct run *rp = coptarg->private;
-	struct cldc_call_opts copts;
-	char *data;
-	size_t data_len;
-	int rc;
-
-	if (errc != CLE_OK) {
-		fprintf(stderr, "first-get failed: %d\n", errc);
+	rp = ncld_get(fhp, &error);
+	if (!rp) {
+		fprintf(stderr, "ncld_get failed: %d\n", error);
 		exit(1);
 	}
 
-	cldc_call_opts_get_data(coptarg, &data, &data_len);
-
-	if (data_len != TESTLEN) {
-		fprintf(stderr, "Bad CLD file length %zu\n", data_len);
+	if (rp->length != TESTLEN) {
+		fprintf(stderr, "Bad CLD file length %ld\n", rp->length);
 		exit(1);
 	}
 
-	if (memcmp(data, TESTSTR, TESTLEN)) {
+	if (memcmp(rp->ptr, TESTSTR, TESTLEN)) {
 		fprintf(stderr, "Bad CLD file content\n");
 		exit(1);
 	}
 
-	memset(&copts, 0, sizeof(copts));
-	copts.cb = close_1_cb;
-	copts.private = rp;
-	rc = cldc_close(rp->fh, &copts);
-	if (rc) {
-		fprintf(stderr, "cldc_close call error %d\n", rc);
-		exit(1);
-	}
-
-	return 0;
-}
-
-static int close_1_cb(struct cldc_call_opts *coptarg, enum cle_err_codes errc)
-{
-	struct run *rp = coptarg->private;
-	struct cldc_call_opts copts;
-	int rc;
-
-	if (errc != CLE_OK) {
-		fprintf(stderr, "first-close failed: %d\n", errc);
-		exit(1);
-	}
-	rp->fh = NULL;
-
-	memset(&copts, 0, sizeof(copts));
-	copts.cb = end_sess_cb;
-	copts.private = rp;
-	rc = cldc_end_sess(rp->udp->sess, &copts);
-	if (rc) {
-		fprintf(stderr, "cldc_end_sess call error %d\n", rc);
-		exit(1);
-	}
-	return 0;
-}
-
-static int end_sess_cb(struct cldc_call_opts *copts, enum cle_err_codes errc)
-{
-	if (errc != CLE_OK) {
-		fprintf(stderr, "end-sess failed: %d\n", errc);
-		exit(1);
-	}
-
-	/* session ended; success */
-	exit(0);
-
-	return 0;
-}
+	ncld_read_free(rp);
 
-static struct run run;
-
-static struct cldc_ops ops = {
-	.timer_ctl		= do_timer_ctl,
-	.pkt_send		= do_pkt_send,
-	.event			= do_event,
-};
-
-static int init(char *name)
-{
-	int rc;
-	int port;
-	struct cldc_call_opts copts;
-
-	run.fname = name;
-
-	port = cld_readport(TEST_PORTFILE_CLD);
-	if (port < 0)
-		return port;
-	if (port == 0)
-		return -1;
-
-	cld_timer_init(&run.tmr_udp, "udp-timer", timer_udp_event, &run);
-
-	rc = cldc_udp_new(TEST_HOST, port, &run.udp);
-	if (rc)
-		return rc;
-
-	memset(&copts, 0, sizeof(copts));
-	copts.cb = new_sess_cb;
-	copts.private = &run;
-	rc = cldc_new_sess(&ops, &copts, run.udp->addr, run.udp->addr_len,
-			   TEST_USER, TEST_USER_KEY, &run, &run.udp->sess);
-	if (rc)
-		return rc;
-
-	// run.udp->sess->verbose = true;
-
-	return 0;
-}
-
-int main(int argc, char *argv[])
-{
-	g_thread_init(NULL);
-	cldc_init();
-	if (init(TFNAME))
-		return 1;
-	test_loop(&run.tlist, run.udp);
+	/* These two are perfect places to hang or crash, so don't just exit. */
+	ncld_close(fhp);
+	ncld_sess_close(nsp);
 	return 0;
 }
 
diff --git a/test/lock-file-event.c b/test/lock-file-event.c
index 2c99468..64e6020 100644
--- a/test/lock-file-event.c
+++ b/test/lock-file-event.c
@@ -25,267 +25,72 @@
 #include "cld-config.h"
 
 #include <sys/types.h>
-#include <unistd.h>
 #include <time.h>
 #include <stdlib.h>
 #include <stdio.h>
-#include <string.h>
-#include <cldc.h>
+#include <ncld.h>
 #include "test.h"
 
-struct run {
-	struct cldc_udp *udp;
-	struct cld_timer_list tlist;
-	struct cld_timer tmr_test;
-	struct cld_timer tmr_udp;
-	struct cldc_fh *fh;
-	char buf[LOCKLEN];
-};
-
-static int new_sess_cb(struct cldc_call_opts *copts, enum cle_err_codes errc);
-static int open_1_cb(struct cldc_call_opts *coptarg, enum cle_err_codes errc);
-static int write_1_cb(struct cldc_call_opts *coptarg, enum cle_err_codes errc);
-static int lock_1_cb(struct cldc_call_opts *coptarg, enum cle_err_codes errc);
-static void timer_1(struct run *rp);
-static int close_1_cb(struct cldc_call_opts *coptarg, enum cle_err_codes errc);
-static int end_sess_cb(struct cldc_call_opts *copts, enum cle_err_codes errc);
-
-static bool do_timer_ctl(void *priv, bool add,
-			 int (*cb)(struct cldc_session *, void *),
-			 void *cb_priv, time_t secs)
-{
-	struct run *rp = priv;
-
-	if (add) {
-		rp->udp->cb = cb;
-		rp->udp->cb_private = cb_priv;
-		cld_timer_add(&rp->tlist, &rp->tmr_udp, time(NULL) + secs);
-	} else {
-		cld_timer_del(&rp->tlist, &rp->tmr_udp);
-	}
-
-	return true;
-}
-
-static int do_pkt_send(void *priv, const void *addr, size_t addrlen,
-		       const void *buf, size_t buflen)
-{
-	struct run *rp = priv;
-	return cldc_udp_pkt_send(rp->udp, addr, addrlen, buf, buflen);
-}
-
-static void timer_udp_event(struct cld_timer *timer)
-{
-	struct run *rp = timer->userdata;
-	struct cldc_udp *udp = rp->udp;
-
-	if (udp->cb)
-		udp->cb(udp->sess, udp->cb_private);
-}
-
-static void do_event(void *private, struct cldc_session *sess,
-		     struct cldc_fh *fh, uint32_t event_mask)
-{
-	fprintf(stderr, "EVENT(0x%x)\n", event_mask);
-}
-
-static int new_sess_cb(struct cldc_call_opts *coptarg, enum cle_err_codes errc)
+int main (int argc, char *argv[])
 {
-	struct run *rp = coptarg->private;
-	struct cldc_call_opts copts;
+	struct ncld_sess *nsp;
+	struct ncld_fh *fhp;
+	int port;
+	struct timespec tm;
+	int error;
 	int rc;
 
-	if (errc != CLE_OK) {
-		fprintf(stderr, "new-sess failed: %d\n", errc);
-		exit(1);
-	}
-
-	/* We use a fixed file name because we contact a private copy of CLD */
-	memset(&copts, 0, sizeof(copts));
-	copts.cb = open_1_cb;
-	copts.private = rp;
-	rc = cldc_open(rp->udp->sess, &copts, TLNAME,
-		       COM_WRITE | COM_LOCK | COM_CREATE,
-		       CE_SESS_FAILED, &rp->fh);
-	if (rc) {
-		fprintf(stderr, "cldc_open call error %d\n", rc);
-		exit(1);
-	}
-	return 0;
-}
-
-static int open_1_cb(struct cldc_call_opts *coptarg, enum cle_err_codes errc)
-{
-	struct run *rp = coptarg->private;
-	struct cldc_call_opts copts;
-	int rc;
+	g_thread_init(NULL);
+	ncld_init();
 
-	if (errc != CLE_OK) {
-		fprintf(stderr, "first-open failed: %d\n", errc);
-		exit(1);
-	}
-	if (rp->fh == NULL) {
-		fprintf(stderr, "first-open NULL fh\n");
-		exit(1);
-	}
-	if (!rp->fh->valid) {
-		fprintf(stderr, "first-open invalid fh\n");
-		exit(1);
-	}
+	port = cld_readport(TEST_PORTFILE_CLD);
+	if (port < 0)
+		return port;
+	if (port == 0)
+		return -1;
 
-	memset(&copts, 0, sizeof(copts));
-	copts.cb = write_1_cb;
-	copts.private = rp;
-	rc = cldc_put(rp->fh, &copts, rp->buf, LOCKLEN);
-	if (rc) {
-		fprintf(stderr, "cldc_put call error %d\n", rc);
+	nsp = ncld_sess_open(TEST_HOST, port, &error, NULL, NULL,
+			     TEST_USER, TEST_USER_KEY);
+	if (!nsp) {
+		fprintf(stderr, "ncld_sess_open(host %s port %u) failed: %d\n",
+			TEST_HOST, port, error);
 		exit(1);
 	}
-	return 0;
-}
 
-static int write_1_cb(struct cldc_call_opts *coptarg, enum cle_err_codes errc)
-{
-	struct run *rp = coptarg->private;
-	struct cldc_call_opts copts;
-	int rc;
-
-	if (errc != CLE_OK) {
-		fprintf(stderr, "first-put failed: %d\n", errc);
+	fhp = ncld_open(nsp, TLNAME, COM_WRITE | COM_LOCK | COM_CREATE,
+			&error, 0, NULL, NULL);
+	if (!fhp) {
+		fprintf(stderr, "ncld_open(%s) failed: %d\n", TLNAME, error);
 		exit(1);
 	}
 
-	memset(&copts, 0, sizeof(copts));
-	copts.cb = lock_1_cb;
-	copts.private = rp;
-	rc = cldc_lock(rp->fh, &copts, 0, false);
+	rc = ncld_write(fhp, LOCKSTR, LOCKLEN);
 	if (rc) {
-		fprintf(stderr, "cldc_lock call error %d\n", rc);
-		exit(1);
-	}
-	return 0;
-}
-
-static int lock_1_cb(struct cldc_call_opts *coptarg, enum cle_err_codes errc)
-{
-	struct run *rp = coptarg->private;
-
-	if (errc != CLE_OK) {
-		fprintf(stderr, "first-lock failed: %d\n", errc);
+		fprintf(stderr, "ncld_write failed: %d\n", rc);
 		exit(1);
 	}
 
-	/* Idle for 40s to verify that session sustains a protocol ping. */
-	cld_timer_add(&rp->tlist, &rp->tmr_test, time(NULL) + 40);
-	return 0;
-}
-
-static void timer_test_event(struct cld_timer *timer)
-{
-	struct run *rp = timer->userdata;
-
-	timer_1(rp);
-}
-
-static void timer_1(struct run *rp)
-{
-	struct cldc_call_opts copts;
-	int rc;
-
-	memset(&copts, 0, sizeof(copts));
-	copts.cb = close_1_cb;
-	copts.private = rp;
-	rc = cldc_close(rp->fh, &copts);
+	rc = ncld_trylock(fhp);
 	if (rc) {
-		fprintf(stderr, "cldc_close call error %d\n", rc);
+		fprintf(stderr, "ncld_trylock failed: %d\n", rc);
 		exit(1);
 	}
-}
-
-static int close_1_cb(struct cldc_call_opts *coptarg, enum cle_err_codes errc)
-{
-	struct run *rp = coptarg->private;
-	struct cldc_call_opts copts;
-	int rc;
 
-	if (errc != CLE_OK) {
-		fprintf(stderr, "first-close failed: %d\n", errc);
-		exit(1);
-	}
-	rp->fh = NULL;
+	printf("idling 40s...\n"); fflush(stdout);
+	/* Idle for 40s to verify that session sustains a protocol ping. */
+	tm.tv_sec = 40;
+	tm.tv_nsec = 0;
+	nanosleep(&tm, NULL);
 
-	memset(&copts, 0, sizeof(copts));
-	copts.cb = end_sess_cb;
-	copts.private = rp;
-	rc = cldc_end_sess(rp->udp->sess, &copts);
+	rc = ncld_unlock(fhp);
 	if (rc) {
-		fprintf(stderr, "cldc_end_sess call error %d\n", rc);
-		exit(1);
-	}
-	return 0;
-}
-
-static int end_sess_cb(struct cldc_call_opts *copts, enum cle_err_codes errc)
-{
-	if (errc != CLE_OK) {
-		fprintf(stderr, "end-sess failed: %d\n", errc);
+		fprintf(stderr, "ncld_unlock failed: %d\n", rc);
 		exit(1);
 	}
 
-	/* session ended; success */
-	exit(0);
-	return 0;
-}
-
-static struct run run;
-
-static struct cldc_ops ops = {
-	.timer_ctl		= do_timer_ctl,
-	.pkt_send		= do_pkt_send,
-	.event			= do_event,
-};
-
-static int init(void)
-{
-	int rc;
-	int port;
-	struct cldc_call_opts copts;
-
-	memcpy(run.buf, LOCKSTR, LOCKLEN);
-
-	port = cld_readport(TEST_PORTFILE_CLD);
-	if (port < 0)
-		return port;
-	if (port == 0)
-		return -1;
-
-	cld_timer_init(&run.tmr_test, "lock-timer", timer_test_event, &run);
-	cld_timer_init(&run.tmr_udp, "udp-timer", timer_udp_event, &run);
-
-	rc = cldc_udp_new(TEST_HOST, port, &run.udp);
-	if (rc)
-		return rc;
-
-	memset(&copts, 0, sizeof(copts));
-	copts.cb = new_sess_cb;
-	copts.private = &run;
-	rc = cldc_new_sess(&ops, &copts, run.udp->addr, run.udp->addr_len,
-			   TEST_USER, TEST_USER_KEY, &run, &run.udp->sess);
-	if (rc)
-		return rc;
-
-	// run.udp->sess->verbose = true;
-
-	return 0;
-}
-
-int main (int argc, char *argv[])
-{
-	g_thread_init(NULL);
-	cldc_init();
-	if (init())
-		return 1;
-	test_loop(&run.tlist, run.udp);
+	/* These two are perfect places to hang or crash, so don't just exit. */
+	ncld_close(fhp);
+	ncld_sess_close(nsp);
 	return 0;
 }
 
diff --git a/test/save-file-event.c b/test/save-file-event.c
index 1b46d29..a91dc65 100644
--- a/test/save-file-event.c
+++ b/test/save-file-event.c
@@ -30,205 +30,18 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
-#include <cldc.h>
+#include <ncld.h>
 #include "test.h"
 
-struct run {
-	struct cldc_udp *udp;
-	struct cld_timer_list tlist;
-	struct cld_timer tmr_udp;
-	struct cldc_fh *fh;
-	char *fname;
-	char *buf;
-	int len;
-};
-
-static int new_sess_cb(struct cldc_call_opts *copts, enum cle_err_codes errc);
-static int open_1_cb(struct cldc_call_opts *coptarg, enum cle_err_codes errc);
-static int write_1_cb(struct cldc_call_opts *coptarg, enum cle_err_codes errc);
-static void call_close(struct run *rp);
-static int close_1_cb(struct cldc_call_opts *coptarg, enum cle_err_codes errc);
-static int end_sess_cb(struct cldc_call_opts *copts, enum cle_err_codes errc);
-
-static bool do_timer_ctl(void *priv, bool add,
-			 int (*cb)(struct cldc_session *, void *),
-			 void *cb_priv, time_t secs)
-{
-	struct run *rp = priv;
-
-	if (add) {
-		rp->udp->cb = cb;
-		rp->udp->cb_private = cb_priv;
-		cld_timer_add(&rp->tlist, &rp->tmr_udp, time(NULL) + secs);
-	} else {
-		cld_timer_del(&rp->tlist, &rp->tmr_udp);
-	}
-	return true;
-}
-
-static int do_pkt_send(void *priv, const void *addr, size_t addrlen,
-		       const void *buf, size_t buflen)
-{
-	struct run *rp = priv;
-	return cldc_udp_pkt_send(rp->udp, addr, addrlen, buf, buflen);
-}
-
-static void timer_udp_event(struct cld_timer *timer)
-{
-	struct run *rp = timer->userdata;
-	struct cldc_udp *udp;
-
-	udp = rp->udp;
-	if (udp->cb)
-		udp->cb(udp->sess, udp->cb_private);
-}
-
-static void do_event(void *private, struct cldc_session *sess,
-		     struct cldc_fh *fh, uint32_t event_mask)
-{
-	fprintf(stderr, "EVENT(0x%x)\n", event_mask);
-}
-
-static int new_sess_cb(struct cldc_call_opts *coptarg, enum cle_err_codes errc)
-{
-	struct run *rp = coptarg->private;
-	struct cldc_call_opts copts;
-	int rc;
-
-	if (errc != CLE_OK) {
-		fprintf(stderr, "new-sess failed: %d\n", errc);
-		exit(1);
-	}
-
-	/* We use a fixed file name because we contact a private copy of CLD */
-	memset(&copts, 0, sizeof(copts));
-	copts.cb = open_1_cb;
-	copts.private = rp;
-	rc = cldc_open(rp->udp->sess, &copts, rp->fname,
-		       COM_WRITE | COM_CREATE,
-		       CE_SESS_FAILED, &rp->fh);
-	if (rc) {
-		fprintf(stderr, "cldc_open call error %d\n", rc);
-		exit(1);
-	}
-	return 0;
-}
-
-static int open_1_cb(struct cldc_call_opts *coptarg, enum cle_err_codes errc)
-{
-	struct run *rp = coptarg->private;
-	struct cldc_call_opts copts;
-	int rc;
-
-	if (errc != CLE_OK) {
-		fprintf(stderr, "first-open failed: %d\n", errc);
-		exit(1);
-	}
-	if (rp->fh == NULL) {
-		fprintf(stderr, "first-open NULL fh\n");
-		exit(1);
-	}
-	if (!rp->fh->valid) {
-		fprintf(stderr, "first-open invalid fh\n");
-		exit(1);
-	}
-
-	if (rp->len == 0) {
-		call_close(rp);
-	} else {
-		memset(&copts, 0, sizeof(copts));
-		copts.cb = write_1_cb;
-		copts.private = rp;
-		rc = cldc_put(rp->fh, &copts, rp->buf, rp->len);
-		if (rc) {
-			fprintf(stderr, "cldc_put call error %d for %d bytes\n",
-				rc, rp->len);
-			exit(1);
-		}
-	}
-	return 0;
-}
-
-static int write_1_cb(struct cldc_call_opts *coptarg, enum cle_err_codes errc)
-{
-	struct run *rp = coptarg->private;
-
-	if (errc != CLE_OK) {
-		fprintf(stderr, "first-put failed: %d\n", errc);
-		exit(1);
-	}
-
-	call_close(rp);
-	return 0;
-}
-
-static void call_close(struct run *rp)
-{
-	struct cldc_call_opts copts;
-	int rc;
-
-	memset(&copts, 0, sizeof(copts));
-	copts.cb = close_1_cb;
-	copts.private = rp;
-	rc = cldc_close(rp->fh, &copts);
-	if (rc) {
-		fprintf(stderr, "cldc_close call error %d\n", rc);
-		exit(1);
-	}
-}
-
-static int close_1_cb(struct cldc_call_opts *coptarg, enum cle_err_codes errc)
-{
-	struct run *rp = coptarg->private;
-	struct cldc_call_opts copts;
-	int rc;
-
-	if (errc != CLE_OK) {
-		fprintf(stderr, "first-close failed: %d\n", errc);
-		exit(1);
-	}
-	rp->fh = NULL;
-
-	memset(&copts, 0, sizeof(copts));
-	copts.cb = end_sess_cb;
-	copts.private = rp;
-	rc = cldc_end_sess(rp->udp->sess, &copts);
-	if (rc) {
-		fprintf(stderr, "cldc_end_sess call error %d\n", rc);
-		exit(1);
-	}
-	return 0;
-}
-
-static int end_sess_cb(struct cldc_call_opts *copts, enum cle_err_codes errc)
-{
-	if (errc != CLE_OK) {
-		fprintf(stderr, "end-sess failed: %d\n", errc);
-		exit(1);
-	}
-
-	/* session ended; success */
-	exit(0);
-	return 0;
-}
-
-static struct run run;
-
-static struct cldc_ops ops = {
-	.timer_ctl		= do_timer_ctl,
-	.pkt_send		= do_pkt_send,
-	.event			= do_event,
-};
-
-static int init(char *name)
+int main(int argc, char *argv[])
 {
-	int rc;
+	struct ncld_sess *nsp;
+	struct ncld_fh *fhp;
 	int port;
-	struct cldc_call_opts copts;
+	int error;
 
-	run.fname = name;
-	run.buf = TESTSTR;
-	run.len = TESTLEN;
+	g_thread_init(NULL);
+	ncld_init();
 
 	port = cld_readport(TEST_PORTFILE_CLD);
 	if (port < 0)
@@ -236,32 +49,30 @@ static int init(char *name)
 	if (port == 0)
 		return -1;
 
-	cld_timer_init(&run.tmr_udp, "udp-timer", timer_udp_event, &run);
-
-	rc = cldc_udp_new(TEST_HOST, port, &run.udp);
-	if (rc)
-		return rc;
-
-	memset(&copts, 0, sizeof(copts));
-	copts.cb = new_sess_cb;
-	copts.private = &run;
-	rc = cldc_new_sess(&ops, &copts, run.udp->addr, run.udp->addr_len,
-			   TEST_USER, TEST_USER_KEY, &run, &run.udp->sess);
-	if (rc)
-		return rc;
+	nsp = ncld_sess_open(TEST_HOST, port, &error, NULL, NULL,
+			     TEST_USER, TEST_USER_KEY);
+	if (!nsp) {
+		fprintf(stderr, "ncld_sess_open(host %s port %u) failed: %d\n",
+			TEST_HOST, port, error);
+		exit(1);
+	}
 
-	// run.udp->sess->verbose = true;
+	fhp = ncld_open(nsp, TFNAME, COM_WRITE | COM_CREATE,
+			&error, 0, NULL, NULL);
+	if (!fhp) {
+		fprintf(stderr, "ncld_open(%s) failed: %d\n", TFNAME, error);
+		exit(1);
+	}
 
-	return 0;
-}
+	error = ncld_write(fhp, TESTSTR, TESTLEN);
+	if (error) {
+		fprintf(stderr, "ncld_write failed: %d\n", error);
+		exit(1);
+	}
 
-int main(int argc, char *argv[])
-{
-	g_thread_init(NULL);
-	cldc_init();
-	if (init(TFNAME))
-		return 1;
-	test_loop(&run.tlist, run.udp);
+	/* These two are perfect places to hang or crash, so don't just exit. */
+	ncld_close(fhp);
+	ncld_sess_close(nsp);
 	return 0;
 }
 
diff --git a/test/test.h b/test/test.h
index a70609d..abd9284 100644
--- a/test/test.h
+++ b/test/test.h
@@ -1,9 +1,6 @@
 #ifndef _CLD_TEST_H_
 #define _CLD_TEST_H_
 
-#include <stdbool.h>
-#include <cldc.h>
-
 #define TESTSTR          "longertestdata\n"
 #define TESTLEN  (sizeof("longertestdata\n")-1)
 
@@ -20,6 +17,4 @@
 
 #define TEST_PORTFILE_CLD	"cld.port"
 
-extern void test_loop(struct cld_timer_list *tlist, struct cldc_udp *udp);
-
 #endif
diff --git a/test/util.c b/test/util.c
deleted file mode 100644
index 7e5ad06..0000000
--- a/test/util.c
+++ /dev/null
@@ -1,79 +0,0 @@
-
-/*
- * Copyright 2009 Red Hat, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.  If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-/*
- * General utilities for CLD tests.
- */
-
-#define _GNU_SOURCE
-#include "cld-config.h"
-
-#include <sys/types.h>
-#include <sys/select.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-#include <cldc.h>
-#include "test.h"
-
-void test_loop(struct cld_timer_list *tlist, struct cldc_udp *udp)
-{
-	int ufd = udp->fd;
-	fd_set rset;
-	struct timeval tm;
-	time_t tmo;
-	int rc;
-
-	for (;;) {
-		FD_ZERO(&rset);
-		FD_SET(ufd, &rset);
-
-		tmo = cld_timers_run(tlist);
-		if (tmo) {
-			tm.tv_sec = tmo;
-			tm.tv_usec = 0;
-			rc = select(ufd + 1, &rset, NULL, NULL, &tm);
-			if (rc < 0) {
-				fprintf(stderr, "select: error\n");
-				exit(1);
-			}
-			if (rc == 0)
-				continue;
-		} else {
-			rc = select(ufd + 1, &rset, NULL, NULL, NULL);
-			if (rc <= 0) {
-				fprintf(stderr, "select: nfd %d\n", rc);
-				exit(1);
-			}
-		}
-
-		if (FD_ISSET(ufd, &rset)) {
-			rc = cldc_udp_receive_pkt(udp);
-			if (rc) {
-				fprintf(stderr,
-					"cldc_udp_receive_pkt: error %d\n", rc);
-				exit(1);
-			}
-		} else {
-			fprintf(stderr, "noevent\n");
-			exit(1);
-		}
-	}
-}
-
diff --git a/tools/cldcli.c b/tools/cldcli.c
index 32289ac..85a7ef8 100644
--- a/tools/cldcli.c
+++ b/tools/cldcli.c
@@ -26,13 +26,10 @@
 #include <errno.h>
 #include <stdio.h>
 #include <argp.h>
-#include <poll.h>
 #include <locale.h>
 #include <stdarg.h>
 #include <ctype.h>
-#include <cldc.h>
-
-#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#include <ncld.h>
 
 const char *argp_program_version = PACKAGE_VERSION;
 
@@ -40,11 +37,6 @@ enum {
 	CLD_PATH_MAX		= 1024,
 };
 
-enum thread_codes {
-	TC_OK,
-	TC_FAILED
-};
-
 static struct argp_option options[] = {
 	{ "debug", 'D', "LEVEL", 0,
 	  "Set debug output to LEVEL (0 = off, 2 = max verbose)" },
@@ -60,89 +52,46 @@ static struct argp_option options[] = {
 static const char doc[] =
 "cldcli - command line interface to coarse locking service";
 
+#define TAG "cldcli"
+
 enum creq_cmd {
-	CREQ_CD,
-	CREQ_CAT,
-	CREQ_LS,
 	CREQ_RM,
 	CREQ_MKDIR,
-	CREQ_CP_FC,		/* cpin: FS-to-CLD copy */
-	CREQ_CP_CF,		/* cpout: CLD-to-FS copy */
-	CREQ_LOCK,
-	CREQ_TRYLOCK,
 	CREQ_UNLOCK,
-	CREQ_LIST_LOCKS,
-};
-
-struct cp_fc_info {
-	void		*mem;
-	size_t		mem_len;
 };
 
 struct creq {
-	enum creq_cmd		cmd;
+	enum creq_cmd		cmd_unused;
 	char			path[CLD_PATH_MAX + 1];
-	struct cp_fc_info	*cfi;
-};
-
-enum { CRESP_MSGSZ = 64 };
-
-struct cresp {
-	enum thread_codes	tcode;
-	char			msg[CRESP_MSGSZ];
-	union {
-		size_t		file_len;
-		unsigned int	n_records;
-		GList		*list;
-	} u;
-};
-
-struct ls_rec {
-	char			name[CLD_INODE_NAME_MAX + 1];
 };
 
 struct cldcli_lock_info {
-	enum creq_cmd		cmd;
-	struct cldc_fh		*fh;
+	bool			is_wait;
+	struct ncld_fh		*fh;
 	uint64_t		id;
 	char			path[CLD_PATH_MAX + 1];
 };
 
-static unsigned long thread_running = 1;
 static GList *host_list;
 static char clicwd[CLD_PATH_MAX + 1] = "/";
-static int to_thread[2], from_thread[2];
-static GThread *cldthr;
 static char our_user[CLD_MAX_USERNAME + 1] = "cli_user";
-static bool cldcli_verbose;
 
 /* globals only for use in thread */
-static struct cldc_udp *thr_udp;
-static struct cldc_fh *thr_fh;
+static struct ncld_sess *nsp;
 static GList *thr_lock_list;
 static uint64_t thr_lock_id = 2;
-static struct cld_timer_list thr_list;
-static struct cld_timer thr_timer;
-static int (*cldc_timer_cb)(struct cldc_session *, void *);
-static void *cldc_timer_private;
 
 static error_t parse_opt (int key, char *arg, struct argp_state *state);
 
 static const struct argp argp = { options, parse_opt, NULL, doc };
 
-static void errc_msg(struct cresp *cresp, enum cle_err_codes errc)
-{
-	strncpy(cresp->msg, cld_errstr(errc), CRESP_MSGSZ);
-	cresp->msg[CRESP_MSGSZ-1] = 0;
-}
-
 static void applog(int prio, const char *fmt, ...)
 {
 	char buf[200];
 	va_list ap;
 
 	va_start(ap, fmt);
-	snprintf(buf, 200, "%s\n", fmt);
+	snprintf(buf, 200, TAG ": %s\n", fmt);
 	vfprintf(stderr, buf, ap);
 	va_end(ap);
 }
@@ -152,616 +101,7 @@ static struct hail_log cli_log = {
 	.verbose = 0,
 };
 
-static void do_write(int fd, const void *buf, size_t buflen, const char *msg)
-{
-	ssize_t rc;
-
-	rc = write(fd, buf, buflen);
-	if (rc < 0)
-		perror(msg);
-	else if (rc != buflen)
-		fprintf(stderr, "%s: short write\n", msg);
-}
-
-static void do_read(int fd, void *buf, size_t buflen, const char *msg)
-{
-	ssize_t rc;
-
-	rc = read(fd, buf, buflen);
-	if (rc < 0)
-		perror(msg);
-	else if (rc != buflen)
-		fprintf(stderr, "%s: short read\n", msg);
-}
-
-/* send message thread -> main */
-static void write_from_thread(const void *buf, size_t buflen)
-{
-	do_write(from_thread[1], buf, buflen, "write-from-thread");
-}
-
-/* send message main -> thread */
-static void write_to_thread(const void *buf, size_t buflen)
-{
-	do_write(to_thread[1], buf, buflen, "write-to-thread");
-}
-
-/* receive message thread -> main */
-static void read_from_thread(void *buf, size_t buflen)
-{
-	do_read(from_thread[0], buf, buflen, "read-from-thread");
-}
-
-/* receive message main -> thread */
-static void read_to_thread(void *buf, size_t buflen)
-{
-	do_read(to_thread[0], buf, buflen, "read-to-thread");
-}
-
-static int cb_ok_done(struct cldc_call_opts *copts_in, enum cle_err_codes errc)
-{
-	struct cresp cresp = { .tcode = TC_FAILED, };
-
-	if (errc == CLE_OK)
-		cresp.tcode = TC_OK;
-	errc_msg(&cresp, errc);
-
-	write_from_thread(&cresp, sizeof(cresp));
-
-	return 0;
-}
-
-static int cb_ls_2(struct cldc_call_opts *copts_in, enum cle_err_codes errc)
-{
-	struct cresp cresp = { .tcode = TC_FAILED, };
-	struct cldc_call_opts copts = { NULL, };
-	struct cld_dirent_cur dc;
-	int rc, i;
-	char *data;
-	size_t data_len;
-	bool first = true;
-
-	if (errc != CLE_OK) {
-		errc_msg(&cresp, errc);
-		write_from_thread(&cresp, sizeof(cresp));
-		return 0;
-	}
-	cldc_call_opts_get_data(copts_in, &data, &data_len);
-
-	rc = cldc_dirent_count(data, data_len);
-	if (rc < 0) {
-		write_from_thread(&cresp, sizeof(cresp));
-		return 0;
-	}
-
-	cresp.tcode = TC_OK;
-	cresp.u.n_records = rc;
-
-	write_from_thread(&cresp, sizeof(cresp));
-
-	cldc_dirent_cur_init(&dc, data, data_len);
-
-	for (i = 0; i < rc; i++) {
-		struct ls_rec lsr;
-		char *s;
-
-		if (first) {
-			first = false;
-
-			if (cldc_dirent_first(&dc) < 0)
-				break;
-		} else {
-			if (cldc_dirent_next(&dc) < 0)
-				break;
-		}
-
-		s = cldc_dirent_name(&dc);
-		strncpy(lsr.name, s, sizeof(lsr.name));
-		lsr.name[sizeof(lsr.name) - 1] = 0;
-		free(s);
-
-		write_from_thread(&lsr, sizeof(lsr));
-
-	}
-
-	cldc_dirent_cur_fini(&dc);
-
-	/* FIXME: race; should wait until close succeeds/fails before
-	 * returning any data.  'fh' may still be in use, otherwise.
-	 */
-	cldc_close(thr_fh, &copts);
-
-	return 0;
-}
-
-static int cb_ls_1(struct cldc_call_opts *copts_in, enum cle_err_codes errc)
-{
-	struct cresp cresp = { .tcode = TC_FAILED, };
-	struct cldc_call_opts copts = { .cb = cb_ls_2, };
-
-	if (errc != CLE_OK) {
-		errc_msg(&cresp, errc);
-		write_from_thread(&cresp, sizeof(cresp));
-		return 0;
-	}
-
-	if (cldc_get(thr_fh, &copts, false)) {
-		write_from_thread(&cresp, sizeof(cresp));
-		return 0;
-	}
-
-	return 0;
-}
-
-static int cb_cat_2(struct cldc_call_opts *copts_in, enum cle_err_codes errc)
-{
-	struct cresp cresp = { .tcode = TC_FAILED, };
-	struct cldc_call_opts copts = { NULL, };
-	char *data;
-	size_t data_len;
-
-	if (errc != CLE_OK) {
-		errc_msg(&cresp, errc);
-		write_from_thread(&cresp, sizeof(cresp));
-		return 0;
-	}
-
-	cldc_call_opts_get_data(copts_in, &data, &data_len);
-
-	cresp.tcode = TC_OK;
-	cresp.u.file_len = data_len;
-
-	write_from_thread(&cresp, sizeof(cresp));
-	write_from_thread(data, data_len);
-
-	/* FIXME: race; should wait until close succeeds/fails before
-	 * returning any data.  'fh' may still be in use, otherwise.
-	 */
-	cldc_close(thr_fh, &copts);
-
-	return 0;
-}
-
-static int cb_cat_1(struct cldc_call_opts *copts_in, enum cle_err_codes errc)
-{
-	struct cresp cresp = { .tcode = TC_FAILED, };
-	struct cldc_call_opts copts = { .cb = cb_cat_2, };
-
-	if (errc != CLE_OK) {
-		errc_msg(&cresp, errc);
-		write_from_thread(&cresp, sizeof(cresp));
-		return 0;
-	}
-
-	if (cldc_get(thr_fh, &copts, false)) {
-		write_from_thread(&cresp, sizeof(cresp));
-		return 0;
-	}
-
-	return 0;
-}
-
-static int cb_cp_cf_2(struct cldc_call_opts *copts_in, enum cle_err_codes errc)
-{
-	struct cresp cresp = { .tcode = TC_FAILED, };
-	struct cldc_call_opts copts = { NULL, };
-	char *data;
-	size_t data_len;
-
-	if (errc != CLE_OK) {
-		errc_msg(&cresp, errc);
-		write_from_thread(&cresp, sizeof(cresp));
-		return 0;
-	}
-
-	cldc_call_opts_get_data(copts_in, &data, &data_len);
-	cresp.tcode = TC_OK;
-	cresp.u.file_len = data_len;
-
-	write_from_thread(&cresp, sizeof(cresp));
-	write_from_thread(data, data_len);
-
-	/* FIXME: race; should wait until close succeeds/fails before
-	 * returning any data.  'fh' may still be in use, otherwise.
-	 */
-	cldc_close(thr_fh, &copts);
-
-	return 0;
-}
-
-static int cb_cp_cf_1(struct cldc_call_opts *copts_in, enum cle_err_codes errc)
-{
-	struct cresp cresp = { .tcode = TC_FAILED, };
-	struct cldc_call_opts copts = { .cb = cb_cp_cf_2, };
-
-	if (errc != CLE_OK) {
-		errc_msg(&cresp, errc);
-		write_from_thread(&cresp, sizeof(cresp));
-		return 0;
-	}
-
-	if (cldc_get(thr_fh, &copts, false)) {
-		write_from_thread(&cresp, sizeof(cresp));
-		return 0;
-	}
-
-	return 0;
-}
-
-static int cb_cp_fc_1(struct cldc_call_opts *copts_in, enum cle_err_codes errc)
-{
-	struct cresp cresp = { .tcode = TC_FAILED, };
-	struct cldc_call_opts copts = { .cb = cb_ok_done, };
-	struct cp_fc_info *cfi = copts_in->private;
-
-	if (errc != CLE_OK) {
-		errc_msg(&cresp, errc);
-		write_from_thread(&cresp, sizeof(cresp));
-		return 0;
-	}
-
-	if (cldc_put(thr_fh, &copts, cfi->mem, cfi->mem_len)) {
-		write_from_thread(&cresp, sizeof(cresp));
-		return 0;
-	}
-
-	return 0;
-}
-
-static int cb_cd_1(struct cldc_call_opts *copts_in, enum cle_err_codes errc)
-{
-	struct cresp cresp = { .tcode = TC_FAILED, };
-	struct cldc_call_opts copts = { .cb = cb_ok_done, };
-
-	if (errc != CLE_OK) {
-		errc_msg(&cresp, errc);
-		write_from_thread(&cresp, sizeof(cresp));
-		return 0;
-	}
-
-	if (cldc_close(thr_fh, &copts)) {
-		write_from_thread(&cresp, sizeof(cresp));
-		return 0;
-	}
-
-	return 0;
-}
-
-static int cb_mkdir_1(struct cldc_call_opts *copts_in, enum cle_err_codes errc)
-{
-	struct cresp cresp = { .tcode = TC_FAILED, };
-	struct cldc_call_opts copts = { NULL, };
-
-	if (errc == CLE_OK)
-		cresp.tcode = TC_OK;
-	errc_msg(&cresp, errc);
-
-	write_from_thread(&cresp, sizeof(cresp));
-
-	/* FIXME: race; should wait until close succeeds/fails before
-	 * returning any data.  'fh' may still be in use, otherwise.
-	 */
-	cldc_close(thr_fh, &copts);
-
-	return 0;
-}
-
-static int cb_lock_2(struct cldc_call_opts *copts_in, enum cle_err_codes errc)
-{
-	struct cldcli_lock_info *li = copts_in->private;
-
-	if ((errc == CLE_OK) ||
-	    ((li->cmd == CREQ_LOCK) && (errc == CLE_LOCK_PENDING)))
-		thr_lock_list = g_list_append(thr_lock_list, li);
-	else
-		free(li);
-
-	return cb_ok_done(copts_in, errc);
-}
-
-static int cb_lock_1(struct cldc_call_opts *copts_in, enum cle_err_codes errc)
-{
-	struct cresp cresp = { .tcode = TC_FAILED, };
-	struct cldc_call_opts copts = { .cb = cb_lock_2, };
-	struct cldcli_lock_info *li = copts_in->private;
-	bool wait_for_lock = (li->cmd == CREQ_LOCK);
-
-	if (errc != CLE_OK) {
-		errc_msg(&cresp, errc);
-		write_from_thread(&cresp, sizeof(cresp));
-		return 0;
-	}
-
-	copts.private = li;
-
-	if (cldc_lock(li->fh, &copts, 0, wait_for_lock)) {
-		write_from_thread(&cresp, sizeof(cresp));
-		free(li);
-		return 0;
-	}
-
-	return 0;
-}
-
-static int cb_unlock_1(struct cldc_call_opts *copts_in, enum cle_err_codes errc)
-{
-	struct cresp cresp = { .tcode = TC_FAILED, };
-	struct cldc_call_opts copts = { NULL, };
-	struct cldcli_lock_info *li = copts_in->private;
-
-	if (errc != CLE_OK) {
-		errc_msg(&cresp, errc);
-		write_from_thread(&cresp, sizeof(cresp));
-		goto out;
-	}
-
-	cresp.tcode = TC_OK;
-
-	write_from_thread(&cresp, sizeof(cresp));
-
-out:
-	cldc_close(li->fh, &copts);
-
-	free(li);
-	return 0;
-}
-
-static void handle_user_command(void)
-{
-	struct creq creq;
-	struct cresp cresp = { .tcode = TC_FAILED, };
-	struct cldc_call_opts copts = { NULL, };
-	int rc;
-
-	read_to_thread(&creq, sizeof(creq));
-
-	if (cli_log.verbose)
-		switch (creq.cmd) {
-		case CREQ_CD:
-		case CREQ_CAT:
-		case CREQ_LS:
-		case CREQ_RM:
-		case CREQ_MKDIR:
-		case CREQ_CP_FC:
-		case CREQ_CP_CF:
-		case CREQ_LOCK:
-		case CREQ_TRYLOCK:
-		case CREQ_UNLOCK:
-			fprintf(stderr, "DEBUG: thr rx'd path '%s'\n",
-				creq.path);
-			break;
-		case CREQ_LIST_LOCKS:
-			fprintf(stderr, "DEBUG: thr rx'd no path\n");
-			break;
-		}
-
-	switch (creq.cmd) {
-	case CREQ_CD:
-		copts.cb = cb_cd_1;
-		rc = cldc_open(thr_udp->sess, &copts, creq.path,
-			       COM_DIRECTORY, 0, &thr_fh);
-		if (rc) {
-			snprintf(cresp.msg, sizeof(cresp.msg),
-				 "cldc_open rc %d", rc);
-			write_from_thread(&cresp, sizeof(cresp));
-			return;
-		}
-		break;
-	case CREQ_CAT:
-		copts.cb = cb_cat_1;
-		rc = cldc_open(thr_udp->sess, &copts, creq.path,
-			       COM_READ, 0, &thr_fh);
-		if (rc) {
-			snprintf(cresp.msg, sizeof(cresp.msg),
-				 "cldc_open rc %d", rc);
-			write_from_thread(&cresp, sizeof(cresp));
-			return;
-		}
-		break;
-	case CREQ_CP_CF:
-		copts.cb = cb_cp_cf_1;
-		rc = cldc_open(thr_udp->sess, &copts, creq.path,
-			       COM_READ, 0, &thr_fh);
-		if (rc) {
-			snprintf(cresp.msg, sizeof(cresp.msg),
-				 "cldc_open rc %d", rc);
-			write_from_thread(&cresp, sizeof(cresp));
-			return;
-		}
-		break;
-	case CREQ_CP_FC:
-		copts.cb = cb_cp_fc_1;
-		copts.private = creq.cfi;
-		rc = cldc_open(thr_udp->sess, &copts, creq.path,
-			       COM_CREATE | COM_WRITE, 0, &thr_fh);
-		if (rc) {
-			snprintf(cresp.msg, sizeof(cresp.msg),
-				 "cldc_open rc %d", rc);
-			write_from_thread(&cresp, sizeof(cresp));
-			return;
-		}
-		break;
-	case CREQ_LS:
-		copts.cb = cb_ls_1;
-		rc = cldc_open(thr_udp->sess, &copts, creq.path,
-			       COM_DIRECTORY | COM_READ, 0, &thr_fh);
-		if (rc) {
-			snprintf(cresp.msg, sizeof(cresp.msg),
-				 "cldc_open rc %d", rc);
-			write_from_thread(&cresp, sizeof(cresp));
-			return;
-		}
-		break;
-	case CREQ_RM:
-		copts.cb = cb_ok_done;
-		rc = cldc_del(thr_udp->sess, &copts, creq.path);
-		if (rc) {
-			snprintf(cresp.msg, sizeof(cresp.msg),
-				 "cldc_del rc %d", rc);
-			write_from_thread(&cresp, sizeof(cresp));
-			return;
-		}
-		break;
-	case CREQ_MKDIR:
-		copts.cb = cb_mkdir_1;
-		rc = cldc_open(thr_udp->sess, &copts, creq.path,
-			       COM_DIRECTORY | COM_CREATE | COM_EXCL, 0,
-			       &thr_fh);
-		if (rc) {
-			snprintf(cresp.msg, sizeof(cresp.msg),
-				 "cldc_open rc %d", rc);
-			write_from_thread(&cresp, sizeof(cresp));
-			return;
-		}
-		break;
-	case CREQ_TRYLOCK:
-	case CREQ_LOCK: {
-		struct cldcli_lock_info *li;
-
-		li = calloc(1, sizeof(*li));
-		if (!li) {
-			strcpy(cresp.msg, "OOM");
-			write_from_thread(&cresp, sizeof(cresp));
-			return;
-		}
-
-		li->cmd = creq.cmd;
-		li->id = thr_lock_id++;
-		strncpy(li->path, creq.path, sizeof(li->path));
-
-		copts.cb = cb_lock_1;
-		copts.private = li;
-		rc = cldc_open(thr_udp->sess, &copts, creq.path,
-			       COM_LOCK, 0, &li->fh);
-		if (rc) {
-			snprintf(cresp.msg, sizeof(cresp.msg),
-				 "cldc_open rc %d", rc);
-			write_from_thread(&cresp, sizeof(cresp));
-			free(li);
-			return;
-		}
-
-		break;
-		}
-
-	case CREQ_UNLOCK: {
-		GList *tmp;
-		struct cldcli_lock_info *li = NULL;
-
-		tmp = thr_lock_list;
-		while (tmp) {
-			li = tmp->data;
-
-			if (!strncmp(li->path, creq.path, sizeof(li->path)))
-				break;
-
-			tmp = tmp->next;
-		}
-		if (!tmp) {
-			write_from_thread(&cresp, sizeof(cresp));
-			return;
-		}
-
-		thr_lock_list = g_list_delete_link(thr_lock_list, tmp);
-
-		copts.cb = cb_unlock_1;
-		copts.private = li;
-		rc = cldc_unlock(li->fh, &copts);
-		if (rc) {
-			snprintf(cresp.msg, sizeof(cresp.msg),
-				 "cldc_unlock rc %d", rc);
-			write_from_thread(&cresp, sizeof(cresp));
-			free(li);
-			return;
-		}
-
-		break;
-		}
-
-	case CREQ_LIST_LOCKS: {
-		GList *tmp, *content = NULL;
-
-		tmp = thr_lock_list;
-		while (tmp) {
-			char *s;
-			struct cldcli_lock_info *li;
-
-			li = tmp->data;
-			tmp = tmp->next;
-
-			s = g_strdup_printf("%llu %s\n",
-				 (unsigned long long) li->id,
-				 li->path);
-
-			content = g_list_append(content, s);
-		}
-
-		cresp.tcode = TC_OK;
-		cresp.u.list = content;
-		write_from_thread(&cresp, sizeof(cresp));
-		break;
-		}
-	}
-}
-
-static int cb_new_sess(struct cldc_call_opts *copts, enum cle_err_codes errc)
-{
-	char tcode = TC_FAILED;
-
-	if (errc != CLE_OK) {
-		write_from_thread(&tcode, 1);
-		return 0;
-	}
-
-	/* signal we are up and ready for commands */
-	tcode = TC_OK;
-	write_from_thread(&tcode, 1);
-
-	return 0;
-}
-
-static void cld_p_timer_cb(struct cld_timer *timer)
-{
-	int (*timer_cb)(struct cldc_session *, void *) = cldc_timer_cb;
-	void *private = cldc_timer_private;
-
-	if (!timer_cb)
-		return;
-
-	cldc_timer_cb = NULL;
-	cldc_timer_private = NULL;
-
-	timer_cb(thr_udp->sess, private);
-}
-
-static bool cld_p_timer_ctl(void *private, bool add,
-			    int (*cb)(struct cldc_session *, void *),
-			    void *cb_private, time_t secs)
-{
-	if (add) {
-		cldc_timer_cb = cb;
-		cldc_timer_private = cb_private;
-
-		thr_timer.fired = false;
-		thr_timer.cb = cld_p_timer_cb;
-		thr_timer.userdata = NULL;
-
-		cld_timer_add(&thr_list, &thr_timer, time(NULL) + secs);
-	} else {
-		cld_timer_del(&thr_list, &thr_timer);
-	}
-	return true;
-}
-
-static int cld_p_pkt_send(void *priv, const void *addr, size_t addrlen,
-			       const void *buf, size_t buflen)
-{
-	struct cldc_udp *udp = priv;
-	return cldc_udp_pkt_send(udp, addr, addrlen, buf, buflen);
-}
-
-static void cld_p_event(void *private, struct cldc_session *sess,
-			struct cldc_fh *fh, uint32_t what)
+static void sess_event(void *private, uint32_t what)
 {
 	fprintf(stderr, "FIXME: handle event(s) %s%s%s%s%s\n",
 		(what & CE_UPDATED) ? "updated " : "",
@@ -771,83 +111,6 @@ static void cld_p_event(void *private, struct cldc_session *sess,
 		(what & CE_SESS_FAILED) ? "sess-fail " : "");
 }
 
-static struct cldc_ops cld_ops = {
-	.timer_ctl	= cld_p_timer_ctl,
-	.pkt_send	= cld_p_pkt_send,
-	.event		= cld_p_event,
-	.errlog		= applog,
-};
-
-static gpointer cld_thread(gpointer dummy)
-{
-	struct cldc_host *dr;
-	struct cldc_call_opts copts = { .cb = cb_new_sess };
-	char tcode = TC_FAILED;
-	struct pollfd pfd[2];
-	time_t next_timeout;
-
-	if (!host_list) {
-		fprintf(stderr, "cldthr: no host list\n");
-		write_from_thread(&tcode, 1);
-		return NULL;
-	}
-
-	dr = host_list->data;
-
-	if (cldc_udp_new(dr->host, dr->port, &thr_udp)) {
-		fprintf(stderr, "cldthr: UDP create failed\n");
-		write_from_thread(&tcode, 1);
-		return NULL;
-	}
-
-	if (cldc_new_sess(&cld_ops, &copts, thr_udp->addr, thr_udp->addr_len,
-			  "cldcli", "cldcli", thr_udp, &thr_udp->sess)) {
-		fprintf(stderr, "cldthr: new_sess failed\n");
-		write_from_thread(&tcode, 1);
-		return NULL;
-	}
-
-	thr_udp->sess->log.verbose = cldcli_verbose;
-
-	pfd[0].fd = thr_udp->fd;
-	pfd[0].events = POLLIN;
-
-	pfd[1].fd = to_thread[0];
-	pfd[1].events = POLLIN;
-
-	next_timeout = cld_timers_run(&thr_list);
-
-	while (thread_running) {
-		int i, rc;
-
-		/* zero revents.  necessary??? */
-		for (i = 0; i < ARRAY_SIZE(pfd); i++)
-			pfd[i].revents = 0;
-
-		/* poll for activity */
-		rc = poll(pfd, 2,
-			  next_timeout ? (next_timeout * 1000) : -1);
-		if (rc < 0) {
-			perror("poll");
-			return NULL;
-		}
-
-		/* dispatch if activity found */
-		for (i = 0; i < ARRAY_SIZE(pfd); i++) {
-			if (pfd[i].revents) {
-				if (i == 0)
-					cldc_udp_receive_pkt(thr_udp);
-				else
-					handle_user_command();
-			}
-		}
-
-		next_timeout = cld_timers_run(&thr_list);
-	}
-
-	return NULL;
-}
-
 static bool make_abs_path(char *dest, size_t dest_len, const char *src)
 {
 	int len;
@@ -870,76 +133,128 @@ static bool make_abs_path(char *dest, size_t dest_len, const char *src)
 
 static void cmd_cd(const char *arg)
 {
-	struct creq creq = { CREQ_CD, };
-	struct cresp cresp;
+	struct creq creq = { 0, };
+	struct ncld_fh *fhp;
+	int error;
 
 	if (!*arg)
 		arg = "/";
 
 	if (!make_abs_path(creq.path, sizeof(creq.path), arg)) {
-		fprintf(stderr, "%s: path too long\n", arg);
+		fprintf(stderr, TAG ": %s: path too long\n", arg);
 		return;
 	}
 
-	/* send message to thread */
-	write_to_thread(&creq, sizeof(creq));
-
-	/* wait for and receive response from thread */
-	read_from_thread(&cresp, sizeof(cresp));
-
-	if (cresp.tcode != TC_OK) {
-		fprintf(stderr, "%s: change dir failed: %s\n", arg, cresp.msg);
+	fhp = ncld_open(nsp, creq.path, COM_DIRECTORY, &error, 0, NULL, NULL);
+	if (!fhp) {
+		if (error < 1000) {
+			fprintf(stderr, TAG ": cannot open path `%s': %s\n",
+				creq.path, strerror(error));
+		} else {
+			fprintf(stderr, TAG ": cannot open path `%s': %d\n",
+				creq.path, error);
+		}
 		return;
 	}
+	ncld_close(fhp);
 
 	strcpy(clicwd, creq.path);
 }
 
-static void show_lsr(const struct ls_rec *lsr)
-{
-	fprintf(stdout, "%s\n", lsr->name);
-}
-
 static void cmd_ls(const char *arg)
 {
-	struct creq creq = { CREQ_LS, };
-	struct cresp cresp;
+	struct creq creq = { 0, };
+	struct ncld_fh *fhp;
+	struct ncld_read *rp;
+	const char *data;
+	size_t data_len;
+	unsigned int n_records;
+	struct cld_dirent_cur dc;
+	bool first;
+	int error;
 	int i;
+	int rc;
 
 	if (!*arg)
 		arg = clicwd;
 
 	if (!make_abs_path(creq.path, sizeof(creq.path), arg)) {
-		fprintf(stderr, "%s: path too long\n", arg);
+		fprintf(stderr, TAG ": %s: path too long\n", arg);
+		return;
+	}
+
+	fhp = ncld_open(nsp, creq.path, COM_DIRECTORY | COM_READ, &error,
+			0, NULL, NULL);
+	if (!fhp) {
+		if (error < 1000) {
+			fprintf(stderr, TAG ": cannot open path `%s': %s\n",
+				creq.path, strerror(error));
+		} else {
+			fprintf(stderr, TAG ": cannot open path `%s': %d\n",
+				creq.path, error);
+		}
 		return;
 	}
 
-	/* send message to thread */
-	write_to_thread(&creq, sizeof(creq));
+	rp = ncld_get(fhp, &error);
+	if (!rp) {
+		if (error < 1000) {
+			fprintf(stderr, TAG ": cannot get on path `%s': %s\n",
+				creq.path, strerror(error));
+		} else {
+			fprintf(stderr, TAG ": cannot get on path `%s': %d\n",
+				creq.path, error);
+		}
+		ncld_close(fhp);
+		return;
+	}
 
-	/* wait for and receive response from thread */
-	read_from_thread(&cresp, sizeof(cresp));
+	data = rp->ptr;
+	data_len = rp->length;
 
-	if (cresp.tcode != TC_OK) {
-		fprintf(stderr, "ls(%s) failed: %s\n", creq.path, cresp.msg);
+	rc = cldc_dirent_count(data, data_len);
+	if (rc < 0) {
+		fprintf(stderr, TAG ": cldc_dirent_count failed on path `%s'\n",
+				creq.path);
+		ncld_read_free(rp);
+		ncld_close(fhp);
 		return;
 	}
+	n_records = rc;
 
-	for (i = 0; i < cresp.u.n_records; i++) {
-		struct ls_rec lsr;
+	cldc_dirent_cur_init(&dc, data, data_len);
+
+	first = true;
+	for (i = 0; i < n_records; i++) {
+		char *s;
 
-		read_from_thread(&lsr, sizeof(lsr));
+		if (first) {
+			first = false;
+
+			if (cldc_dirent_first(&dc) < 0)
+				break;
+		} else {
+			if (cldc_dirent_next(&dc) < 0)
+				break;
+		}
 
-		show_lsr(&lsr);
+		s = cldc_dirent_name(&dc);
+		printf("%s\n", s);
+		free(s);
 	}
+
+	cldc_dirent_cur_fini(&dc);
+
+	ncld_read_free(rp);
+	ncld_close(fhp);
 }
 
 static void cmd_cat(const char *arg)
 {
-	struct creq creq = { CREQ_CAT, };
-	struct cresp cresp;
-	size_t len;
-	void *mem;
+	struct creq creq = { 0, };
+	struct ncld_fh *fhp;
+	struct ncld_read *rp;
+	int error;
 
 	if (!*arg) {
 		fprintf(stderr, "cat: argument required\n");
@@ -947,77 +262,63 @@ static void cmd_cat(const char *arg)
 	}
 
 	if (!make_abs_path(creq.path, sizeof(creq.path), arg)) {
-		fprintf(stderr, "%s: path too long\n", arg);
+		fprintf(stderr, TAG ": %s: path too long\n", arg);
 		return;
 	}
 
-	/* send message to thread */
-	write_to_thread(&creq, sizeof(creq));
-
-	/* wait for and receive response from thread */
-	read_from_thread(&cresp, sizeof(cresp));
-
-	if (cresp.tcode != TC_OK) {
-		fprintf(stderr, "%s: cat failed: %s\n", arg, cresp.msg);
+	fhp = ncld_open(nsp, creq.path, COM_READ, &error, 0, NULL, NULL);
+	if (!fhp) {
+		if (error < 1000) {
+			fprintf(stderr, TAG ": cannot open path `%s': %s\n",
+				creq.path, strerror(error));
+		} else {
+			fprintf(stderr, TAG ": cannot open path `%s': %d\n",
+				creq.path, error);
+		}
 		return;
 	}
 
-	len = cresp.u.file_len;
-	mem = malloc(len);
-	if (!mem) {
-		fprintf(stderr, "%s: OOM (%u)\n", __func__, (unsigned int) len);
+	rp = ncld_get(fhp, &error);
+	if (!rp) {
+		fprintf(stderr, TAG ": cannot read from path `%s': %d\n",
+			creq.path, error);
+		ncld_close(fhp);
 		return;
 	}
 
-	/* read file data from thread */
-	read_from_thread(mem, len);
-
-	/* write file data to stdout */
-	(void) fwrite(mem, len, 1, stdout);
+	(void) fwrite(rp->ptr, rp->length, 1, stdout);
 	fprintf(stdout, "\n");
 
-	free(mem);
+	ncld_read_free(rp);
+	ncld_close(fhp);
 }
 
 static void cmd_list_locks(void)
 {
-	struct creq creq = { CREQ_LIST_LOCKS, };
-	struct cresp cresp;
-	GList *tmp, *content;
+	GList *tmp;
 
-	/* send message to thread */
-	write_to_thread(&creq, sizeof(creq));
-
-	/* wait for and receive response from thread */
-	read_from_thread(&cresp, sizeof(cresp));
-
-	if (cresp.tcode != TC_OK) {
-		fprintf(stderr, "list-locks failed: %s\n", cresp.msg);
-		return;
-	}
-
-	content = tmp = cresp.u.list;
+	tmp = thr_lock_list;
 	while (tmp) {
-		char *s;
+		struct cldcli_lock_info *li;
 
-		s = tmp->data;
+		li = tmp->data;
 		tmp = tmp->next;
 
-		printf("%s", s);
-
-		free(s);
+		printf("%llu %s\n", (unsigned long long) li->id, li->path);
 	}
-
-	g_list_free(content);
 }
 
-static void cmd_cp_io(const char *cmd, const char *arg, bool read_cld_file)
+static void cmd_cpin(const char *cmd, const char *arg)
 {
 	struct creq creq;
-	struct cresp cresp;
+	struct ncld_fh *fhp;
 	gchar **sv = NULL, *cld_path, *fs_path;
-	void *mem = NULL;
-	size_t flen = 0;
+	gchar *fs_content = NULL;
+	gsize fs_len = 0;
+	int error;
+	int rc;
+
+	memset(&creq, 0, sizeof(creq));
 
 	if (!*arg) {
 		fprintf(stderr, "%s: argument required\n", cmd);
@@ -1030,86 +331,157 @@ static void cmd_cp_io(const char *cmd, const char *arg, bool read_cld_file)
 		goto out;
 	}
 
-	memset(&creq, 0, sizeof(creq));
-
-	if (read_cld_file) {
-		creq.cmd = CREQ_CP_CF;
-		cld_path = sv[0];
-		fs_path = sv[1];
-	} else {
-		gchar *fs_content = NULL;
-		gsize fs_len = 0;
-
-		creq.cmd = CREQ_CP_FC;
-		cld_path = sv[1];
-		fs_path = sv[0];
-
-		if (!g_file_get_contents(fs_path, &fs_content,
-					 &fs_len, NULL)) {
-			fprintf(stderr, "Failed to read data from FS path %s\n",
-				fs_path);
-			goto out;
-		}
+	cld_path = sv[1];
+	fs_path = sv[0];
 
-		mem = fs_content;
-		flen = fs_len;
+	if (!g_file_get_contents(fs_path, &fs_content, &fs_len, NULL)) {
+		fprintf(stderr, TAG ": Failed to read data from FS path %s\n",
+			fs_path);
+		goto out;
 	}
 
 	if (!make_abs_path(creq.path, sizeof(creq.path), cld_path)) {
-		fprintf(stderr, "%s: path too long\n", arg);
+		fprintf(stderr, TAG ": %s: path too long\n", arg);
+		goto out;
+	}
+
+	fhp = ncld_open(nsp, creq.path, COM_CREATE | COM_WRITE,
+			&error, 0, NULL, NULL);
+	if (!fhp) {
+		fprintf(stderr, TAG ": %s: cannot open: %d\n", creq.path, error);
 		goto out;
 	}
 
-	creq.cfi = calloc(1, sizeof(*creq.cfi));
-	if (!creq.cfi) {
-		fprintf(stderr, "OOM\n");
+	rc = ncld_write(fhp, fs_content, fs_len);
+	if (rc) {
+		fprintf(stderr, TAG ": %s(%s -> %s) failed: %d\n",
+			cmd, sv[0], sv[1], rc);
+		ncld_close(fhp);
 		goto out;
 	}
 
-	creq.cfi->mem = mem;
-	creq.cfi->mem_len = flen;
+	ncld_close(fhp);
 
-	/* send message to thread */
-	write_to_thread(&creq, sizeof(creq));
+out:
+	g_strfreev(sv);
+	free(fs_content);
+}
 
-	/* wait for and receive response from thread */
-	read_from_thread(&cresp, sizeof(cresp));
+static void cmd_cpout(const char *cmd, const char *arg)
+{
+	struct creq creq;
+	struct ncld_fh *fhp;
+	struct ncld_read *rp;
+	gchar **sv = NULL, *cld_path, *fs_path;
+	int error;
+
+	memset(&creq, 0, sizeof(creq));
+
+	if (!*arg) {
+		fprintf(stderr, "%s: argument required\n", cmd);
+		return;
+	}
 
-	if (cresp.tcode != TC_OK) {
-		fprintf(stderr, "%s(%s -> %s) failed: %s\n",
-			cmd, sv[0], sv[1], cresp.msg);
+	sv = g_strsplit_set(arg, " \t\f\r\n", 2);
+	if (!sv || !sv[0] || !sv[1]) {
+		fprintf(stderr, "%s: two arguments required\n", cmd);
 		goto out;
 	}
 
-	if (read_cld_file) {
-		flen = cresp.u.file_len;
-		mem = malloc(flen);
-		if (!mem) {
-			fprintf(stderr, "%s: OOM (%u)\n",
-				__func__, (unsigned int) flen);
-			exit(1);
-		}
+	cld_path = sv[0];
+	fs_path = sv[1];
 
-		read_from_thread(mem, flen);
+	if (!make_abs_path(creq.path, sizeof(creq.path), cld_path)) {
+		fprintf(stderr, TAG ": %s: path too long\n", arg);
+		goto out;
+	}
 
-		if (!g_file_set_contents(fs_path, mem, flen, NULL)) {
-			fprintf(stderr, "Successfully read CLD data from %s,\n"
-				"but failed to write data to FS path %s\n",
-				cld_path,
-				fs_path);
-		}
+	fhp = ncld_open(nsp, creq.path, COM_READ, &error, 0, NULL, NULL);
+	if (!fhp) {
+		fprintf(stderr, TAG ": %s: cannot open: %d\n", creq.path, error);
+		goto out;
+	}
+	rp = ncld_get(fhp, &error);
+	if (!rp) {
+		fprintf(stderr, TAG ": cannot read from path `%s': %d\n",
+			creq.path, error);
+		ncld_close(fhp);
+		goto out;
+	}
+
+	if (!g_file_set_contents(fs_path, rp->ptr, rp->length, NULL)) {
+		fprintf(stderr, "Successfully read CLD data from %s,\n"
+			"but failed to write data to FS path %s\n",
+			cld_path, fs_path);
 	}
 
+	ncld_read_free(rp);
+	ncld_close(fhp);
+
 out:
-	free(creq.cfi);
 	g_strfreev(sv);
-	free(mem);
+}
+
+static void cmd_lock(const char *cmd, const char *arg, bool wait_for_lock)
+{
+	struct creq creq = { 0, };
+	struct ncld_fh *fhp;
+	struct cldcli_lock_info *li;
+	int error;
+	int rc;
+
+	if (!*arg) {
+		fprintf(stderr, "%s: argument required\n", cmd);
+		return;
+	}
+
+	if (!make_abs_path(creq.path, sizeof(creq.path), arg)) {
+		fprintf(stderr, TAG ": %s: path too long\n", arg);
+		return;
+	}
+
+	li = calloc(1, sizeof(*li));
+	if (!li) {
+		fprintf(stderr, TAG ": OOM\n");
+		return;
+	}
+
+	li->is_wait = wait_for_lock;
+	li->id = thr_lock_id++;
+	strncpy(li->path, creq.path, CLD_PATH_MAX);
+
+	fhp = ncld_open(nsp, creq.path, COM_LOCK, &error, 0, NULL, NULL);
+	if (!fhp) {
+		fprintf(stderr, TAG ": %s: cannot open: %d\n", creq.path, error);
+		free(li);
+		return;
+	}
+	li->fh = fhp;
+
+	if (wait_for_lock)
+		rc = ncld_qlock(fhp);
+	else
+		rc = ncld_trylock(fhp);
+
+	if (rc < 0) {
+		fprintf(stderr, TAG ": %s: cannot lock: %d\n", creq.path, error);
+		ncld_close(fhp);
+		free(li);
+		return;
+	}
+
+	if (rc > 0)
+		printf("lock %ld queued\n", (long)li->id);
+
+	thr_lock_list = g_list_append(thr_lock_list, li);
 }
 
 static void basic_cmd(const char *cmd, const char *arg, enum creq_cmd cmd_no)
 {
-	struct creq creq = { cmd_no, };
-	struct cresp cresp;
+	struct creq creq = { 0, };
+	struct ncld_fh *fhp;
+	int error;
+	int rc;
 
 	if (!*arg) {
 		fprintf(stderr, "%s: argument required\n", cmd);
@@ -1117,18 +489,57 @@ static void basic_cmd(const char *cmd, const char *arg, enum creq_cmd cmd_no)
 	}
 
 	if (!make_abs_path(creq.path, sizeof(creq.path), arg)) {
-		fprintf(stderr, "%s: path too long\n", arg);
+		fprintf(stderr, TAG ": %s: path too long\n", arg);
 		return;
 	}
 
-	/* send message to thread */
-	write_to_thread(&creq, sizeof(creq));
+	switch (cmd_no) {
+	case CREQ_RM:
+		rc = ncld_del(nsp, creq.path);
+		break;
+	case CREQ_MKDIR:
+		rc = 0;
+		fhp = ncld_open(nsp, creq.path,
+				COM_DIRECTORY | COM_CREATE | COM_EXCL, &error,
+				0, NULL, NULL);
+		if (fhp)
+			ncld_close(fhp);
+		else
+			rc = error;
+		break;
+
+	case CREQ_UNLOCK: {
+		GList *tmp;
+		struct cldcli_lock_info *li = NULL;
+
+		tmp = thr_lock_list;
+		while (tmp) {
+			li = tmp->data;
+
+			if (!strncmp(li->path, creq.path, sizeof(li->path)))
+				break;
 
-	/* wait for and receive response from thread */
-	read_from_thread(&cresp, sizeof(cresp));
+			tmp = tmp->next;
+		}
+		if (!tmp) {
+			fprintf(stderr, TAG ": no lock found\n");
+			return;
+		}
+
+		thr_lock_list = g_list_delete_link(thr_lock_list, tmp);
+
+		rc = ncld_unlock(li->fh);
+		ncld_close(li->fh);
+		free(li);
+		break;
+		}
+	default:
+		fprintf(stderr, TAG ": IE unknown cmd %d\n", cmd_no);
+		return;
+	}
 
-	if (cresp.tcode != TC_OK) {
-		fprintf(stderr, "%s(%s) failed: %s\n", cmd, arg, cresp.msg);
+	if (rc) {
+		fprintf(stderr, TAG ": %s(%s) failed: %d\n", cmd, arg, rc);
 		return;
 	}
 }
@@ -1222,7 +633,8 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state)
 		if (atoi(arg) >= 0 && atoi(arg) <= 2)
 			cli_log.verbose = atoi(arg);
 		else {
-			fprintf(stderr, "invalid debug level: '%s'\n", arg);
+			fprintf(stderr, TAG ": invalid debug level: '%s'\n",
+				arg);
 			argp_usage(state);
 		}
 		break;
@@ -1232,13 +644,13 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state)
 		break;
 	case 'u':
 		if (strlen(arg) >= CLD_MAX_USERNAME) {
-			fprintf(stderr, "invalid user: '%s'\n", arg);
+			fprintf(stderr, TAG ": invalid user: '%s'\n", arg);
 			argp_usage(state);
 		} else
 			strcpy(our_user, arg);
 		break;
 	case 'v':
-		cldcli_verbose = true;
+		cli_log.verbose = true;
 		break;
 	case ARGP_KEY_ARG:
 		argp_usage(state);	/* too many args */
@@ -1254,27 +666,27 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state)
 
 static void prompt(void)
 {
-	fprintf(stderr, "[%s %s]$ ", our_user, clicwd);
-	fflush(stderr);
+	printf("[%s %s]$ ", our_user, clicwd);
+	fflush(stdout);
 }
 
-static char linebuf[CLD_PATH_MAX + 1];
-
 int main (int argc, char *argv[])
 {
+	char linebuf[CLD_PATH_MAX + 1];
+	struct cldc_host *dr;
 	error_t aprc;
-	char tcode;
+	int error;
 
 	/* isspace() and strcasecmp() consistency requires this */
 	setlocale(LC_ALL, "C");
 
 	g_thread_init(NULL);
 
-	cldc_init();
+	ncld_init();
 
 	aprc = argp_parse(&argp, argc, argv, 0, NULL, NULL);
 	if (aprc) {
-		fprintf(stderr, "argp_parse failed: %s\n", strerror(aprc));
+		fprintf(stderr, TAG ": argp_parse failed: %s\n", strerror(aprc));
 		return 1;
 	}
 
@@ -1283,39 +695,35 @@ int main (int argc, char *argv[])
 		char hostb[hostsz];
 
 		if (gethostname(hostb, hostsz-1) < 0) {
-			fprintf(stderr, "gethostname error: %s\n",
+			fprintf(stderr, TAG ": gethostname error: %s\n",
 				strerror(errno));
 			return 1;
 		}
 		hostb[hostsz-1] = 0;
 		if (cldc_getaddr(&host_list, hostb, &cli_log)) {
-			fprintf(stderr, "Unable to find a CLD host\n");
+			fprintf(stderr, TAG ": Unable to find a CLD host\n");
 			return 1;
 		}
 	}
 
-	if ((pipe(from_thread) < 0) || (pipe(to_thread) < 0)) {
-		perror("pipe");
-		return 1;
-	}
-
-	cldthr = g_thread_create(cld_thread, NULL, TRUE, NULL);
-	if (!cldthr) {
-		fprintf(stderr, "thread creation failed\n");
-		return 1;
-	}
+	printf("Waiting for session startup...\n");
+	fflush(stdout);
+	dr = host_list->data;
 
-	fprintf(stderr, "Waiting for thread startup...\n");
-	if (read(from_thread[0], &tcode, 1) != 1) {
-		perror("read");
-		return 1;
-	}
-	if (tcode != TC_OK) {
-		fprintf(stderr, "thread startup failed\n");
+	nsp = ncld_sess_open(dr->host, dr->port, &error, sess_event, NULL,
+			     "cldcli", "cldcli");
+	if (!nsp) {
+		if (error < 1000) {
+			fprintf(stderr, TAG ": cannot open CLD session: %s\n",
+				strerror(error));
+		} else {
+			fprintf(stderr, TAG ": cannot open CLD session: %d\n",
+				error);
+		}
 		return 1;
 	}
 
-	fprintf(stderr, "Type 'help' at the prompt to list commands.\n");
+	printf("Type 'help' at the prompt to list commands.\n");
 	prompt();
 
 	while (fgets(linebuf, sizeof(linebuf), stdin) != NULL) {
@@ -1364,13 +772,13 @@ int main (int argc, char *argv[])
 		else if (!strcmp(tok1, "cat"))
 			cmd_cat(tok2);
 		else if (!strcmp(tok1, "cpin"))
-			cmd_cp_io(tok1, tok2, false);
+			cmd_cpin(tok1, tok2);
 		else if (!strcmp(tok1, "cpout"))
-			cmd_cp_io(tok1, tok2, true);
+			cmd_cpout(tok1, tok2);
 		else if (!strcmp(tok1, "lock"))
-			basic_cmd(tok1, tok2, CREQ_LOCK);
+			cmd_lock(tok1, tok2, true);
 		else if (!strcmp(tok1, "trylock"))
-			basic_cmd(tok1, tok2, CREQ_TRYLOCK);
+			cmd_lock(tok1, tok2, false);
 		else if (!strcmp(tok1, "unlock"))
 			basic_cmd(tok1, tok2, CREQ_UNLOCK);
 		else if ((!strcmp(tok1, "list")) && tok2 &&
@@ -1388,8 +796,7 @@ int main (int argc, char *argv[])
 		prompt();
 	}
 
-	thread_running = 0;
-
+	ncld_sess_close(nsp);
 	return 0;
 }
 

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [Patch 1/1] CLD: Introduce the "New CLD" API
  2010-02-07 19:15 [Patch 1/1] CLD: Introduce the "New CLD" API Pete Zaitcev
@ 2010-02-07 22:26 ` Jeff Garzik
  2010-02-08 12:32 ` Jeff Garzik
  2010-02-14  0:52 ` Jeff Garzik
  2 siblings, 0 replies; 17+ messages in thread
From: Jeff Garzik @ 2010-02-07 22:26 UTC (permalink / raw)
  To: Pete Zaitcev; +Cc: Project Hail List

On 02/07/2010 02:15 PM, Pete Zaitcev wrote:
> The "traditional" CLD API is too difficult to program. In particular,
> switching from a rigid "Group" policy to arbitrary paths in existing
> clients in Chunk and tabled turned out to be next to impossible.
> The issue is due to the fundamental nature of the API as based on very
> fine-grained events.
>
> So, in the interests of clients, introduce the "new" API. Its basic
> definition is in<ncld.h>. It presents a filesystem-like interface,
> extended with event callbacks for coarse events, such as an end of
> CLD session.
>
> The patch converts all in-tree clients from cldc_xxx to ncld_xxx and
> discards some of code that became unused (test/util.c).
>
> Signed-Off-By: Pete Zaitcev<zaitcev@redhat.com>

At a quick glance, looks good.  A few nits like the "if (log)" stuff and 
indenting struct field names jump out, but nothing major.  I'll give it 
a thorough review and apply on Monday...

	Jeff



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Patch 1/1] CLD: Introduce the "New CLD" API
  2010-02-07 19:15 [Patch 1/1] CLD: Introduce the "New CLD" API Pete Zaitcev
  2010-02-07 22:26 ` Jeff Garzik
@ 2010-02-08 12:32 ` Jeff Garzik
  2010-02-09  0:30   ` Pete Zaitcev
  2010-02-09  1:46   ` Pete Zaitcev
  2010-02-14  0:52 ` Jeff Garzik
  2 siblings, 2 replies; 17+ messages in thread
From: Jeff Garzik @ 2010-02-08 12:32 UTC (permalink / raw)
  To: Pete Zaitcev; +Cc: Project Hail List

On 02/07/2010 02:15 PM, Pete Zaitcev wrote:
> The "traditional" CLD API is too difficult to program. In particular,
> switching from a rigid "Group" policy to arbitrary paths in existing
> clients in Chunk and tabled turned out to be next to impossible.
> The issue is due to the fundamental nature of the API as based on very
> fine-grained events.
>
> So, in the interests of clients, introduce the "new" API. Its basic
> definition is in<ncld.h>. It presents a filesystem-like interface,
> extended with event callbacks for coarse events, such as an end of
> CLD session.
>
> The patch converts all in-tree clients from cldc_xxx to ncld_xxx and
> discards some of code that became unused (test/util.c).
>
> Signed-Off-By: Pete Zaitcev<zaitcev@redhat.com>
>
> ---
>   include/Makefile.am    |    2
>   include/ncld.h         |   88 ++
>   lib/cldc-dns.c         |   92 +-
>   lib/cldc.c             |  856 ++++++++++++++++++++++++++
>   test/Makefile.am       |    5
>   test/it-works.c        |  125 ---
>   test/load-file-event.c |  244 +------
>   test/lock-file-event.c |  269 +-------
>   test/save-file-event.c |  245 -------
>   test/test.h            |    5
>   test/util.c            |   79 --
>   tools/cldcli.c         | 1249 ++++++++++-----------------------------
>   12 files changed, 1433 insertions(+), 1826 deletions(-)

applied, with changes:

- some cosmetic reformatting, to match existing code

- log param in cldc-dns should not be made conditional as an 
undocumented side effect of ncld


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Patch 1/1] CLD: Introduce the "New CLD" API
  2010-02-08 12:32 ` Jeff Garzik
@ 2010-02-09  0:30   ` Pete Zaitcev
  2010-02-09  6:25     ` Jeff Garzik
  2010-02-09  1:46   ` Pete Zaitcev
  1 sibling, 1 reply; 17+ messages in thread
From: Pete Zaitcev @ 2010-02-09  0:30 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: Project Hail List

On Mon, 08 Feb 2010 07:32:56 -0500
Jeff Garzik <jeff@garzik.org> wrote:

> - log param in cldc-dns should not be made conditional as an 
> undocumented side effect of ncld

I thought it was compatible with the old clients, they can continue
to pass the log in an argument as they did before.

BTW, I noticed you reworked the tests, which is fine, but could you
also rename lock-file-event to lock-file? The idea was to have two
versions: one with libevent and one without, but that never happened.

-- Pete

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Patch 1/1] CLD: Introduce the "New CLD" API
  2010-02-08 12:32 ` Jeff Garzik
  2010-02-09  0:30   ` Pete Zaitcev
@ 2010-02-09  1:46   ` Pete Zaitcev
  2010-02-09  2:06     ` Jeff Garzik
  1 sibling, 1 reply; 17+ messages in thread
From: Pete Zaitcev @ 2010-02-09  1:46 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: Project Hail List

On Mon, 08 Feb 2010 07:32:56 -0500
Jeff Garzik <jeff@garzik.org> wrote:

> - log param in cldc-dns should not be made conditional as an 
> undocumented side effect of ncld

I pulled, and it appears that you merged a code that crashes at the
first error message. We need something like this:

diff --git a/lib/cldc.c b/lib/cldc.c
index 7c30064..beb1e22 100644
--- a/lib/cldc.c
+++ b/lib/cldc.c
@@ -98,6 +98,15 @@ static void cldc_errlog(int prio, const char *fmt, ...)
 	va_end(ap);
 }
 
+static void ncld_nolog(int prio, const char *fmt, ...)
+{
+	;
+}
+
+static struct hail_log ncld_log = {
+	.func	= ncld_nolog
+};
+
 static int ack_seqid(struct cldc_session *sess, uint64_t seqid_le)
 {
 	XDR xdrs;
@@ -1297,7 +1306,7 @@ static int ncld_getsrv(char **hostp, unsigned short *portp)
 		return errno;
 	hostb[hostsz-1] = 0;
 
-	if (cldc_getaddr(&host_list, hostb, NULL))
+	if (cldc_getaddr(&host_list, hostb, &ncld_log))
 		return 1001;
 
 	/*
@@ -1490,7 +1499,7 @@ static struct cldc_ops ncld_ops = {
 	.timer_ctl	= ncld_p_timer_ctl,
 	.pkt_send	= ncld_p_pkt_send,
 	.event		= ncld_p_event,
-	.errlog		= NULL,
+	.errlog		= ncld_nolog,
 };
 
 static int ncld_new_sess(struct cldc_call_opts *copts, enum cle_err_codes errc)

Stubbing of ncld_ops is not related to the crash, but just for
consistency.

-- Pete

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [Patch 1/1] CLD: Introduce the "New CLD" API
  2010-02-09  1:46   ` Pete Zaitcev
@ 2010-02-09  2:06     ` Jeff Garzik
  2010-02-09  2:17       ` Pete Zaitcev
  0 siblings, 1 reply; 17+ messages in thread
From: Jeff Garzik @ 2010-02-09  2:06 UTC (permalink / raw)
  To: Pete Zaitcev; +Cc: Project Hail List

On 02/08/2010 08:46 PM, Pete Zaitcev wrote:
> On Mon, 08 Feb 2010 07:32:56 -0500
> Jeff Garzik<jeff@garzik.org>  wrote:
>
>> - log param in cldc-dns should not be made conditional as an
>> undocumented side effect of ncld
>
> I pulled, and it appears that you merged a code that crashes at the
> first error message. We need something like this:

So it successfully exposed locations that failed to propagate logging 
support.  :)


> diff --git a/lib/cldc.c b/lib/cldc.c
> index 7c30064..beb1e22 100644
> --- a/lib/cldc.c
> +++ b/lib/cldc.c
> @@ -98,6 +98,15 @@ static void cldc_errlog(int prio, const char *fmt, ...)
>   	va_end(ap);
>   }
>
> +static void ncld_nolog(int prio, const char *fmt, ...)
> +{
> +	;
> +}
> +
> +static struct hail_log ncld_log = {
> +	.func	= ncld_nolog
> +};
> +
>   static int ack_seqid(struct cldc_session *sess, uint64_t seqid_le)
>   {
>   	XDR xdrs;
> @@ -1297,7 +1306,7 @@ static int ncld_getsrv(char **hostp, unsigned short *portp)
>   		return errno;
>   	hostb[hostsz-1] = 0;
>
> -	if (cldc_getaddr(&host_list, hostb, NULL))
> +	if (cldc_getaddr(&host_list, hostb,&ncld_log))
>   		return 1001;
>

Logging pointer should be supplied by the caller...  that is the larger 
bug.  Needing a no-op log function is just an indication of that.

	Jeff


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Patch 1/1] CLD: Introduce the "New CLD" API
  2010-02-09  2:06     ` Jeff Garzik
@ 2010-02-09  2:17       ` Pete Zaitcev
  2010-02-09  4:55         ` Jeff Garzik
  0 siblings, 1 reply; 17+ messages in thread
From: Pete Zaitcev @ 2010-02-09  2:17 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: Project Hail List

On Mon, 08 Feb 2010 21:06:17 -0500
Jeff Garzik <jeff@garzik.org> wrote:

> > -	if (cldc_getaddr(&host_list, hostb, NULL))
> > +	if (cldc_getaddr(&host_list, hostb, &ncld_log))
> >   		return 1001;

> Logging pointer should be supplied by the caller...  that is the larger 
> bug.  Needing a no-op log function is just an indication of that.

I did it before, but then every client, without exception, needed
to include <stdarg.h> and provide the log. And what for? This is
STUPID and proof is in the pudding: your getsrvinfo does not do
anything of the sort. Might as well replace cldc_getadd with getsrvinfo
and then everyone becomes happy.

-- Pete

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Patch 1/1] CLD: Introduce the "New CLD" API
  2010-02-09  2:17       ` Pete Zaitcev
@ 2010-02-09  4:55         ` Jeff Garzik
  2010-02-09  5:35           ` Pete Zaitcev
  0 siblings, 1 reply; 17+ messages in thread
From: Jeff Garzik @ 2010-02-09  4:55 UTC (permalink / raw)
  To: Pete Zaitcev; +Cc: Project Hail List

On 02/08/2010 09:17 PM, Pete Zaitcev wrote:
> On Mon, 08 Feb 2010 21:06:17 -0500
> Jeff Garzik<jeff@garzik.org>  wrote:
>
>>> -	if (cldc_getaddr(&host_list, hostb, NULL))
>>> +	if (cldc_getaddr(&host_list, hostb,&ncld_log))
>>>    		return 1001;
>
>> Logging pointer should be supplied by the caller...  that is the larger
>> bug.  Needing a no-op log function is just an indication of that.
>
> I did it before, but then every client, without exception, needed
> to include<stdarg.h>  and provide the log. And what for? This is
> STUPID and proof is in the pudding: your getsrvinfo does not do
> anything of the sort.

Possibly true -- but it is worse to introduce internal inconsistencies. 
  It is far better to remove debugging statements completely than to 
create inconsistent usage.


> Might as well replace cldc_getadd with getsrvinfo
> and then everyone becomes happy.

Seems a good fit :)

	Jeff



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Patch 1/1] CLD: Introduce the "New CLD" API
  2010-02-09  4:55         ` Jeff Garzik
@ 2010-02-09  5:35           ` Pete Zaitcev
  2010-02-09  6:03             ` Jeff Garzik
  0 siblings, 1 reply; 17+ messages in thread
From: Pete Zaitcev @ 2010-02-09  5:35 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: Project Hail List

On Mon, 08 Feb 2010 23:55:03 -0500
Jeff Garzik <jeff@garzik.org> wrote:

> >>> -	if (cldc_getaddr(&host_list, hostb, NULL))
> >>> +	if (cldc_getaddr(&host_list, hostb,&ncld_log))
> >>>    		return 1001;
> >
> >> Logging pointer should be supplied by the caller...  that is the larger
> >> bug.  Needing a no-op log function is just an indication of that.
> >
> > I did it before, but then every client, without exception, needed
> > to include<stdarg.h>  and provide the log. And what for? This is
> > STUPID and proof is in the pudding: your getsrvinfo does not do
> > anything of the sort.
> 
> Possibly true -- but it is worse to introduce internal inconsistencies. 
>   It is far better to remove debugging statements completely than to 
> create inconsistent usage.

Hmm, you may be right about that.

> > Might as well replace cldc_getadd with getsrvinfo
> > and then everyone becomes happy.
> 
> Seems a good fit :)

How far along were you with getsrvinfo? I only have the header
that you sent to the list just before Christmas.

-- Pete

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Patch 1/1] CLD: Introduce the "New CLD" API
  2010-02-09  5:35           ` Pete Zaitcev
@ 2010-02-09  6:03             ` Jeff Garzik
  0 siblings, 0 replies; 17+ messages in thread
From: Jeff Garzik @ 2010-02-09  6:03 UTC (permalink / raw)
  To: Pete Zaitcev; +Cc: Project Hail List

[-- Attachment #1: Type: text/plain, Size: 1212 bytes --]

On 02/09/2010 12:35 AM, Pete Zaitcev wrote:
> On Mon, 08 Feb 2010 23:55:03 -0500
> Jeff Garzik<jeff@garzik.org>  wrote:
>
>>>>> -	if (cldc_getaddr(&host_list, hostb, NULL))
>>>>> +	if (cldc_getaddr(&host_list, hostb,&ncld_log))
>>>>>     		return 1001;
>>>
>>>> Logging pointer should be supplied by the caller...  that is the larger
>>>> bug.  Needing a no-op log function is just an indication of that.
>>>
>>> I did it before, but then every client, without exception, needed
>>> to include<stdarg.h>   and provide the log. And what for? This is
>>> STUPID and proof is in the pudding: your getsrvinfo does not do
>>> anything of the sort.
>>
>> Possibly true -- but it is worse to introduce internal inconsistencies.
>>    It is far better to remove debugging statements completely than to
>> create inconsistent usage.
>
> Hmm, you may be right about that.
>
>>> Might as well replace cldc_getadd with getsrvinfo
>>> and then everyone becomes happy.
>>
>> Seems a good fit :)
>
> How far along were you with getsrvinfo? I only have the header
> that you sent to the list just before Christmas.

Coding complete, but needed testing.  Probably works, since it came from 
working code.  See attached.

	Jeff



[-- Attachment #2: getsrvinfo.h --]
[-- Type: text/plain, Size: 1233 bytes --]

#ifndef __GETSRVINFO_H__
#define __GETSRVINFO_H__

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

struct srvinfo;

enum srvinfo_error_codes {
	ESI_NONE		= 0,	/* no error */
	ESI_CORRUPT		= 1,	/* server returned bad data */
	ESI_FAIL		= 2,	/* server returned permanent failure */
	ESI_AGAIN		= 3,	/* server returned temporary failure;
					 * try again later.*/
	ESI_OOM			= 4,	/* internal memory alloc failed */
	ESI_INVAL		= 5,	/* invalid argument(s) */
};

enum srvinfo_flags {
	FSI_NO_ADDR		= (1U << 0),  /* skip host->addrs lookup */
};

struct srvinfo {
	unsigned int		si_prio;    /* SRV priority */
	unsigned int		si_weight;  /* SRV weight */
	char			*si_target; /* SRV target domainname */
	unsigned short		si_port;    /* SRV port */

	struct addrinfo		*si_addr;   /* addresses returned
					     * from getaddrinfo(3) lookup
					     * on si_target */
	struct srvinfo		*si_next;   /* next srvinfo in result list */
};

extern int getsrvinfo(const char *service_name, const char *domain_name,
		      const struct addrinfo *hints,
		      unsigned int flags, struct srvinfo **res);
extern void freesrvinfo(struct srvinfo *res);
extern const char *gsi_strerror(int errcode);

#endif /* __GETSRVINFO_H__ */

[-- Attachment #3: getsrvinfo.c --]
[-- Type: text/plain, Size: 5530 bytes --]


/*
 * Copyright 2009 Red Hat, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <netdb.h>
#include <resolv.h>
#include "getsrvinfo.h"

#define __must_be_array(a) \
	(__builtin_types_compatible_p(typeof(a), typeof(&a[0])))
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))

enum {
	gsi_max_dom_name_sz		= 64,
	gsi_dns_buf_sz			= 1024,
};

static int fill_srvinfo(struct srvinfo *si,
			const struct addrinfo *hints,
			unsigned int gsi_flags,
			unsigned int priority,
			unsigned int weight, unsigned int port,
			unsigned int nlen, const char *name)
{
	char portstr[11];
	char *hostname;
	struct addrinfo *res0 = NULL;
	int rc = 0;

	sprintf(portstr, "%u", port);

	hostname = malloc(nlen + 1);
	if (!hostname)
		return -ENOMEM;

	memcpy(hostname, name, nlen);
	hostname[nlen] = 0;

	if (!(gsi_flags & FSI_NO_ADDR)) {
		rc = getaddrinfo(hostname, portstr, hints, &res0);

		/* because we do not wish failure of one lookup
		 * to cause failure of the entire operation,
		 * we simply record the lack of an address (NULL)
		 * and move on.
		 */
		if (rc)
			res0 = NULL;
	}

	si->si_prio = priority;
	si->si_weight = weight;
	si->si_target = hostname;
	si->si_port = port;

	si->si_addr = res0;
	si->si_next = NULL;

	return 0;
}

void freesrvinfo(struct srvinfo *res)
{
	while (res) {
		struct srvinfo *tmp;
		
		tmp = res;
		res = res->si_next;

		if (tmp->si_addr)
			freeaddrinfo(tmp->si_addr);
		free(tmp->si_target);
		free(tmp);
	}
}

int getsrvinfo(const char *service_name, const char *domain_name,
	       const struct addrinfo *hints, unsigned int gsi_flags,
	       struct srvinfo **res_out)
{
	unsigned char resp[gsi_dns_buf_sz];
	int rlen;
	ns_msg nsb;
	ns_rr rrb;
	int rrlen;
	char hostb[gsi_max_dom_name_sz];
	struct srvinfo *si, *res = NULL, *res_last = NULL;
	const unsigned char *p;
	int rc, gsi_rc, i;

	if (!domain_name || !res_out)
		return ESI_INVAL;

	*res_out = NULL;

	/* we concatencate service_name and domain_name as a helpful
	 * service for the caller, because it is very common
	 * that service_name is either completely static, or at least
	 * stored in a separate variable from domain_name.
	 */
	if (service_name) {
		char *name;
		size_t name_len;
		int has_dot;

		has_dot = (service_name[strlen(service_name) - 1] == '.');
		name_len = strlen(service_name) + strlen(domain_name) +
			   (has_dot ? 0 : 1) + 1;

		name = malloc(name_len);
		if (!name)
			return ESI_OOM;

		snprintf(name, name_len, "%s%s%s", service_name,
			     has_dot ? "" : ".",
			     domain_name);
			
		rc = res_search(name, ns_c_in, ns_t_srv, resp, sizeof(resp));

		free(name);
	} else {
		rc = res_search(domain_name, ns_c_in, ns_t_srv,
				resp, sizeof(resp));
	}

	/* parse resolver return value */
	if (rc < 0) {
		switch (h_errno) {
		case TRY_AGAIN:
			return ESI_AGAIN;
		case HOST_NOT_FOUND:
		case NO_DATA:
		case NO_RECOVERY:
		default:
			return ESI_FAIL;
		}
	}
	rlen = rc;

	if (rlen == 0)
		return ESI_FAIL;

	/* set up DNS result parse */
	if (ns_initparse(resp, rlen, &nsb) < 0)
		return ESI_CORRUPT;

	/* iterate through each answer.  Because DNS packets may
	 * be truncated, we do not signal an error on
	 * short-length faults found during packet parsing
	 */
	for (i = 0; i < ns_msg_count(nsb, ns_s_an); i++) {
		rc = ns_parserr(&nsb, ns_s_an, i, &rrb);
		if (rc < 0)
			continue;

		if (ns_rr_class(rrb) != ns_c_in)
			continue;

		switch (ns_rr_type(rrb)) {
		case ns_t_srv:
			rrlen = ns_rr_rdlen(rrb);
			if (rrlen < 8) {	/* 2+2+2 and 2 for host */
				break;
			}
			p = ns_rr_rdata(rrb);
			rc = dn_expand(resp, resp+rlen, p+6,
				       hostb, gsi_max_dom_name_sz);
			if (rc < 0) {
				break;
			}
			if (rc < 2) {
				break;
			}

			si = malloc(sizeof(*si));
			if (!si) {
				gsi_rc = ESI_OOM;
				goto err_out;
			}

			if (fill_srvinfo(si, hints, gsi_flags,
					 ns_get16(p+0),
					 ns_get16(p+2),
					 ns_get16(p+4),
					 rc, hostb)) {
				free(si);
				gsi_rc = ESI_OOM;
				goto err_out;
			}

			/* if first item, set BOL-ptr */
			if (!res)
				res = si;

			/* append to EOL */
			if (res_last)
				res_last->si_next = si;
			res_last = si;

			break;

		case ns_t_cname:	/* impossible, but ... ? */
		default:
			break;
		}
	}

	*res_out = res;
	return ESI_NONE;

err_out:
	freesrvinfo(res);
	return gsi_rc;
}

static const char *gsi_error_str[] = {
	[ESI_NONE]		= "no error",
	[ESI_CORRUPT]		= "server returned bad data",
	[ESI_FAIL]		= "server returned permanent failure",
	[ESI_AGAIN]		= "server returned temporary failure",
	[ESI_OOM]		= "internal memory alloc failed",
	[ESI_INVAL]		= "invalid argument(s)",
};

const char *gsi_strerror(int errcode)
{
	if (errcode < 0 || errcode >= ARRAY_SIZE(gsi_error_str))
		return NULL;
	
	return gsi_error_str[errcode];
}


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Patch 1/1] CLD: Introduce the "New CLD" API
  2010-02-09  0:30   ` Pete Zaitcev
@ 2010-02-09  6:25     ` Jeff Garzik
  0 siblings, 0 replies; 17+ messages in thread
From: Jeff Garzik @ 2010-02-09  6:25 UTC (permalink / raw)
  To: Pete Zaitcev; +Cc: Project Hail List

On 02/08/2010 07:30 PM, Pete Zaitcev wrote:
> BTW, I noticed you reworked the tests, which is fine, but could you
> also rename lock-file-event to lock-file? The idea was to have two
> versions: one with libevent and one without, but that never happened.

Easy enough... done.

	Jeff


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Patch 1/1] CLD: Introduce the "New CLD" API
  2010-02-07 19:15 [Patch 1/1] CLD: Introduce the "New CLD" API Pete Zaitcev
  2010-02-07 22:26 ` Jeff Garzik
  2010-02-08 12:32 ` Jeff Garzik
@ 2010-02-14  0:52 ` Jeff Garzik
  2010-02-18  0:05   ` Pete Zaitcev
  2 siblings, 1 reply; 17+ messages in thread
From: Jeff Garzik @ 2010-02-14  0:52 UTC (permalink / raw)
  To: Pete Zaitcev; +Cc: Project Hail List

On 02/07/2010 02:15 PM, Pete Zaitcev wrote:
> +	case CREQ_MKDIR:
> +		rc = 0;
> +		fhp = ncld_open(nsp, creq.path,
> +				COM_DIRECTORY | COM_CREATE | COM_EXCL,&error,
> +				0, NULL, NULL);
> +		if (fhp)
> +			ncld_close(fhp);
> +		else
> +			rc = error;
> +		break;
> +
[...]
> -	}
> -	if (tcode != TC_OK) {
> -		fprintf(stderr, "thread startup failed\n");
> +	nsp = ncld_sess_open(dr->host, dr->port,&error, sess_event, NULL,
> +			     "cldcli", "cldcli");
> +	if (!nsp) {
> +		if (error<  1000) {
> +			fprintf(stderr, TAG ": cannot open CLD session: %s\n",
> +				strerror(error));
> +		} else {
> +			fprintf(stderr, TAG ": cannot open CLD session: %d\n",
> +				error);
> +		}
>   		return 1;
>   	}


A point of style:  the 'p' suffix is discouraged.  It is too much like 
the much-maligned Hungarian notation, which is odious in part because it 
duplicates information found in the type definition.  In this case, 'p' 
duplicates the indication that it is a pointer.

The return value from ncld_sess_open() should be named 'ns' or 'sess' or 
similar.  The return value from ncld_open() should be named 'fh' or similar.

	Jeff



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Patch 1/1] CLD: Introduce the "New CLD" API
  2010-02-14  0:52 ` Jeff Garzik
@ 2010-02-18  0:05   ` Pete Zaitcev
  2010-02-18  1:18     ` Jeff Garzik
  0 siblings, 1 reply; 17+ messages in thread
From: Pete Zaitcev @ 2010-02-18  0:05 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: Project Hail List

On Sat, 13 Feb 2010 19:52:18 -0500
Jeff Garzik <jeff@garzik.org> wrote:

> A point of style:  the 'p' suffix is discouraged.

I'll batch-rename it when I get better.

-- Pete

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Patch 1/1] CLD: Introduce the "New CLD" API
  2010-02-18  0:05   ` Pete Zaitcev
@ 2010-02-18  1:18     ` Jeff Garzik
  2010-02-19  1:35       ` Pete Zaitcev
  0 siblings, 1 reply; 17+ messages in thread
From: Jeff Garzik @ 2010-02-18  1:18 UTC (permalink / raw)
  To: Pete Zaitcev; +Cc: Project Hail List

[-- Attachment #1: Type: text/plain, Size: 612 bytes --]

On 02/17/2010 07:05 PM, Pete Zaitcev wrote:
> On Sat, 13 Feb 2010 19:52:18 -0500
> Jeff Garzik<jeff@garzik.org>  wrote:
>
>> A point of style:  the 'p' suffix is discouraged.
>
> I'll batch-rename it when I get better.

Get well soon...

Since it sounds like there will be no conflicting patches, I went ahead 
and fixed things up myself, using my trusty sar (search-and-replace) 
script.  I find sar quite useful, because it (a) matches and replaces on 
word boundaries, and (b) it performs in-situ updates, unlike most other 
Unix tools.

Attached are both sar, and the cld commit it helped produce.

	Jeff




[-- Attachment #2: sar --]
[-- Type: text/plain, Size: 652 bytes --]

#!/usr/bin/perl -w

use strict;

my ($search, $replace, $fn, @data, $mod);
my $modified = 0;

die "usage: sar search-text replace-text files..."
	unless $search = shift;
die "usage: sar search-text replace-text files..."
	unless $replace = shift;

foreach $fn (@ARGV) {
	@data = ();
	$mod = 0;

	open(F, $fn) or die "$fn: $!\n";
	while (<F>) {
		if ($mod) {
			s/\b$search\b/$replace/go;
		}
		elsif (/\b$search\b/o) {
			$mod = 1;
			s/\b$search\b/$replace/go;
		}
		push(@data, $_);
	}
	close(F);

	if ($mod) {
		open(F, ">$fn") or die "$fn: $!\n";
		print F @data;
		close(F);
		$modified++;
	}
}

printf "%d files modified.\n", $modified;
exit(0);

[-- Attachment #3: patch --]
[-- Type: text/plain, Size: 38910 bytes --]

commit 1c7d8de3e44e641651f766d6863780343ecaa5a8
Author: Jeff Garzik <jeff@garzik.org>
Date:   Wed Feb 17 20:14:04 2010 -0500

    Cosmetic renaming related to ncld API.
    
    s/fhp/fh/
    s/ses/sess/
    s/nsp/nsess/
    
    And use a more standard way of calling callbacks:
    
    -               if (nsp->event)
    -                       (*nsp->event)(nsp->event_arg, what);
    +               if (nsess->event)
    +                       nsess->event(nsess->event_arg, what);
    
    Signed-off-by: Jeff Garzik <jgarzik@redhat.com>

diff --git a/include/ncld.h b/include/ncld.h
index 4664299..dbf126a 100644
--- a/include/ncld.h
+++ b/include/ncld.h
@@ -47,7 +47,7 @@ struct ncld_sess {
 };
 
 struct ncld_fh {
-	struct ncld_sess	*ses;
+	struct ncld_sess	*sess;
 	struct cldc_fh		*fh;	/* FIXME cldc_open2 take direct & */
 	bool			is_open;
 	int			errc;
@@ -76,8 +76,8 @@ extern struct ncld_sess *ncld_sess_open(const char *host, int port,
 extern struct ncld_fh *ncld_open(struct ncld_sess *s, const char *fname,
 	unsigned int mode, int *error, unsigned int events,
 	void (*event)(void *, unsigned int), void *ev_arg);
-extern int ncld_del(struct ncld_sess *nsp, const char *fname);
-extern struct ncld_read *ncld_get(struct ncld_fh *fhp, int *error);
+extern int ncld_del(struct ncld_sess *nsess, const char *fname);
+extern struct ncld_read *ncld_get(struct ncld_fh *fh, int *error);
 extern struct ncld_read *ncld_get_meta(struct ncld_fh *fh, int *error);
 extern void ncld_read_free(struct ncld_read *rp);
 extern int ncld_write(struct ncld_fh *, const void *data, long len);
diff --git a/lib/cldc.c b/lib/cldc.c
index 74ac18b..afe88ab 100644
--- a/lib/cldc.c
+++ b/lib/cldc.c
@@ -1343,8 +1343,8 @@ static int ncld_gethost(char **hostp, unsigned short *portp,
 
 static void ncld_udp_timer_event(struct cld_timer *timer)
 {
-	struct ncld_sess *nsp = timer->userdata;
-	struct cldc_udp *udp = nsp->udp;
+	struct ncld_sess *nsess = timer->userdata;
+	struct cldc_udp *udp = nsess->udp;
 
 	if (udp->cb)
 		udp->cb(udp->sess, udp->cb_private);
@@ -1361,13 +1361,13 @@ enum {
  * went wrong, so system features should report it (usualy as a core).
  * When debugging, strace or -F mode will capture the output.
  */
-static void ncld_thread_command(struct ncld_sess *nsp)
+static void ncld_thread_command(struct ncld_sess *nsess)
 {
 	ssize_t rrc;
 	unsigned char cmd;
 	uint32_t what;
 
-	rrc = read(nsp->to_thread[0], &cmd, 1);
+	rrc = read(nsess->to_thread[0], &cmd, 1);
 	if (rrc < 0) {
 		fprintf(stderr, "read error: %s\n", strerror(errno));
 		abort();
@@ -1381,13 +1381,13 @@ static void ncld_thread_command(struct ncld_sess *nsp)
 		/* No answer to requestor. Wait with g_thread_join. */
 		g_thread_exit(NULL);
 	} else if (cmd == NCLD_CMD_SESEV) {
-		rrc = read(nsp->to_thread[0], &what, sizeof(uint32_t));
+		rrc = read(nsess->to_thread[0], &what, sizeof(uint32_t));
 		if (rrc < sizeof(uint32_t)) {
 			fprintf(stderr, "bad read param\n");
 			g_thread_exit(NULL);
 		}
-		if (nsp->event)
-			(*nsp->event)(nsp->event_arg, what);
+		if (nsess->event)
+			nsess->event(nsess->event_arg, what);
 	} else {
 		fprintf(stderr, "bad command 0x%x\n", cmd);
 		abort();
@@ -1396,21 +1396,21 @@ static void ncld_thread_command(struct ncld_sess *nsp)
 
 static gpointer ncld_sess_thr(gpointer data)
 {
-	struct ncld_sess *nsp = data;
+	struct ncld_sess *nsess = data;
 	struct pollfd pfd[2];
 	time_t tmo;
 	int i;
 	int rc;
 
 	for (;;) {
-		g_mutex_lock(nsp->mutex);
-		tmo = cld_timers_run(&nsp->tlist);
-		g_mutex_unlock(nsp->mutex);
+		g_mutex_lock(nsess->mutex);
+		tmo = cld_timers_run(&nsess->tlist);
+		g_mutex_unlock(nsess->mutex);
 
 		memset(pfd, 0, sizeof(pfd));
-		pfd[0].fd = nsp->to_thread[0];
+		pfd[0].fd = nsess->to_thread[0];
 		pfd[0].events = POLLIN;
-		pfd[1].fd = nsp->udp->fd;
+		pfd[1].fd = nsess->udp->fd;
 		pfd[1].events = POLLIN;
 
 		rc = poll(pfd, 2, tmo ? tmo*1000 : -1);
@@ -1424,11 +1424,11 @@ static gpointer ncld_sess_thr(gpointer data)
 		for (i = 0; i < ARRAY_SIZE(pfd); i++) {
 			if (pfd[i].revents) {
 				if (i == 0) {
-					ncld_thread_command(nsp);
+					ncld_thread_command(nsess);
 				} else {
-					g_mutex_lock(nsp->mutex);
-					cldc_udp_receive_pkt(nsp->udp);
-					g_mutex_unlock(nsp->mutex);
+					g_mutex_lock(nsess->mutex);
+					cldc_udp_receive_pkt(nsess->udp);
+					g_mutex_unlock(nsess->mutex);
 				}
 			}
 		}
@@ -1440,28 +1440,28 @@ static gpointer ncld_sess_thr(gpointer data)
 /*
  * Ask the thread to exit and wait until it does.
  */
-static void ncld_thr_end(struct ncld_sess *nsp)
+static void ncld_thr_end(struct ncld_sess *nsess)
 {
 	unsigned char cmd;
 
 	cmd = NCLD_CMD_END;
-	write(nsp->to_thread[1], &cmd, 1);
-	g_thread_join(nsp->thread);
+	write(nsess->to_thread[1], &cmd, 1);
+	g_thread_join(nsess->thread);
 }
 
 static bool ncld_p_timer_ctl(void *priv, bool add,
 			     int (*cb)(struct cldc_session *, void *),
 			     void *cb_priv, time_t secs)
 {
-	struct ncld_sess *nsp = priv;
-	struct cldc_udp *udp = nsp->udp;
+	struct ncld_sess *nsess = priv;
+	struct cldc_udp *udp = nsess->udp;
 
 	if (add) {
 		udp->cb = cb;
 		udp->cb_private = cb_priv;
-		cld_timer_add(&nsp->tlist, &nsp->udp_timer, time(NULL) + secs);
+		cld_timer_add(&nsess->tlist, &nsess->udp_timer, time(NULL) + secs);
 	} else {
-		cld_timer_del(&nsp->tlist, &nsp->udp_timer);
+		cld_timer_del(&nsess->tlist, &nsess->udp_timer);
 	}
 	return true;
 }
@@ -1469,31 +1469,31 @@ static bool ncld_p_timer_ctl(void *priv, bool add,
 static int ncld_p_pkt_send(void *priv, const void *addr, size_t addrlen,
 			       const void *buf, size_t buflen)
 {
-	struct ncld_sess *nsp = priv;
-	return cldc_udp_pkt_send(nsp->udp, addr, addrlen, buf, buflen);
+	struct ncld_sess *nsess = priv;
+	return cldc_udp_pkt_send(nsess->udp, addr, addrlen, buf, buflen);
 }
 
 static void ncld_p_event(void *priv, struct cldc_session *csp,
 			 struct cldc_fh *fh, uint32_t what)
 {
-	struct ncld_sess *nsp = priv;
+	struct ncld_sess *nsess = priv;
 	unsigned char cmd;
 
 	if (what == CE_SESS_FAILED) {
-		if (nsp->udp->sess != csp)
+		if (nsess->udp->sess != csp)
 			abort();
-		nsp->is_up = false;
+		nsess->is_up = false;
 		/* XXX wake up all I/O waiters here */
 		/*
 		 * This is a trick. As a direct callback from clcd layer,
-		 * we are running under nsp->mutex, so we cannot call back
+		 * we are running under nsess->mutex, so we cannot call back
 		 * into a user of ncld. If we do, it may invoke another
 		 * ncld operation and deadlock. So, bump session callbacks
 		 * into the part of the helper thread that runs unlocked.
 		 */
 		cmd = NCLD_CMD_SESEV;
-		write(nsp->to_thread[1], &cmd, 1);
-		write(nsp->to_thread[1], &what, sizeof(what));
+		write(nsess->to_thread[1], &cmd, 1);
+		write(nsess->to_thread[1], &what, sizeof(what));
 	}
 }
 
@@ -1506,25 +1506,25 @@ static struct cldc_ops ncld_ops = {
 
 static int ncld_new_sess(struct cldc_call_opts *copts, enum cle_err_codes errc)
 {
-	struct ncld_sess *nsp = copts->private;
+	struct ncld_sess *nsess = copts->private;
 
 	/*
 	 * All callbacks from cldc layer run on the context of the thread
-	 * with nsp->mutex locked, so we don't lock it again here.
+	 * with nsess->mutex locked, so we don't lock it again here.
 	 */
-	nsp->errc = errc;
-	nsp->is_up = true;
-	g_cond_broadcast(nsp->cond);
+	nsess->errc = errc;
+	nsess->is_up = true;
+	g_cond_broadcast(nsess->cond);
 	return 0;
 }
 
-static int ncld_wait_session(struct ncld_sess *nsp)
+static int ncld_wait_session(struct ncld_sess *nsess)
 {
-	g_mutex_lock(nsp->mutex);
-	while (!nsp->is_up)
-		g_cond_wait(nsp->cond, nsp->mutex);
-	g_mutex_unlock(nsp->mutex);
-	return nsp->errc;
+	g_mutex_lock(nsess->mutex);
+	while (!nsess->is_up)
+		g_cond_wait(nsess->cond, nsess->mutex);
+	g_mutex_unlock(nsess->mutex);
+	return nsess->errc;
 }
 
 /*
@@ -1553,91 +1553,91 @@ struct ncld_sess *ncld_sess_open(const char *host, int port, int *error,
 				 void *ev_arg, const char *cld_user,
 				 const char *cld_key)
 {
-	struct ncld_sess *nsp;
+	struct ncld_sess *nsess;
 	struct cldc_call_opts copts;
 	int err;
 	GError *gerr;
 	int rc;
 
 	err = ENOMEM;
-	nsp = malloc(sizeof(struct ncld_sess));
-	if (!nsp)
+	nsess = malloc(sizeof(struct ncld_sess));
+	if (!nsess)
 		goto out_sesalloc;
-	memset(nsp, 0, sizeof(struct ncld_sess));
-	cld_timer_init(&nsp->udp_timer, "nsp-udp-timer", ncld_udp_timer_event,
-		       nsp);
-	nsp->mutex = g_mutex_new();
-	if (!nsp->mutex)
+	memset(nsess, 0, sizeof(struct ncld_sess));
+	cld_timer_init(&nsess->udp_timer, "nsess-udp-timer", ncld_udp_timer_event,
+		       nsess);
+	nsess->mutex = g_mutex_new();
+	if (!nsess->mutex)
 		goto out_mutex;
-	nsp->cond = g_cond_new();
-	if (!nsp->cond)
+	nsess->cond = g_cond_new();
+	if (!nsess->cond)
 		goto out_cond;
 
 	if (!host) {
-		err = ncld_getsrv(&nsp->host, &nsp->port);
+		err = ncld_getsrv(&nsess->host, &nsess->port);
 		if (err)
 			goto out_srv;
 	} else {
-		err = ncld_gethost(&nsp->host, &nsp->port, host, port);
+		err = ncld_gethost(&nsess->host, &nsess->port, host, port);
 		if (err)
 			goto out_srv;
 	}
 
-	nsp->event = ev_func;
-	nsp->event_arg = ev_arg;
+	nsess->event = ev_func;
+	nsess->event_arg = ev_arg;
 
-	if (pipe(nsp->to_thread) < 0) {
+	if (pipe(nsess->to_thread) < 0) {
 		err = errno;
 		goto out_pipe_to;
 	}
 
-	if (cldc_udp_new(nsp->host, nsp->port, &nsp->udp)) {
+	if (cldc_udp_new(nsess->host, nsess->port, &nsess->udp)) {
 		err = 1023;
 		goto out_udp;
 	}
 
-	nsp->thread = g_thread_create(ncld_sess_thr, nsp, TRUE, &gerr);
-	if (nsp->thread == NULL) {
+	nsess->thread = g_thread_create(ncld_sess_thr, nsess, TRUE, &gerr);
+	if (nsess->thread == NULL) {
 		err = 1022;
 		goto out_thread;
 	}
 
 	memset(&copts, 0, sizeof(copts));
 	copts.cb = ncld_new_sess;
-	copts.private = nsp;
-	if (cldc_new_sess(&ncld_ops, &copts, nsp->udp->addr, nsp->udp->addr_len,
-			  cld_user, cld_key, nsp, &nsp->udp->sess)) {
+	copts.private = nsess;
+	if (cldc_new_sess(&ncld_ops, &copts, nsess->udp->addr, nsess->udp->addr_len,
+			  cld_user, cld_key, nsess, &nsess->udp->sess)) {
 		err = 1024;
 		goto out_session;
 	}
 
-	/* nsp->udp->sess->log.verbose = 1; */
+	/* nsess->udp->sess->log.verbose = 1; */
 
-	rc = ncld_wait_session(nsp);
+	rc = ncld_wait_session(nsess);
 	if (rc) {
 		err = 1100 + rc % 1000;
 		goto out_start;
 	}
 
-	return nsp;
+	return nsess;
 
 out_start:
-	cldc_kill_sess(nsp->udp->sess);
+	cldc_kill_sess(nsess->udp->sess);
 out_session:
-	ncld_thr_end(nsp);
+	ncld_thr_end(nsess);
 out_thread:
-	cldc_udp_free(nsp->udp);
+	cldc_udp_free(nsess->udp);
 out_udp:
-	close(nsp->to_thread[0]);
-	close(nsp->to_thread[1]);
+	close(nsess->to_thread[0]);
+	close(nsess->to_thread[1]);
 out_pipe_to:
-	free(nsp->host);
+	free(nsess->host);
 out_srv:
-	g_cond_free(nsp->cond);
+	g_cond_free(nsess->cond);
 out_cond:
-	g_mutex_free(nsp->mutex);
+	g_mutex_free(nsess->mutex);
 out_mutex:
-	free(nsp);
+	free(nsess);
 out_sesalloc:
 	*error = err;
 	return NULL;
@@ -1645,23 +1645,23 @@ out_sesalloc:
 
 static int ncld_open_cb(struct cldc_call_opts *copts, enum cle_err_codes errc)
 {
-	struct ncld_fh *fhp = copts->private;
+	struct ncld_fh *fh = copts->private;
 
-	fhp->errc = errc;
-	fhp->is_open = true;
-	g_cond_broadcast(fhp->ses->cond);
+	fh->errc = errc;
+	fh->is_open = true;
+	g_cond_broadcast(fh->sess->cond);
 	return 0;
 }
 
-static int ncld_wait_open(struct ncld_fh *fhp)
+static int ncld_wait_open(struct ncld_fh *fh)
 {
-	struct ncld_sess *nsp = fhp->ses;
+	struct ncld_sess *nsess = fh->sess;
 
-	g_mutex_lock(nsp->mutex);
-	while (!fhp->is_open)
-		g_cond_wait(nsp->cond, nsp->mutex);
-	g_mutex_unlock(nsp->mutex);
-	return fhp->errc;
+	g_mutex_lock(nsess->mutex);
+	while (!fh->is_open)
+		g_cond_wait(nsess->cond, nsess->mutex);
+	g_mutex_unlock(nsess->mutex);
+	return fh->errc;
 }
 
 /*
@@ -1674,49 +1674,49 @@ static int ncld_wait_open(struct ncld_fh *fhp)
  *
  * On error, return NULL and set the error code (can be errno or our own code).
  */
-struct ncld_fh *ncld_open(struct ncld_sess *nsp, const char *fname,
+struct ncld_fh *ncld_open(struct ncld_sess *nsess, const char *fname,
 			  unsigned int mode, int *error, unsigned int events,
 			  void (*ev_func)(void *, unsigned int), void *ev_arg)
 {
-	struct ncld_fh *fhp;
+	struct ncld_fh *fh;
 	struct cldc_call_opts copts;
 	int err;
 	int rc;
 
 	err = EBUSY;
-	if (!nsp->is_up)
+	if (!nsess->is_up)
 		goto out_session;
 
 	err = ENOMEM;
-	fhp = malloc(sizeof(struct ncld_fh));
-	if (!fhp)
+	fh = malloc(sizeof(struct ncld_fh));
+	if (!fh)
 		goto out_alloc;
-	memset(fhp, 0, sizeof(struct ncld_fh));
-	fhp->ses = nsp;
-	fhp->event_mask = events;
-	fhp->event_func = ev_func;
-	fhp->event_arg = ev_arg;
+	memset(fh, 0, sizeof(struct ncld_fh));
+	fh->sess = nsess;
+	fh->event_mask = events;
+	fh->event_func = ev_func;
+	fh->event_arg = ev_arg;
 
-	g_mutex_lock(nsp->mutex);
+	g_mutex_lock(nsess->mutex);
 	memset(&copts, 0, sizeof(copts));
 	copts.cb = ncld_open_cb;
-	copts.private = fhp;
-	rc = cldc_open(nsp->udp->sess, &copts, fname, mode, events, &fhp->fh);
+	copts.private = fh;
+	rc = cldc_open(nsess->udp->sess, &copts, fname, mode, events, &fh->fh);
 	if (rc) {
 		err = -rc;
-		g_mutex_unlock(nsp->mutex);
+		g_mutex_unlock(nsess->mutex);
 		goto out_open;
 	}
-	g_mutex_unlock(nsp->mutex);
+	g_mutex_unlock(nsess->mutex);
 
-	rc = ncld_wait_open(fhp);
+	rc = ncld_wait_open(fh);
 	if (rc) {
 		err = 1100 + rc;
 		goto out_start;
 	}
 
-	nsp->handles = g_list_prepend(nsp->handles, fhp);
-	return fhp;
+	nsess->handles = g_list_prepend(nsess->handles, fh);
+	return fh;
 
 out_start:
 	/*
@@ -1726,7 +1726,7 @@ out_start:
 	 * garbage-collected if we're lucky).
 	 */
 out_open:
-	free(fhp);
+	free(fh);
 out_alloc:
 out_session:
 	*error = err;
@@ -1734,7 +1734,7 @@ out_session:
 }
 
 struct ncld_delio {
-	struct ncld_sess *ses;
+	struct ncld_sess *sess;
 	bool is_done;
 	int errc;
 };
@@ -1742,48 +1742,48 @@ struct ncld_delio {
 static int ncld_del_cb(struct cldc_call_opts *copts, enum cle_err_codes errc)
 {
 	struct ncld_delio *dp = copts->private;
-	struct ncld_sess *nsp = dp->ses;
+	struct ncld_sess *nsess = dp->sess;
 
 	dp->errc = errc;
 	dp->is_done = true;
-	g_cond_broadcast(nsp->cond);
+	g_cond_broadcast(nsess->cond);
 	return 0;
 }
 
 static int ncld_wait_del(struct ncld_delio *dp)
 {
-	struct ncld_sess *nsp = dp->ses;
+	struct ncld_sess *nsess = dp->sess;
 
-	g_mutex_lock(nsp->mutex);
+	g_mutex_lock(nsess->mutex);
 	while (!dp->is_done)
-		g_cond_wait(nsp->cond, nsp->mutex);
-	g_mutex_unlock(nsp->mutex);
+		g_cond_wait(nsess->cond, nsess->mutex);
+	g_mutex_unlock(nsess->mutex);
 	return dp->errc;
 }
 
-int ncld_del(struct ncld_sess *nsp, const char *fname)
+int ncld_del(struct ncld_sess *nsess, const char *fname)
 {
 	struct cldc_call_opts copts;
 	struct ncld_delio dpb;
 	int rc;
 
-	if (!nsp->is_up)
+	if (!nsess->is_up)
 		return -EBUSY;
 
 	memset(&dpb, 0, sizeof(struct ncld_delio));
-	dpb.ses = nsp;
+	dpb.sess = nsess;
 
-	g_mutex_lock(nsp->mutex);
+	g_mutex_lock(nsess->mutex);
 	memset(&copts, 0, sizeof(copts));
 	copts.cb = ncld_del_cb;
 	copts.private = &dpb;
-	rc = cldc_del(nsp->udp->sess, &copts, fname);
+	rc = cldc_del(nsess->udp->sess, &copts, fname);
 	if (rc) {
-		g_mutex_unlock(nsp->mutex);
+		g_mutex_unlock(nsess->mutex);
 		return -rc;
 	}
 	/* XXX A delete operation is not accounted for end-session */
-	g_mutex_unlock(nsp->mutex);
+	g_mutex_unlock(nsess->mutex);
 
 	rc = ncld_wait_del(&dpb);
 	if (rc)
@@ -1795,7 +1795,7 @@ int ncld_del(struct ncld_sess *nsp, const char *fname)
 static int ncld_read_cb(struct cldc_call_opts *copts, enum cle_err_codes errc)
 {
 	struct ncld_read *rp = copts->private;
-	struct ncld_fh *fhp = rp->fh;
+	struct ncld_fh *fh = rp->fh;
 
 	if (errc) {
 		rp->errc = errc;
@@ -1809,20 +1809,20 @@ static int ncld_read_cb(struct cldc_call_opts *copts, enum cle_err_codes errc)
 		rp->length = l;
 	}
 	rp->is_done = true;
-	g_cond_broadcast(fhp->ses->cond);
+	g_cond_broadcast(fh->sess->cond);
 	return 0;
 }
 
 static int ncld_wait_read(struct ncld_read *rp)
 {
-	struct ncld_fh *fhp = rp->fh;
-	struct ncld_sess *nsp = fhp->ses;
+	struct ncld_fh *fh = rp->fh;
+	struct ncld_sess *nsess = fh->sess;
 
-	g_mutex_lock(nsp->mutex);
+	g_mutex_lock(nsess->mutex);
 	while (!rp->is_done)
-		g_cond_wait(nsp->cond, nsp->mutex);
-	--fhp->nios;
-	g_mutex_unlock(nsp->mutex);
+		g_cond_wait(nsess->cond, nsess->mutex);
+	--fh->nios;
+	g_mutex_unlock(nsess->mutex);
 	return rp->errc;
 }
 
@@ -1830,14 +1830,14 @@ static int ncld_wait_read(struct ncld_read *rp)
  * @error Error code buffer.
  * @return Pointer to struct ncld_read or NULL if error.
  */
-struct ncld_read *ncld_get(struct ncld_fh *fhp, int *error)
+struct ncld_read *ncld_get(struct ncld_fh *fh, int *error)
 {
-	struct ncld_sess *nsp = fhp->ses;
+	struct ncld_sess *nsess = fh->sess;
 	struct ncld_read *rp;
 	struct cldc_call_opts copts;
 	int rc;
 
-	if (!fhp->is_open) {
+	if (!fh->is_open) {
 		*error = EBUSY;
 		return NULL;
 	}
@@ -1848,21 +1848,21 @@ struct ncld_read *ncld_get(struct ncld_fh *fhp, int *error)
 		return NULL;
 	}
 	memset(rp, 0, sizeof(struct ncld_read));
-	rp->fh = fhp;
+	rp->fh = fh;
 
-	g_mutex_lock(nsp->mutex);
+	g_mutex_lock(nsess->mutex);
 	memset(&copts, 0, sizeof(copts));
 	copts.cb = ncld_read_cb;
 	copts.private = rp;
-	rc = cldc_get(fhp->fh, &copts, false);
+	rc = cldc_get(fh->fh, &copts, false);
 	if (rc) {
-		g_mutex_unlock(nsp->mutex);
+		g_mutex_unlock(nsess->mutex);
 		free(rp);
 		*error = -rc;
 		return NULL;
 	}
-	fhp->nios++;
-	g_mutex_unlock(nsp->mutex);
+	fh->nios++;
+	g_mutex_unlock(nsess->mutex);
 
 	rc = ncld_wait_read(rp);
 	if (rc) {
@@ -1887,7 +1887,7 @@ static int ncld_read_meta_cb(struct cldc_call_opts *copts, enum cle_err_codes er
 		rp->length = 0;
 	}
 	rp->is_done = true;
-	g_cond_broadcast(fh->ses->cond);
+	g_cond_broadcast(fh->sess->cond);
 	return 0;
 }
 
@@ -1897,7 +1897,7 @@ static int ncld_read_meta_cb(struct cldc_call_opts *copts, enum cle_err_codes er
  */
 struct ncld_read *ncld_get_meta(struct ncld_fh *fh, int *error)
 {
-	struct ncld_sess *nsp = fh->ses;
+	struct ncld_sess *nsess = fh->sess;
 	struct ncld_read *rp;
 	struct cldc_call_opts copts;
 	int rc;
@@ -1915,19 +1915,19 @@ struct ncld_read *ncld_get_meta(struct ncld_fh *fh, int *error)
 	memset(rp, 0, sizeof(struct ncld_read));
 	rp->fh = fh;
 
-	g_mutex_lock(nsp->mutex);
+	g_mutex_lock(nsess->mutex);
 	memset(&copts, 0, sizeof(copts));
 	copts.cb = ncld_read_meta_cb;
 	copts.private = rp;
 	rc = cldc_get(fh->fh, &copts, true);
 	if (rc) {
-		g_mutex_unlock(nsp->mutex);
+		g_mutex_unlock(nsess->mutex);
 		free(rp);
 		*error = -rc;
 		return NULL;
 	}
 	fh->nios++;
-	g_mutex_unlock(nsp->mutex);
+	g_mutex_unlock(nsess->mutex);
 
 	rc = ncld_wait_read(rp);
 	if (rc) {
@@ -1963,54 +1963,54 @@ struct ncld_genio {
 static int ncld_genio_cb(struct cldc_call_opts *copts, enum cle_err_codes errc)
 {
 	struct ncld_genio *ap = copts->private;
-	struct ncld_fh *fhp = ap->fh;
+	struct ncld_fh *fh = ap->fh;
 
 	ap->errc = errc;
 	ap->is_done = true;
-	g_cond_broadcast(fhp->ses->cond);
+	g_cond_broadcast(fh->sess->cond);
 	return 0;
 }
 
 static int ncld_wait_genio(struct ncld_genio *ap)
 {
-	struct ncld_fh *fhp = ap->fh;
-	struct ncld_sess *nsp = fhp->ses;
+	struct ncld_fh *fh = ap->fh;
+	struct ncld_sess *nsess = fh->sess;
 
-	g_mutex_lock(nsp->mutex);
+	g_mutex_lock(nsess->mutex);
 	while (!ap->is_done)
-		g_cond_wait(nsp->cond, nsp->mutex);
-	--fhp->nios;
-	g_mutex_unlock(nsp->mutex);
+		g_cond_wait(nsess->cond, nsess->mutex);
+	--fh->nios;
+	g_mutex_unlock(nsess->mutex);
 	return ap->errc;
 }
 
 /*
  * @return: Zero or error code.
  */
-int ncld_write(struct ncld_fh *fhp, const void *data, long len)
+int ncld_write(struct ncld_fh *fh, const void *data, long len)
 {
-	struct ncld_sess *nsp = fhp->ses;
+	struct ncld_sess *nsess = fh->sess;
 	struct cldc_call_opts copts;
 	struct ncld_genio apb;
 	int rc;
 
-	if (!fhp->is_open)
+	if (!fh->is_open)
 		return -EBUSY;
 
 	memset(&apb, 0, sizeof(struct ncld_genio));
-	apb.fh = fhp;
+	apb.fh = fh;
 
-	g_mutex_lock(nsp->mutex);
+	g_mutex_lock(nsess->mutex);
 	memset(&copts, 0, sizeof(copts));
 	copts.cb = ncld_genio_cb;
 	copts.private = &apb;
-	rc = cldc_put(fhp->fh, &copts, data, len);
+	rc = cldc_put(fh->fh, &copts, data, len);
 	if (rc) {
-		g_mutex_unlock(nsp->mutex);
+		g_mutex_unlock(nsess->mutex);
 		return -rc;
 	}
-	fhp->nios++;
-	g_mutex_unlock(nsp->mutex);
+	fh->nios++;
+	g_mutex_unlock(nsess->mutex);
 
 	rc = ncld_wait_genio(&apb);
 	if (rc)
@@ -2019,30 +2019,30 @@ int ncld_write(struct ncld_fh *fhp, const void *data, long len)
 	return 0;
 }
 
-int ncld_trylock(struct ncld_fh *fhp)
+int ncld_trylock(struct ncld_fh *fh)
 {
-	struct ncld_sess *nsp = fhp->ses;
+	struct ncld_sess *nsess = fh->sess;
 	struct cldc_call_opts copts;
 	struct ncld_genio apb;
 	int rc;
 
-	if (!fhp->is_open)
+	if (!fh->is_open)
 		return -EBUSY;
 
 	memset(&apb, 0, sizeof(struct ncld_genio));
-	apb.fh = fhp;
+	apb.fh = fh;
 
-	g_mutex_lock(nsp->mutex);
+	g_mutex_lock(nsess->mutex);
 	memset(&copts, 0, sizeof(copts));
 	copts.cb = ncld_genio_cb;
 	copts.private = &apb;
-	rc = cldc_lock(fhp->fh, &copts, 0, false);
+	rc = cldc_lock(fh->fh, &copts, 0, false);
 	if (rc) {
-		g_mutex_unlock(nsp->mutex);
+		g_mutex_unlock(nsess->mutex);
 		return -rc;
 	}
-	fhp->nios++;
-	g_mutex_unlock(nsp->mutex);
+	fh->nios++;
+	g_mutex_unlock(nsess->mutex);
 
 	rc = ncld_wait_genio(&apb);
 	if (rc)
@@ -2051,30 +2051,30 @@ int ncld_trylock(struct ncld_fh *fhp)
 	return 0;
 }
 
-int ncld_unlock(struct ncld_fh *fhp)
+int ncld_unlock(struct ncld_fh *fh)
 {
-	struct ncld_sess *nsp = fhp->ses;
+	struct ncld_sess *nsess = fh->sess;
 	struct cldc_call_opts copts;
 	struct ncld_genio apb;
 	int rc;
 
-	if (!fhp->is_open)
+	if (!fh->is_open)
 		return -EBUSY;
 
 	memset(&apb, 0, sizeof(struct ncld_genio));
-	apb.fh = fhp;
+	apb.fh = fh;
 
-	g_mutex_lock(nsp->mutex);
+	g_mutex_lock(nsess->mutex);
 	memset(&copts, 0, sizeof(copts));
 	copts.cb = ncld_genio_cb;
 	copts.private = &apb;
-	rc = cldc_unlock(fhp->fh, &copts);
+	rc = cldc_unlock(fh->fh, &copts);
 	if (rc) {
-		g_mutex_unlock(nsp->mutex);
+		g_mutex_unlock(nsess->mutex);
 		return -rc;
 	}
-	fhp->nios++;
-	g_mutex_unlock(nsp->mutex);
+	fh->nios++;
+	g_mutex_unlock(nsess->mutex);
 
 	rc = ncld_wait_genio(&apb);
 	if (rc)
@@ -2090,30 +2090,30 @@ int ncld_unlock(struct ncld_fh *fhp)
  * Applications using this supply a callback and a mask to ncld_open.
  * FIXME: This does not work at present, since server does not post them.
  */
-int ncld_qlock(struct ncld_fh *fhp)
+int ncld_qlock(struct ncld_fh *fh)
 {
-	struct ncld_sess *nsp = fhp->ses;
+	struct ncld_sess *nsess = fh->sess;
 	struct cldc_call_opts copts;
 	struct ncld_genio apb;
 	int rc;
 
-	if (!fhp->is_open)
+	if (!fh->is_open)
 		return -EBUSY;
 
 	memset(&apb, 0, sizeof(struct ncld_genio));
-	apb.fh = fhp;
+	apb.fh = fh;
 
-	g_mutex_lock(nsp->mutex);
+	g_mutex_lock(nsess->mutex);
 	memset(&copts, 0, sizeof(copts));
 	copts.cb = ncld_genio_cb;
 	copts.private = &apb;
-	rc = cldc_lock(fhp->fh, &copts, 0, true);
+	rc = cldc_lock(fh->fh, &copts, 0, true);
 	if (rc) {
-		g_mutex_unlock(nsp->mutex);
+		g_mutex_unlock(nsess->mutex);
 		return -rc;
 	}
-	fhp->nios++;
-	g_mutex_unlock(nsp->mutex);
+	fh->nios++;
+	g_mutex_unlock(nsess->mutex);
 
 	rc = ncld_wait_genio(&apb);
 	if (rc) {
@@ -2126,11 +2126,11 @@ int ncld_qlock(struct ncld_fh *fhp)
 
 static int ncld_close_cb(struct cldc_call_opts *copts, enum cle_err_codes errc)
 {
-	struct ncld_fh *fhp = copts->private;
+	struct ncld_fh *fh = copts->private;
 
-	fhp->errc = errc;
-	fhp->is_open = false;
-	g_cond_broadcast(fhp->ses->cond);
+	fh->errc = errc;
+	fh->is_open = false;
+	g_cond_broadcast(fh->sess->cond);
 	return 0;
 }
 
@@ -2140,28 +2140,28 @@ static int ncld_close_cb(struct cldc_call_opts *copts, enum cle_err_codes errc)
  * for us, because users keep pointers, not file descriptor numbers.
  * Applications should stop application I/O first, then close.
  */
-void ncld_close(struct ncld_fh *fhp)
+void ncld_close(struct ncld_fh *fh)
 {
-	struct ncld_sess *nsp = fhp->ses;
+	struct ncld_sess *nsess = fh->sess;
 	struct cldc_call_opts copts;
 	int rc;
 
-	if (!fhp->is_open)
+	if (!fh->is_open)
 		abort();
 
-	g_mutex_lock(nsp->mutex);
+	g_mutex_lock(nsess->mutex);
 	memset(&copts, 0, sizeof(copts));
 	copts.cb = ncld_close_cb;
-	copts.private = fhp;
-	rc = cldc_close(fhp->fh, &copts);
-	g_mutex_unlock(nsp->mutex);
+	copts.private = fh;
+	rc = cldc_close(fh->fh, &copts);
+	g_mutex_unlock(nsess->mutex);
 
 	if (rc == 0) {
-		g_mutex_lock(nsp->mutex);
-		while (fhp->is_open)
-			g_cond_wait(nsp->cond, nsp->mutex);
-		g_mutex_unlock(nsp->mutex);
-		/* At this point, we ignore fhp->errc. */
+		g_mutex_lock(nsess->mutex);
+		while (fh->is_open)
+			g_cond_wait(nsess->cond, nsess->mutex);
+		g_mutex_unlock(nsess->mutex);
+		/* At this point, we ignore fh->errc. */
 	}
 
 	/*
@@ -2171,13 +2171,13 @@ void ncld_close(struct ncld_fh *fhp)
 	 * N.B.: this is making use of the fact that we only have one
 	 * conditional per session, and therefore end-of-I/O pokes us here.
 	 */
-	g_mutex_lock(nsp->mutex);
-	while (fhp->nios)
-		g_cond_wait(nsp->cond, nsp->mutex);
-	g_mutex_unlock(nsp->mutex);
+	g_mutex_lock(nsess->mutex);
+	while (fh->nios)
+		g_cond_wait(nsess->cond, nsess->mutex);
+	g_mutex_unlock(nsess->mutex);
 
-	nsp->handles = g_list_remove_all(nsp->handles, fhp);
-	free(fhp);
+	nsess->handles = g_list_remove_all(nsess->handles, fh);
+	free(fh);
 }
 
 static void ncld_func_close(gpointer data, gpointer priv)
@@ -2185,20 +2185,20 @@ static void ncld_func_close(gpointer data, gpointer priv)
 	ncld_close(data);
 }
 
-void ncld_sess_close(struct ncld_sess *nsp)
+void ncld_sess_close(struct ncld_sess *nsess)
 {
-	g_list_foreach(nsp->handles, ncld_func_close, NULL);
-	g_list_free(nsp->handles);
+	g_list_foreach(nsess->handles, ncld_func_close, NULL);
+	g_list_free(nsess->handles);
 
-	cldc_kill_sess(nsp->udp->sess);
-	ncld_thr_end(nsp);
-	cldc_udp_free(nsp->udp);
-	close(nsp->to_thread[0]);
-	close(nsp->to_thread[1]);
-	g_cond_free(nsp->cond);
-	g_mutex_free(nsp->mutex);
-	free(nsp->host);
-	free(nsp);
+	cldc_kill_sess(nsess->udp->sess);
+	ncld_thr_end(nsess);
+	cldc_udp_free(nsess->udp);
+	close(nsess->to_thread[0]);
+	close(nsess->to_thread[1]);
+	g_cond_free(nsess->cond);
+	g_mutex_free(nsess->mutex);
+	free(nsess->host);
+	free(nsess);
 }
 
 void ncld_init(void)
diff --git a/test/basic-io.c b/test/basic-io.c
index 2565280..31bfcab 100644
--- a/test/basic-io.c
+++ b/test/basic-io.c
@@ -35,59 +35,59 @@
 
 static int test_write(int port)
 {
-	struct ncld_sess *nsp;
-	struct ncld_fh *fhp;
+	struct ncld_sess *nsess;
+	struct ncld_fh *fh;
 	int error;
 
-	nsp = ncld_sess_open(TEST_HOST, port, &error, NULL, NULL,
+	nsess = ncld_sess_open(TEST_HOST, port, &error, NULL, NULL,
 			     TEST_USER, TEST_USER_KEY);
-	if (!nsp) {
+	if (!nsess) {
 		fprintf(stderr, "ncld_sess_open(host %s port %u) failed: %d\n",
 			TEST_HOST, port, error);
 		exit(1);
 	}
 
-	fhp = ncld_open(nsp, TFNAME, COM_WRITE | COM_CREATE,
+	fh = ncld_open(nsess, TFNAME, COM_WRITE | COM_CREATE,
 			&error, 0, NULL, NULL);
-	if (!fhp) {
+	if (!fh) {
 		fprintf(stderr, "ncld_open(%s) failed: %d\n", TFNAME, error);
 		exit(1);
 	}
 
-	error = ncld_write(fhp, TESTSTR, TESTLEN);
+	error = ncld_write(fh, TESTSTR, TESTLEN);
 	if (error) {
 		fprintf(stderr, "ncld_write failed: %d\n", error);
 		exit(1);
 	}
 
 	/* These two are perfect places to hang or crash, so don't just exit. */
-	ncld_close(fhp);
-	ncld_sess_close(nsp);
+	ncld_close(fh);
+	ncld_sess_close(nsess);
 	return 0;
 }
 
 static int test_read(int port)
 {
-	struct ncld_sess *nsp;
-	struct ncld_fh *fhp;
+	struct ncld_sess *nsess;
+	struct ncld_fh *fh;
 	struct ncld_read *rp;
 	int error;
 
-	nsp = ncld_sess_open(TEST_HOST, port, &error, NULL, NULL,
+	nsess = ncld_sess_open(TEST_HOST, port, &error, NULL, NULL,
 			     TEST_USER, TEST_USER_KEY);
-	if (!nsp) {
+	if (!nsess) {
 		fprintf(stderr, "ncld_sess_open(host %s port %u) failed: %d\n",
 			TEST_HOST, port, error);
 		exit(1);
 	}
 
-	fhp = ncld_open(nsp, TFNAME, COM_READ, &error, 0, NULL, NULL);
-	if (!fhp) {
+	fh = ncld_open(nsess, TFNAME, COM_READ, &error, 0, NULL, NULL);
+	if (!fh) {
 		fprintf(stderr, "ncld_open(%s) failed: %d\n", TFNAME, error);
 		exit(1);
 	}
 
-	rp = ncld_get(fhp, &error);
+	rp = ncld_get(fh, &error);
 	if (!rp) {
 		fprintf(stderr, "ncld_get failed: %d\n", error);
 		exit(1);
@@ -106,8 +106,8 @@ static int test_read(int port)
 	ncld_read_free(rp);
 
 	/* These two are perfect places to hang or crash, so don't just exit. */
-	ncld_close(fhp);
-	ncld_sess_close(nsp);
+	ncld_close(fh);
+	ncld_sess_close(nsess);
 	return 0;
 }
 
diff --git a/test/basic-session.c b/test/basic-session.c
index d8f9ec1..6caf046 100644
--- a/test/basic-session.c
+++ b/test/basic-session.c
@@ -31,7 +31,7 @@
 
 int main (int argc, char *argv[])
 {
-	struct ncld_sess *nsp;
+	struct ncld_sess *nsess;
 	int error;
 	int port;
 
@@ -44,15 +44,15 @@ int main (int argc, char *argv[])
 	if (port == 0)
 		return -1;
 
-	nsp = ncld_sess_open(TEST_HOST, port, &error, NULL, NULL,
+	nsess = ncld_sess_open(TEST_HOST, port, &error, NULL, NULL,
 			     TEST_USER, TEST_USER_KEY);
-	if (!nsp) {
+	if (!nsess) {
 		fprintf(stderr, "ncld_sess_open(host %s port %u) failed: %d\n",
 			TEST_HOST, port, error);
 		exit(1);
 	}
 
-	ncld_sess_close(nsp);
+	ncld_sess_close(nsess);
 	return 0;
 }
 
diff --git a/test/lock-file.c b/test/lock-file.c
index 64e6020..d0ea9c1 100644
--- a/test/lock-file.c
+++ b/test/lock-file.c
@@ -33,8 +33,8 @@
 
 int main (int argc, char *argv[])
 {
-	struct ncld_sess *nsp;
-	struct ncld_fh *fhp;
+	struct ncld_sess *nsess;
+	struct ncld_fh *fh;
 	int port;
 	struct timespec tm;
 	int error;
@@ -49,28 +49,28 @@ int main (int argc, char *argv[])
 	if (port == 0)
 		return -1;
 
-	nsp = ncld_sess_open(TEST_HOST, port, &error, NULL, NULL,
+	nsess = ncld_sess_open(TEST_HOST, port, &error, NULL, NULL,
 			     TEST_USER, TEST_USER_KEY);
-	if (!nsp) {
+	if (!nsess) {
 		fprintf(stderr, "ncld_sess_open(host %s port %u) failed: %d\n",
 			TEST_HOST, port, error);
 		exit(1);
 	}
 
-	fhp = ncld_open(nsp, TLNAME, COM_WRITE | COM_LOCK | COM_CREATE,
+	fh = ncld_open(nsess, TLNAME, COM_WRITE | COM_LOCK | COM_CREATE,
 			&error, 0, NULL, NULL);
-	if (!fhp) {
+	if (!fh) {
 		fprintf(stderr, "ncld_open(%s) failed: %d\n", TLNAME, error);
 		exit(1);
 	}
 
-	rc = ncld_write(fhp, LOCKSTR, LOCKLEN);
+	rc = ncld_write(fh, LOCKSTR, LOCKLEN);
 	if (rc) {
 		fprintf(stderr, "ncld_write failed: %d\n", rc);
 		exit(1);
 	}
 
-	rc = ncld_trylock(fhp);
+	rc = ncld_trylock(fh);
 	if (rc) {
 		fprintf(stderr, "ncld_trylock failed: %d\n", rc);
 		exit(1);
@@ -82,15 +82,15 @@ int main (int argc, char *argv[])
 	tm.tv_nsec = 0;
 	nanosleep(&tm, NULL);
 
-	rc = ncld_unlock(fhp);
+	rc = ncld_unlock(fh);
 	if (rc) {
 		fprintf(stderr, "ncld_unlock failed: %d\n", rc);
 		exit(1);
 	}
 
 	/* These two are perfect places to hang or crash, so don't just exit. */
-	ncld_close(fhp);
-	ncld_sess_close(nsp);
+	ncld_close(fh);
+	ncld_sess_close(nsess);
 	return 0;
 }
 
diff --git a/tools/cldcli.c b/tools/cldcli.c
index 85a7ef8..2a2c82b 100644
--- a/tools/cldcli.c
+++ b/tools/cldcli.c
@@ -77,7 +77,7 @@ static char clicwd[CLD_PATH_MAX + 1] = "/";
 static char our_user[CLD_MAX_USERNAME + 1] = "cli_user";
 
 /* globals only for use in thread */
-static struct ncld_sess *nsp;
+static struct ncld_sess *nsess;
 static GList *thr_lock_list;
 static uint64_t thr_lock_id = 2;
 
@@ -134,7 +134,7 @@ static bool make_abs_path(char *dest, size_t dest_len, const char *src)
 static void cmd_cd(const char *arg)
 {
 	struct creq creq = { 0, };
-	struct ncld_fh *fhp;
+	struct ncld_fh *fh;
 	int error;
 
 	if (!*arg)
@@ -145,8 +145,8 @@ static void cmd_cd(const char *arg)
 		return;
 	}
 
-	fhp = ncld_open(nsp, creq.path, COM_DIRECTORY, &error, 0, NULL, NULL);
-	if (!fhp) {
+	fh = ncld_open(nsess, creq.path, COM_DIRECTORY, &error, 0, NULL, NULL);
+	if (!fh) {
 		if (error < 1000) {
 			fprintf(stderr, TAG ": cannot open path `%s': %s\n",
 				creq.path, strerror(error));
@@ -156,7 +156,7 @@ static void cmd_cd(const char *arg)
 		}
 		return;
 	}
-	ncld_close(fhp);
+	ncld_close(fh);
 
 	strcpy(clicwd, creq.path);
 }
@@ -164,7 +164,7 @@ static void cmd_cd(const char *arg)
 static void cmd_ls(const char *arg)
 {
 	struct creq creq = { 0, };
-	struct ncld_fh *fhp;
+	struct ncld_fh *fh;
 	struct ncld_read *rp;
 	const char *data;
 	size_t data_len;
@@ -183,9 +183,9 @@ static void cmd_ls(const char *arg)
 		return;
 	}
 
-	fhp = ncld_open(nsp, creq.path, COM_DIRECTORY | COM_READ, &error,
+	fh = ncld_open(nsess, creq.path, COM_DIRECTORY | COM_READ, &error,
 			0, NULL, NULL);
-	if (!fhp) {
+	if (!fh) {
 		if (error < 1000) {
 			fprintf(stderr, TAG ": cannot open path `%s': %s\n",
 				creq.path, strerror(error));
@@ -196,7 +196,7 @@ static void cmd_ls(const char *arg)
 		return;
 	}
 
-	rp = ncld_get(fhp, &error);
+	rp = ncld_get(fh, &error);
 	if (!rp) {
 		if (error < 1000) {
 			fprintf(stderr, TAG ": cannot get on path `%s': %s\n",
@@ -205,7 +205,7 @@ static void cmd_ls(const char *arg)
 			fprintf(stderr, TAG ": cannot get on path `%s': %d\n",
 				creq.path, error);
 		}
-		ncld_close(fhp);
+		ncld_close(fh);
 		return;
 	}
 
@@ -217,7 +217,7 @@ static void cmd_ls(const char *arg)
 		fprintf(stderr, TAG ": cldc_dirent_count failed on path `%s'\n",
 				creq.path);
 		ncld_read_free(rp);
-		ncld_close(fhp);
+		ncld_close(fh);
 		return;
 	}
 	n_records = rc;
@@ -246,13 +246,13 @@ static void cmd_ls(const char *arg)
 	cldc_dirent_cur_fini(&dc);
 
 	ncld_read_free(rp);
-	ncld_close(fhp);
+	ncld_close(fh);
 }
 
 static void cmd_cat(const char *arg)
 {
 	struct creq creq = { 0, };
-	struct ncld_fh *fhp;
+	struct ncld_fh *fh;
 	struct ncld_read *rp;
 	int error;
 
@@ -266,8 +266,8 @@ static void cmd_cat(const char *arg)
 		return;
 	}
 
-	fhp = ncld_open(nsp, creq.path, COM_READ, &error, 0, NULL, NULL);
-	if (!fhp) {
+	fh = ncld_open(nsess, creq.path, COM_READ, &error, 0, NULL, NULL);
+	if (!fh) {
 		if (error < 1000) {
 			fprintf(stderr, TAG ": cannot open path `%s': %s\n",
 				creq.path, strerror(error));
@@ -278,11 +278,11 @@ static void cmd_cat(const char *arg)
 		return;
 	}
 
-	rp = ncld_get(fhp, &error);
+	rp = ncld_get(fh, &error);
 	if (!rp) {
 		fprintf(stderr, TAG ": cannot read from path `%s': %d\n",
 			creq.path, error);
-		ncld_close(fhp);
+		ncld_close(fh);
 		return;
 	}
 
@@ -290,7 +290,7 @@ static void cmd_cat(const char *arg)
 	fprintf(stdout, "\n");
 
 	ncld_read_free(rp);
-	ncld_close(fhp);
+	ncld_close(fh);
 }
 
 static void cmd_list_locks(void)
@@ -311,7 +311,7 @@ static void cmd_list_locks(void)
 static void cmd_cpin(const char *cmd, const char *arg)
 {
 	struct creq creq;
-	struct ncld_fh *fhp;
+	struct ncld_fh *fh;
 	gchar **sv = NULL, *cld_path, *fs_path;
 	gchar *fs_content = NULL;
 	gsize fs_len = 0;
@@ -345,22 +345,22 @@ static void cmd_cpin(const char *cmd, const char *arg)
 		goto out;
 	}
 
-	fhp = ncld_open(nsp, creq.path, COM_CREATE | COM_WRITE,
+	fh = ncld_open(nsess, creq.path, COM_CREATE | COM_WRITE,
 			&error, 0, NULL, NULL);
-	if (!fhp) {
+	if (!fh) {
 		fprintf(stderr, TAG ": %s: cannot open: %d\n", creq.path, error);
 		goto out;
 	}
 
-	rc = ncld_write(fhp, fs_content, fs_len);
+	rc = ncld_write(fh, fs_content, fs_len);
 	if (rc) {
 		fprintf(stderr, TAG ": %s(%s -> %s) failed: %d\n",
 			cmd, sv[0], sv[1], rc);
-		ncld_close(fhp);
+		ncld_close(fh);
 		goto out;
 	}
 
-	ncld_close(fhp);
+	ncld_close(fh);
 
 out:
 	g_strfreev(sv);
@@ -370,7 +370,7 @@ out:
 static void cmd_cpout(const char *cmd, const char *arg)
 {
 	struct creq creq;
-	struct ncld_fh *fhp;
+	struct ncld_fh *fh;
 	struct ncld_read *rp;
 	gchar **sv = NULL, *cld_path, *fs_path;
 	int error;
@@ -396,16 +396,16 @@ static void cmd_cpout(const char *cmd, const char *arg)
 		goto out;
 	}
 
-	fhp = ncld_open(nsp, creq.path, COM_READ, &error, 0, NULL, NULL);
-	if (!fhp) {
+	fh = ncld_open(nsess, creq.path, COM_READ, &error, 0, NULL, NULL);
+	if (!fh) {
 		fprintf(stderr, TAG ": %s: cannot open: %d\n", creq.path, error);
 		goto out;
 	}
-	rp = ncld_get(fhp, &error);
+	rp = ncld_get(fh, &error);
 	if (!rp) {
 		fprintf(stderr, TAG ": cannot read from path `%s': %d\n",
 			creq.path, error);
-		ncld_close(fhp);
+		ncld_close(fh);
 		goto out;
 	}
 
@@ -416,7 +416,7 @@ static void cmd_cpout(const char *cmd, const char *arg)
 	}
 
 	ncld_read_free(rp);
-	ncld_close(fhp);
+	ncld_close(fh);
 
 out:
 	g_strfreev(sv);
@@ -425,7 +425,7 @@ out:
 static void cmd_lock(const char *cmd, const char *arg, bool wait_for_lock)
 {
 	struct creq creq = { 0, };
-	struct ncld_fh *fhp;
+	struct ncld_fh *fh;
 	struct cldcli_lock_info *li;
 	int error;
 	int rc;
@@ -450,22 +450,22 @@ static void cmd_lock(const char *cmd, const char *arg, bool wait_for_lock)
 	li->id = thr_lock_id++;
 	strncpy(li->path, creq.path, CLD_PATH_MAX);
 
-	fhp = ncld_open(nsp, creq.path, COM_LOCK, &error, 0, NULL, NULL);
-	if (!fhp) {
+	fh = ncld_open(nsess, creq.path, COM_LOCK, &error, 0, NULL, NULL);
+	if (!fh) {
 		fprintf(stderr, TAG ": %s: cannot open: %d\n", creq.path, error);
 		free(li);
 		return;
 	}
-	li->fh = fhp;
+	li->fh = fh;
 
 	if (wait_for_lock)
-		rc = ncld_qlock(fhp);
+		rc = ncld_qlock(fh);
 	else
-		rc = ncld_trylock(fhp);
+		rc = ncld_trylock(fh);
 
 	if (rc < 0) {
 		fprintf(stderr, TAG ": %s: cannot lock: %d\n", creq.path, error);
-		ncld_close(fhp);
+		ncld_close(fh);
 		free(li);
 		return;
 	}
@@ -479,7 +479,7 @@ static void cmd_lock(const char *cmd, const char *arg, bool wait_for_lock)
 static void basic_cmd(const char *cmd, const char *arg, enum creq_cmd cmd_no)
 {
 	struct creq creq = { 0, };
-	struct ncld_fh *fhp;
+	struct ncld_fh *fh;
 	int error;
 	int rc;
 
@@ -495,15 +495,15 @@ static void basic_cmd(const char *cmd, const char *arg, enum creq_cmd cmd_no)
 
 	switch (cmd_no) {
 	case CREQ_RM:
-		rc = ncld_del(nsp, creq.path);
+		rc = ncld_del(nsess, creq.path);
 		break;
 	case CREQ_MKDIR:
 		rc = 0;
-		fhp = ncld_open(nsp, creq.path,
+		fh = ncld_open(nsess, creq.path,
 				COM_DIRECTORY | COM_CREATE | COM_EXCL, &error,
 				0, NULL, NULL);
-		if (fhp)
-			ncld_close(fhp);
+		if (fh)
+			ncld_close(fh);
 		else
 			rc = error;
 		break;
@@ -710,9 +710,9 @@ int main (int argc, char *argv[])
 	fflush(stdout);
 	dr = host_list->data;
 
-	nsp = ncld_sess_open(dr->host, dr->port, &error, sess_event, NULL,
+	nsess = ncld_sess_open(dr->host, dr->port, &error, sess_event, NULL,
 			     "cldcli", "cldcli");
-	if (!nsp) {
+	if (!nsess) {
 		if (error < 1000) {
 			fprintf(stderr, TAG ": cannot open CLD session: %s\n",
 				strerror(error));
@@ -796,7 +796,7 @@ int main (int argc, char *argv[])
 		prompt();
 	}
 
-	ncld_sess_close(nsp);
+	ncld_sess_close(nsess);
 	return 0;
 }
 

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [Patch 1/1] CLD: Introduce the "New CLD" API
  2010-02-18  1:18     ` Jeff Garzik
@ 2010-02-19  1:35       ` Pete Zaitcev
  2010-02-19  2:41         ` Jeff Garzik
  0 siblings, 1 reply; 17+ messages in thread
From: Pete Zaitcev @ 2010-02-19  1:35 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: Project Hail List

On Wed, 17 Feb 2010 20:18:52 -0500
Jeff Garzik <jeff@garzik.org> wrote:

> >> A point of style:  the 'p' suffix is discouraged.
> >
> > I'll batch-rename it when I get better.

> Since it sounds like there will be no conflicting patches, I went ahead 
> and fixed things up myself, using my trusty sar (search-and-replace) 
> script.  I find sar quite useful, because it (a) matches and replaces on 
> word boundaries, and (b) it performs in-situ updates, unlike most other 
> Unix tools.

I imagine the numbers of '>>>>>>' clauses I have to fix after the
next "git pull". Oh well.

-- Pete

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Patch 1/1] CLD: Introduce the "New CLD" API
  2010-02-19  1:35       ` Pete Zaitcev
@ 2010-02-19  2:41         ` Jeff Garzik
  2010-02-19 22:23           ` Pete Zaitcev
  0 siblings, 1 reply; 17+ messages in thread
From: Jeff Garzik @ 2010-02-19  2:41 UTC (permalink / raw)
  To: Pete Zaitcev; +Cc: Project Hail List

On 02/18/2010 08:35 PM, Pete Zaitcev wrote:
> On Wed, 17 Feb 2010 20:18:52 -0500
> Jeff Garzik<jeff@garzik.org>  wrote:
>
>>>> A point of style:  the 'p' suffix is discouraged.
>>>
>>> I'll batch-rename it when I get better.
>
>> Since it sounds like there will be no conflicting patches, I went ahead
>> and fixed things up myself, using my trusty sar (search-and-replace)
>> script.  I find sar quite useful, because it (a) matches and replaces on
>> word boundaries, and (b) it performs in-situ updates, unlike most other
>> Unix tools.
>
> I imagine the numbers of '>>>>>>' clauses I have to fix after the
> next "git pull". Oh well.

If you perform the substitutions on your local working tree using the 
sar script, the diff between git HEAD and your local working tree should 
provide something manageable.

That's how to I split up Colin's XDR patch into multiple patches... 
repeatedly diff between HEAD and XDR-everything trees, apply a subset of 
the total diff, a single logical change. lather rinse repeat.

	Jeff



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Patch 1/1] CLD: Introduce the "New CLD" API
  2010-02-19  2:41         ` Jeff Garzik
@ 2010-02-19 22:23           ` Pete Zaitcev
  0 siblings, 0 replies; 17+ messages in thread
From: Pete Zaitcev @ 2010-02-19 22:23 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: Project Hail List

On Thu, 18 Feb 2010 21:41:35 -0500
Jeff Garzik <jeff@garzik.org> wrote:

> > I imagine the numbers of '>>>>>>' clauses I have to fix after the
> > next "git pull". Oh well.
> 
> If you perform the substitutions on your local working tree using the 
> sar script, the diff between git HEAD and your local working tree should 
> provide something manageable.

Yep, I paniced too early. One :%s/\<nsp\>/nsess/g was sufficient.

-- Pete

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2010-02-19 22:23 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-02-07 19:15 [Patch 1/1] CLD: Introduce the "New CLD" API Pete Zaitcev
2010-02-07 22:26 ` Jeff Garzik
2010-02-08 12:32 ` Jeff Garzik
2010-02-09  0:30   ` Pete Zaitcev
2010-02-09  6:25     ` Jeff Garzik
2010-02-09  1:46   ` Pete Zaitcev
2010-02-09  2:06     ` Jeff Garzik
2010-02-09  2:17       ` Pete Zaitcev
2010-02-09  4:55         ` Jeff Garzik
2010-02-09  5:35           ` Pete Zaitcev
2010-02-09  6:03             ` Jeff Garzik
2010-02-14  0:52 ` Jeff Garzik
2010-02-18  0:05   ` Pete Zaitcev
2010-02-18  1:18     ` Jeff Garzik
2010-02-19  1:35       ` Pete Zaitcev
2010-02-19  2:41         ` Jeff Garzik
2010-02-19 22:23           ` Pete Zaitcev

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.