PERFORCE change 124747 for review

Fredrik Lindberg fli at FreeBSD.org
Sun Aug 5 11:59:30 PDT 2007


http://perforce.freebsd.org/chv.cgi?CH=124747

Change 124747 by fli at fli_nexus on 2007/08/05 18:58:30

	- Add support to manipulate the record database.  Allows add,
	  remove and list operations (root only).
	- Add support to view and flush the cache (root only).
	- Add support to view active interfaces (root only).
	- Follow name change (mdnsd_clipkg.h -> mdnsd_ipc.h).
	- Save client credentials aquired from socket.
	- Change how messages are read.  Read for as long as data
	  is available, also use length information encoded in message
	  to properly separate messages.

Affected files ...

.. //depot/projects/soc2007/fli-mdns_sd/mdnsd/clisrv.c#2 edit
.. //depot/projects/soc2007/fli-mdns_sd/mdnsd/clisrv.h#2 edit

Differences ...

==== //depot/projects/soc2007/fli-mdns_sd/mdnsd/clisrv.c#2 (text+ko) ====

@@ -34,13 +34,14 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
 #include "event.h"
 #include "clisrv.h"
 #include "mdnsd.h"
-#include "mdnsd_clipkg.h"
+#include "mdnsd_ipc.h"
 #include "log.h"
 #include "objalloc.h"
 #include "utf8.h"
@@ -52,13 +53,44 @@
 static int evh_cli(const struct event_io *, const ev_arg);
 
 static int cp_parse(struct cs_client *, char *, size_t, int);
-static int mtpf_query(struct cs_client *, struct cp_head *, char *, size_t);
+static int mtpf_query(struct cs_client *, struct mipc_head *, char *, size_t);
+static int mtpf_if_list(struct cs_client *, struct mipc_head *, char *,
+    size_t);
+static int mtpf_ident_list(struct cs_client *, struct mipc_head *, char *,
+    size_t);
+static int mtpf_ident_add(struct cs_client *, struct mipc_head *, char *,
+    size_t);
+static int mtpf_ident_del(struct cs_client *, struct mipc_head *, char *,
+    size_t);
+static int mtpf_name_add(struct cs_client *, struct mipc_head *, char *,
+    size_t);
+static int mtpf_name_del(struct cs_client *, struct mipc_head *, char *,
+    size_t);
+static int mtpf_name_list(struct cs_client *, struct mipc_head *, char *,
+    size_t);
+static int mtpf_res_add(struct cs_client *, struct mipc_head *, char *,
+    size_t);
+static int mtpf_res_del(struct cs_client *, struct mipc_head *, char *,
+    size_t);
+static int mtpf_res_list(struct cs_client *, struct mipc_head *, char *,
+    size_t);
+static int mtpf_cache_flush(struct cs_client *, struct mipc_head *, char *,
+    size_t);
+static int mtpf_cache_list(struct cs_client *, struct mipc_head *, char *f,
+    size_t);
 
 static void send_error(struct cs_client *, int, int);
 static void send_ack(struct cs_client *, int);
 
-static int queryadd(struct cs_client *, struct csc_query *, int, int, int);
-static int querydel(struct cs_client *, struct csc_query * , int);
+static int queryadd(struct cs_client *, struct csc_query *, unsigned int,
+    int, int);
+static int querydel(struct cs_client *, struct csc_query * , unsigned int);
+
+#define IPC_SETHDR(mih, id, type, len) \
+    (mih)->mih_ver = MIPC_VERSION; \
+    (mih)->mih_id = id; \
+    (mih)->mih_msgtype = type; \
+    (mih)->mih_msglen = len;
 
 /*
  * Open UNIX pipe socket to clients
@@ -205,11 +237,12 @@
 	TAILQ_INSERT_TAIL(&cs->cs_head, csc, csc_next);
 	csc->csc_sock = sock;
 	csc->csc_serv = cs;
+	csc->csc_suser = 0;
 	eva.ptr = csc;
 	csc->csc_evid = event_add(g->g_evl, EVENT_TYPE_IO, evh_cli, &eva,
 	    evh_clisetup_init, &eva);
 
-	dprintf(DEBUG_CS, "New UNIX pipe client csc=%x", csc);
+	dprintf(DEBUG_CS, "New UNIX pipe client csc=%x, sock=%d", csc, sock);
 out:
 	MTX_UNLOCK(cs, cs_mtx);
 	return (0);
@@ -270,11 +303,12 @@
 	struct cs_client *csc;
 	struct cmsghdr *cmptr;
 	struct sockcred *cred;
-	int n, sock, suser, error;
+	struct mipc_head *mih;
+	int n, sock, error, len;
 	struct msghdr msg;
 	struct iovec iov[1];
-	char control[CMSG_LEN(SOCKCREDSIZE(1))];
-	char buf[CP_MAXPLEN];
+	char control[CMSG_LEN(SOCKCREDSIZE(1)) + sizeof(struct cmsghdr)];
+	char buf[MIPC_MAXPLEN];
 
 	csc = arg.ptr;
 	MDNS_INIT_ASSERT(csc, csc_magic);
@@ -282,8 +316,6 @@
 
 	sock = csc->csc_sock;
 
-	iov[0].iov_base = buf;
-	iov[0].iov_len = CP_MAXPLEN;
 	msg.msg_name = NULL;
 	msg.msg_namelen = 0;
 	msg.msg_iov = iov;
@@ -291,30 +323,43 @@
 	msg.msg_control = control;
 	msg.msg_controllen = sizeof(control);
 	msg.msg_flags = 0;
+	iov[0].iov_base = buf + sizeof(struct mipc_head);
+
+	for (;;) {
+		n = read(sock, buf, sizeof(struct mipc_head));
+		if (n < (signed int)sizeof(struct mipc_head))
+			break;
 
-	n = recvmsg(sock, &msg, 0);
-	if (n < 0)
-		goto out;
-	cmptr = CMSG_FIRSTHDR(&msg);
-	suser = 0;
-	if (cmptr != NULL) {
-		if (cmptr->cmsg_type == SCM_CREDS &&
-		    cmptr->cmsg_level == SOL_SOCKET) {
-			cred = (struct sockcred *)CMSG_DATA(cmptr);
-			if (cred->sc_euid == 0)
-				suser = 1;
+		mih = (struct mipc_head *)buf;
+		if (mih->mih_ver != MIPC_VERSION)
+			continue;
+
+		len = mih->mih_msglen > MIPC_MAXPLEN ?
+		    MIPC_MAXPLEN : mih->mih_msglen;
+		iov[0].iov_len = len - sizeof(struct mipc_head);
+
+		n = recvmsg(sock, &msg, 0);
+		if ((unsigned int)n != iov[0].iov_len)
+			continue;
+
+		/* Check credentials */
+		cmptr = CMSG_FIRSTHDR(&msg);
+		if (cmptr != NULL) {
+			if (cmptr->cmsg_type == SCM_CREDS &&
+			    cmptr->cmsg_level == SOL_SOCKET) {
+				cred = (struct sockcred *)CMSG_DATA(cmptr);
+				csc->csc_suser = (cred->sc_euid == 0) ? 1 : 0;
+			}
 		}
-	}
 
-	dprintf(DEBUG_CS, "Received packet on UNIX pipe "
-	    "csc=%x, len=%d, suser=%d", csc, n, suser);
+		dprintf(DEBUG_CS, "Received packet on UNIX pipe csc=%x, "
+		    "len=%d, suser=%d, sock=%d", csc, n, csc->csc_suser, sock);
 
-	error = cp_parse(csc, buf, n, suser);
-	if (error != 0) {
-		dprintf(DEBUG_CS, "Failed to parse packet csc=%x", csc);
-	}	
+		error = cp_parse(csc, buf, n, csc->csc_suser);
+		if (error != 0)
+			dprintf(DEBUG_CS, "Failed to parse packet csc=%x", csc);
+	}
 
-out:
 	MTX_UNLOCK(csc, csc_mtx);
 	return (0);
 }
@@ -322,7 +367,7 @@
 /*
  * Parser defintions to individual message types.
  */
-typedef int (*mtp_func) (struct cs_client *, struct cp_head *, char *, size_t);
+typedef int (*mtp_func) (struct cs_client *, struct mipc_head *, char *, size_t);
 struct msgtype_parser {
 	int mtp_msgtype;	/* message type */
 	int mtp_suser;		/* super user privs required */
@@ -333,163 +378,1119 @@
  * Table of recognized message types and their corresponding parser.
  */
 static struct msgtype_parser mtp_table[] = {
-	{ .mtp_msgtype = CPM_ACK, .mtp_suser = 0, .mtp_parser = NULL },
-	{ .mtp_msgtype = CPM_ERROR, .mtp_suser = 0, .mtp_parser = NULL },
-	{ .mtp_msgtype = CPM_QUERY, .mtp_suser = 0, .mtp_parser = mtpf_query }
+	{ .mtp_msgtype = MIM_ACK, .mtp_suser = 0, .mtp_parser = NULL },
+	{ .mtp_msgtype = MIM_ERROR, .mtp_suser = 0, .mtp_parser = NULL },
+	{ .mtp_msgtype = MIM_QUERY, .mtp_suser = 0, .mtp_parser = mtpf_query },
+	{ .mtp_msgtype = MIM_IF_LIST, .mtp_suser = 1,
+	  .mtp_parser = mtpf_if_list },
+	{ .mtp_msgtype = MIM_IDENT_LIST, .mtp_suser = 1,
+	  .mtp_parser = mtpf_ident_list },
+	{ .mtp_msgtype = MIM_IDENT_ADD, .mtp_suser = 1,
+	  .mtp_parser = mtpf_ident_add },
+	{ .mtp_msgtype = MIM_IDENT_DEL, .mtp_suser = 1,
+	  .mtp_parser = mtpf_ident_del },
+	{ .mtp_msgtype = MIM_IDENT_NAME_ADD, .mtp_suser = 1,
+	  .mtp_parser = mtpf_name_add },
+	{ .mtp_msgtype = MIM_IDENT_NAME_DEL, .mtp_suser = 1,
+	  .mtp_parser = mtpf_name_del },
+	{ .mtp_msgtype = MIM_IDENT_NAME_LIST, .mtp_suser = 1,
+	  .mtp_parser = mtpf_name_list },
+	{ .mtp_msgtype = MIM_IDENT_RES_ADD, .mtp_suser = 1,
+	  .mtp_parser = mtpf_res_add },
+	{ .mtp_msgtype = MIM_IDENT_RES_DEL, .mtp_suser = 1,
+	  .mtp_parser = mtpf_res_del },
+	{ .mtp_msgtype = MIM_IDENT_RES_LIST, .mtp_suser = 1,
+	  .mtp_parser = mtpf_res_list },
+	{ .mtp_msgtype = MIM_CACHE_FLUSH, .mtp_suser = 1,
+	  .mtp_parser = mtpf_cache_flush },
+	{ .mtp_msgtype = MIM_CACHE_LIST, .mtp_suser = 1,
+	  .mtp_parser = mtpf_cache_list }
 };
 static int mtp_table_size = sizeof(mtp_table) / sizeof(struct msgtype_parser);
 
-
 /*
  * Parse packet received on UNIX pipe
  */
 static int
 cp_parse(struct cs_client *csc, char *buf, size_t len, int suser)
 {
-	struct cp_head *cph;
+	struct mipc_head *mih;
 	int i, error = 0;
 
-	if (len < sizeof(struct cp_head))
-		return (CPE_IVAL);
+
+	if (len < sizeof(struct mipc_head))
+		return (-1);
 	
-	cph = (struct cp_head *)buf;
-	if (cph->cph_ver != CP_VERSION)
-		return (CPE_IVAL);
+	mih = (struct mipc_head *)buf;
+
+	dprintf(DEBUG_CS, "Header ver=%d, msgtype=%d",
+	    mih->mih_ver, mih->mih_msgtype);
+
+	if (mih->mih_ver != MIPC_VERSION) {
+		error = MIE_IVAL;
+		goto error;
+	}
 
 	for (i = 0; i < mtp_table_size; i++)
-		if (cph->cph_msgtype == mtp_table[i].mtp_msgtype)
+		if (mih->mih_msgtype == mtp_table[i].mtp_msgtype)
 			break;
-	if (i == mtp_table_size)
-		return (CPE_IVAL);
+	if (i == mtp_table_size) {
+		error = MIE_IVAL;
+		goto error;
+	}
 
-	if (mtp_table[i].mtp_suser && !suser)
-		return (CPE_PERM);
-
-	dprintf(DEBUG_CS, "Header ver=%d, msgtype=%d",
-	    cph->cph_ver, cph->cph_msgtype);
+	if (mtp_table[i].mtp_suser && !suser) {
+		dprintf(DEBUG_CS, "Privileged request from non-root user "
+		    "csc=%x", csc);
+		error = MIE_PERM;
+		goto error;
+	}
 
 	if (mtp_table[i].mtp_parser != NULL) {
-		error = mtp_table[i].mtp_parser(csc, cph,
-		    buf + sizeof(struct cp_head),
-		    len - sizeof(struct cp_head));
+		error = mtp_table[i].mtp_parser(csc, mih,
+		    buf + sizeof(struct mipc_head),
+		    len - sizeof(struct mipc_head));
 	}
 	if (error != 0)
-		send_error(csc, cph->cph_id, error);
+		goto error;
 
-	return (error);
+	return (0);
+error:
+	send_error(csc, mih->mih_id, error);
+	return (-1);
 }
 
 /*
  * Query parser
  */
 static int
-mtpf_query(struct cs_client *csc, struct cp_head *cph, char *buf, size_t len)
+mtpf_query(struct cs_client *csc, struct mipc_head *mih, char *buf, size_t len)
 {
-	struct cp_query *cpq;
+	struct mipc_query *miq;
 	wchar_t *wp;
 	int error, retval = 0;
 	struct csc_query cscq;
 	wchar_t name[MDNS_RECORD_LEN+1];
 
-	if (len < sizeof(struct cp_query))
-		return (CPE_IVAL);
+	if (len < sizeof(struct mipc_query))
+		return (MIE_IVAL);
 
-	cpq = (struct cp_query *)buf;
-	if ((cpq->cpq_len * sizeof(wchar_t)) + sizeof(struct cp_query) != len)
-		return (CPE_IVAL);
+	miq = (struct mipc_query *)buf;
+	if ((miq->miq_len * sizeof(wchar_t)) + sizeof(struct mipc_query) != len)
+		return (MIE_IVAL);
 
-	wp = (wchar_t *)(buf + sizeof(struct cp_query));
-	memcpy(name, wp, cpq->cpq_len * sizeof(wchar_t));
-	name[cpq->cpq_len] = L'\0';
+	wp = (wchar_t *)(buf + sizeof(struct mipc_query));
+	memcpy(name, wp, miq->miq_len * sizeof(wchar_t));
+	name[miq->miq_len] = L'\0';
 	error = utf8_encode(name, cscq.cscq_qs.name, MDNS_RECORD_LEN);
 	if (error < 0)
-		return (CPE_IVAL);
+		return (MIE_IVAL);
 
 	dprintf(DEBUG_CS,"Query message class=%d, type=%d, name=%ls, "
-	    "cmd=%d, fam=%d, ifidx=%d, timeout=%d", cpq->cpq_class,
-	    cpq->cpq_type, name, cpq->cpq_cmd, cpq->cpq_fam,
-	    cpq->cpq_ifidx, cpq->cpq_timeout);
+	    "cmd=%d, fam=%d, ifidx=%d, timeout=%d", miq->miq_class,
+	    miq->miq_type, name, miq->miq_cmd, miq->miq_fam,
+	    miq->miq_ifidx, miq->miq_timeout);
 
 	cscq.cscq_qs.q_name = cscq.cscq_qs.name;
-	cscq.cscq_qs.q_type = cpq->cpq_type;
-	cscq.cscq_qs.q_class = cpq->cpq_class;
-	cscq.cscq_id = cph->cph_id;
+	cscq.cscq_qs.q_type = miq->miq_type;
+	cscq.cscq_qs.q_class = miq->miq_class;
+	cscq.cscq_id = mih->mih_id;
 	cscq.cscq_resp = 0;
 	cscq.cscq_csc = csc;
 	MDNS_INIT_SET(&cscq, cscq_magic);
 
-	switch (cpq->cpq_cmd) {
-	case CPQ_CMD_ONESHOT:
-		error = queryadd(csc, &cscq, cpq->cpq_ifidx, cpq->cpq_fam,
-		    cpq->cpq_timeout);
+	switch (miq->miq_cmd) {
+	case MIQ_CMD_ONESHOT:
+		error = queryadd(csc, &cscq, miq->miq_ifidx, miq->miq_fam,
+		    miq->miq_timeout);
 		if (error != 0)
-			retval = CPE_IVAL;
+			retval = MIE_IVAL;
 		break;
-	case CPQ_CMD_CREG:
-		error = queryadd(csc, &cscq, cpq->cpq_ifidx, cpq->cpq_fam, 0);
+	case MIQ_CMD_CREG:
+		error = queryadd(csc, &cscq, miq->miq_ifidx, miq->miq_fam, 0);
 		if (error == 0)
-			send_ack(csc, cph->cph_id);
+			send_ack(csc, mih->mih_id);
 		else
-			retval = CPE_REGQ;
+			retval = MIE_REGQ;
 		break;
-	case CPQ_CMD_CDEREG:
-		error = querydel(csc, &cscq, cpq->cpq_ifidx);
+	case MIQ_CMD_CDEREG:
+		error = querydel(csc, &cscq, miq->miq_ifidx);
 		if (error == 0)
-			send_ack(csc, cph->cph_id);
+			send_ack(csc, mih->mih_id);
 		else
-			retval = CPE_DEREGQ;
+			retval = MIE_DEREGQ;
 		break;
 	default:
-		return (CPE_IVAL);
+		return (MIE_IVAL);
+	}
+
+	return (0);
+}
+
+/*
+ * List active interfaces
+ */
+static int
+mtpf_if_list(struct cs_client *csc, struct mipc_head *mih, char *buf __unused,
+    size_t len)
+{
+	struct md_glob *g;
+	struct md_if *mif;
+	size_t iflen;
+	struct mipc_if miif;
+	struct mipc_head rmih;
+	struct iovec iov[3];
+
+	if (len != 0)	
+		return (MIE_IVAL);
+
+	dprintf(DEBUG_CS, "Interface list request csc=%x", csc);
+
+	g = csc->csc_serv->cs_glob;
+	IPC_SETHDR(&rmih, mih->mih_id, MIM_IF, 0);
+	iov[0].iov_base = &rmih;
+	iov[0].iov_len = sizeof(struct mipc_head);
+	iov[1].iov_base = &miif;
+	iov[1].iov_len = sizeof(struct mipc_if);
+
+	RW_RLOCK(g, g_lock);
+	TAILQ_FOREACH(mif, &g->g_ifs_head, mif_next) {
+		iflen = strlen(mif->mif_ifnam);
+		iov[2].iov_base = mif->mif_ifnam;
+		iov[2].iov_len = iflen;
+		miif.miif_ifidx = mif->mif_index;
+		miif.miif_len = iflen;
+		miif.miif_flags = 0;
+		rmih.mih_msglen =
+		    sizeof(struct mipc_head) + sizeof(struct mipc_if) + iflen;
+		writev(csc->csc_sock, iov, 3);
+	}
+
+	RW_UNLOCK(g, g_lock);
+	send_ack(csc, mih->mih_id);
+	return (0);	
+}
+
+/*
+ * List database record idents
+ */
+static int
+mtpf_ident_list(struct cs_client *csc, struct mipc_head *mih, char *buf,
+    size_t len)
+{
+	struct mipc_dbi_list *miil;
+	struct md_glob *g;
+	struct md_if *mif;
+	char **ident;
+	int i, ilen;
+	struct mipc_dbident mii;
+	struct mipc_head rmih;
+	struct iovec iov[3];
+
+	if (len < sizeof(struct mipc_dbi_list))
+		return (MIE_IVAL);
+
+	miil = (struct mipc_dbi_list *)buf;
+	g = csc->csc_serv->cs_glob;
+
+	if (miil->miil_ifidx > g->g_ifs_max)
+		return (MIE_IVAL);
+
+	mif = g->g_ifs[miil->miil_ifidx];
+	if (mif == NULL)
+		return (MIE_IVAL);
+
+	IPC_SETHDR(&rmih, mih->mih_id, MIM_IDENT, 0);
+	iov[0].iov_base = &rmih;
+	iov[0].iov_len = sizeof(struct mipc_head);
+	iov[1].iov_base = &mii;
+	iov[1].iov_len = sizeof(struct mipc_dbident);
+	mii.mii_ifidx = mif->mif_index;
+
+	ident = dbr_ident_list(&mif->mif_dbr);
+
+	i = 0;
+	while (ident[i] != NULL) {
+		ilen = strlen(ident[i]);
+		rmih.mih_msglen = sizeof(struct mipc_head) +
+		    sizeof(struct mipc_dbident) + ilen;
+		mii.mii_len = ilen;
+		iov[2].iov_base = ident[i];
+		iov[2].iov_len = ilen;
+		writev(csc->csc_sock, iov, 3);
+		i++;
+	}
+
+	dprintf(DEBUG_CS, "Sent identifier list to client, csc=%x", csc);
+
+	send_ack(csc, mih->mih_id);	
+	dbr_ident_list_free(ident);
+	return (0);
+}
+
+/*
+ * IPC MIM_IDENT_ADD - Add an itentifier to the record database
+ * The message type MIM_IDENT_ADD allows a privileged client to add
+ * a new resource identifier to the record database, either to a specific
+ * interface index or to all active interfaces.
+ */
+static int
+mtpf_ident_add(struct cs_client *csc, struct mipc_head *mih, char *buf,
+    size_t len)
+{
+	struct mipc_dbident *mii;
+	struct md_glob *g;
+	struct md_if *mif;
+	char *ident, *p;
+	int error = 0;
+
+	g = csc->csc_serv->cs_glob;
+
+	if (len < sizeof(struct mipc_dbident))
+		return (MIE_IVAL);
+
+	mii = (struct mipc_dbident *)buf;
+	p = buf + sizeof(struct mipc_dbident);
+	len -= sizeof(struct mipc_dbident);
+
+	if (mii->mii_ifidx > g->g_ifs_max)
+		return (MIE_IVAL);
+
+	if (mii->mii_len > len)
+		return (MIE_IVAL);
+
+	ident = malloc(mii->mii_len + 1);
+	if (ident == NULL)
+		return (MIE_INTE);
+	memcpy(ident, p, mii->mii_len);
+	ident[mii->mii_len] = '\0';
+
+	dprintf(DEBUG_CS, "Request to add resource identifier %s, ifidx=%d "
+	    "csc=%x", ident, mii->mii_ifidx, csc);
+
+	RW_RLOCK(g, g_lock);
+
+	/*
+	 * Only add the identifier to a specific interface index
+	 * if one was specified in the message.
+	 */
+	if (mii->mii_ifidx != 0) {
+		mif = g->g_ifs[mii->mii_ifidx];
+		if (mif == NULL) {
+			RW_UNLOCK(g, g_lock);
+			free(ident);
+			return (MIE_IVAL);
+		}
+		error = dbr_ident_add(&mif->mif_dbr, ident);
+	}
+	else {
+		/* We ignore errors in this case */
+		TAILQ_FOREACH(mif, &g->g_ifs_head, mif_next) {
+			dbr_ident_add(&mif->mif_dbr, ident);
+		}
+	}
+
+	RW_UNLOCK(g, g_lock);
+	free(ident);
+	if (error < 0)
+		return (MIE_EXISTS);
+
+	send_ack(csc, mih->mih_id);
+	return (0);
+}
+
+/*
+ * IPC MIM_IDENT_DEL - Remove an identifier from the record database
+ */
+static int
+mtpf_ident_del(struct cs_client *csc, struct mipc_head *mih, char *buf,
+    size_t len)
+{
+	struct mipc_dbident *mii;
+	struct md_glob *g;
+	struct md_if *mif;
+	char *p, *ident;
+	int error = 0;
+
+	g = csc->csc_serv->cs_glob;
+
+	if (len < sizeof(struct mipc_dbident))
+		return (MIE_IVAL);
+
+	mii = (struct mipc_dbident *)buf;
+	p = buf + sizeof(struct mipc_dbident);
+	len -= sizeof(struct mipc_dbident);
+
+	if (mii->mii_ifidx > g->g_ifs_max)
+		return (MIE_IVAL);
+
+	if (mii->mii_len > len)
+		return (MIE_IVAL);
+
+	ident = malloc(mii->mii_len + 1);
+	if (ident == NULL)
+		return (MIE_INTE);
+	memcpy(ident, p, mii->mii_len);
+	ident[mii->mii_len] = '\0';
+
+	dprintf(DEBUG_CS, "Request to remove identifier %s, ifidx=%d, csc=%x",
+	    ident, mii->mii_ifidx, csc);
+
+	RW_RLOCK(g, g_lock);
+
+	if (mii->mii_ifidx != 0) {
+		mif = g->g_ifs[mii->mii_ifidx];
+		if (mif == NULL) {
+			RW_UNLOCK(g, g_lock);
+			free(ident);
+			return (MIE_IVAL);
+		}
+		error = dbr_ident_del(&mif->mif_dbr, ident);
+	}
+	else {
+		TAILQ_FOREACH(mif, &g->g_ifs_head, mif_next) {
+			dbr_ident_del(&mif->mif_dbr, ident);
+		}
+	}
+
+	RW_UNLOCK(g, g_lock);
+	free(ident);
+	if (error < 0)
+		return (MIE_EXISTS);
+
+	send_ack(csc, mih->mih_id);
+	return (0);
+}
+
+static int
+parse_dbi_name(char *buf, size_t len, struct mipc_dbi_name **miin, char **ident,
+    wchar_t **name)
+{
+	char *p;
+	struct mipc_dbi_name *miin2;
+
+	if (len < sizeof(struct mipc_dbi_name))
+		return (MIE_IVAL);
+
+	*miin = (struct mipc_dbi_name *)buf;
+	len -= sizeof(struct mipc_dbi_name);
+	p = buf + sizeof(struct mipc_dbi_name);
+
+	miin2 = *miin;
+
+	if (len < miin2->miin_ilen)
+		return (MIE_IVAL);
+
+	*ident = malloc(miin2->miin_ilen + 1);
+	if (*ident == NULL)
+		return (MIE_INTE);
+	memcpy(*ident, p, miin2->miin_ilen);
+	*ident[miin2->miin_ilen] = '\0';
+	p += miin2->miin_ilen;
+	len -= miin2->miin_ilen;
+
+	if (len < miin2->miin_len) {
+		free(*ident);
+		return (MIE_IVAL);
+	}
+
+	*name = malloc((miin2->miin_len + 1) * sizeof(wchar_t));
+	if (*name == NULL) {
+		free(*ident);
+		return (MIE_IVAL);
+	}
+	memcpy(*name, p, miin2->miin_len * sizeof(wchar_t));
+	*name[miin2->miin_len] = L'\0';
+
+	return (0);
+}
+
+/*
+ * IPC MIM_IDENT_NAME_ADD - Add a name record to a resource identifier
+ */
+static int
+mtpf_name_add(struct cs_client *csc, struct mipc_head *mih, char *buf,
+    size_t len)
+{
+	struct md_glob *g;
+	struct md_if *mif;
+	struct mipc_dbi_name *miin;
+	wchar_t *name;
+	char *ident;
+	int error, retval = 0;
+
+	error = parse_dbi_name(buf, len, &miin, &ident, &name);
+	if (error != 0)
+		return (error);
+
+	g = csc->csc_serv->cs_glob;
+
+	dprintf(DEBUG_CS, "Request to add name %ls to identifier %s, "
+	    "csc=%x, ifidx=%d", name, ident, csc, miin->miin_ifidx);
+
+	RW_RLOCK(g, g_lock);
+
+	if (miin->miin_ifidx > g->g_ifs_max)
+		goto error;
+
+	if (miin->miin_ifidx != 0) {
+		mif = g->g_ifs[miin->miin_ifidx];
+		if (mif == NULL)
+			goto error;
+		error = dbr_name_add(&mif->mif_dbr, ident, name);
+		if (error != 0)
+			retval = MIE_NOENT;
+	}
+	else {
+		TAILQ_FOREACH(mif, &g->g_ifs_head, mif_next) {
+			dbr_name_add(&mif->mif_dbr, ident, name);
+		}
+	}
+
+	RW_UNLOCK(g, g_lock);
+	free(ident);
+	free(name);
+	if (retval == 0)
+		send_ack(csc, mih->mih_id);
+	return (retval);
+error:
+	RW_UNLOCK(g, g_lock);
+	free(ident);
+	free(name);
+	return (MIE_IVAL);
+}
+
+/*
+ * IPC MIM_IDENT_NAME_DEL - Remove a name from a resource identifier
+ */
+static int
+mtpf_name_del(struct cs_client *csc, struct mipc_head *mih, char *buf,
+    size_t len)
+{
+	struct md_glob *g;
+	struct md_if *mif;
+	struct mipc_dbi_name *miin;
+	wchar_t *name;
+	char *ident;
+	int error, retval = 0;
+
+	error = parse_dbi_name(buf, len, &miin, &ident, &name);
+	if (error != 0)
+		return (error);
+
+	g = csc->csc_serv->cs_glob;
+
+	dprintf(DEBUG_CS, "Request to remove name %ls to identifier %s, "
+	    "csc=%x, ifidx=%d", name, ident, csc, miin->miin_ifidx);
+
+	RW_RLOCK(g, g_lock);
+
+	if (miin->miin_ifidx > g->g_ifs_max)
+		goto error;
+
+	if (miin->miin_ifidx != 0) {
+		mif = g->g_ifs[miin->miin_ifidx];
+		if (mif == NULL)
+			goto error;
+		error = dbr_name_add(&mif->mif_dbr, ident, name);
+		if (error != 0)
+			retval = MIE_EXISTS;
+	}
+	else {
+		TAILQ_FOREACH(mif, &g->g_ifs_head, mif_next) {
+			dbr_name_add(&mif->mif_dbr, ident, name);
+		}
+	}
+
+	RW_UNLOCK(g, g_lock);
+	free(ident);
+	free(name);
+	if (retval == 0)
+		send_ack(csc, mih->mih_id);
+	return (retval);
+error:
+	RW_UNLOCK(g, g_lock);
+	free(ident);
+	free(name);
+	return (error);
+}
+
+/*
+ * IPC MIM_IDENT_NAME_LIST - Return a list of names on an identifier
+ */
+static int
+mtpf_name_list(struct cs_client *csc, struct mipc_head *mih, char *buf,
+    size_t len)
+{
+	struct md_glob *g;
+	struct md_if *mif;
+	struct mipc_dbi_name_list *miinl;
+	char *ident, *p;
+	struct dbr_name *dn;
+	int retval = 0;
+	size_t namlen, nlen, i;
+	struct mipc_dbi_name miin;
+	struct mipc_head rmih;
+	struct iovec iov[5];
+
+	if (len < sizeof(struct mipc_dbi_name_list))
+		return (MIE_IVAL);
+
+	miinl = (struct mipc_dbi_name_list *)buf;
+	p = buf + sizeof(struct mipc_dbi_name_list);
+	len -= sizeof(struct mipc_dbi_name_list);
+
+	if (len < miinl->miinl_ilen)
+		return (MIE_IVAL);
+
+	ident = malloc(miinl->miinl_ilen + 0);
+	if (ident == NULL)
+		return (MIE_INTE);
+	memcpy(ident, p, miinl->miinl_ilen);
+	ident[miinl->miinl_ilen] = '\0';
+
+	dprintf(DEBUG_CS, "Request to list names on identifier %s, "
+	    "csc=%x, ifidx=%d", ident, csc, miinl->miinl_ifidx);
+
+	if (miinl->miinl_ifidx == 0)
+		return (MIE_IVAL);
+
+	g = csc->csc_serv->cs_glob;
+	RW_RLOCK(g, g_lock);
+
+	mif = g->g_ifs[miinl->miinl_ifidx];
+	if (mif == NULL) {
+		retval = MIE_IVAL;
+		goto out;
+	}
+
+	dn = dbr_name_list(&mif->mif_dbr, ident, &namlen);
+	if (dn == NULL) {
+		retval = MIE_INTE;
+		goto out;
+	}
+
+	miin.miin_ifidx = mif->mif_index;
+	miin.miin_zero = 0;
+
+	RW_UNLOCK(g, g_lock);
+
+	IPC_SETHDR(&rmih, mih->mih_id, MIM_IDENT_NAME, 0);
+	iov[0].iov_base = &rmih;
+	iov[0].iov_len = sizeof(struct mipc_head);
+	iov[1].iov_base = &miin;
+	iov[1].iov_len = sizeof(struct mipc_dbi_name);
+	iov[2].iov_base = ident;
+	iov[2].iov_len = miinl->miinl_ilen;
+	miin.miin_ilen = miinl->miinl_ilen;
+
+	for (i = 0; i < namlen; i++) {
+		rmih.mih_msglen = sizeof(struct mipc_head) +
+		    sizeof(struct mipc_dbi_name) + miinl->miinl_ilen;
+
+		len = wcslen(dn[i].dn_name);
+		iov[3].iov_base = dn[i].dn_name;
+		iov[3].iov_len = len * sizeof(wchar_t);
+		rmih.mih_msglen += nlen;
+		miin.miin_len = nlen;
+	
+		if (dn[i].dn_ename != NULL) {
+			len = wcslen(dn[i].dn_ename);
+			iov[4].iov_base = dn[i].dn_ename;
+			iov[4].iov_len = len * sizeof(wchar_t);	
+			rmih.mih_msglen += nlen;
+			miin.miin_elen = nlen;
+		}
+		else {
+			iov[4].iov_base = NULL;
+			iov[4].iov_len = 0;
+			miin.miin_elen = 0;
+		}
+		writev(csc->csc_sock, iov, 5);
+	}
+
+	dbr_name_list_free(dn, namlen);
+	send_ack(csc, mih->mih_id);
+	return (0);
+out:
+	RW_UNLOCK(g, g_lock);
+	free(ident);
+	return (retval);
+}
+
+/*
+ * Parse MIM_IDENT_RES_{ADD,DEL} messages, helper do mtpf_res_{add,del}
+ */
+static int
+parse_res_set(char *buf, size_t len, struct mipc_dbi_res_set **mirs,
+    char **ident, wchar_t **res, char **resptr)
+{
+	struct mipc_dbi_res_set *mirs2;
+	char *p;
+
+	if (len < sizeof(struct mipc_dbi_res_set))
+		return (MIE_IVAL);
+
+	*mirs = (struct mipc_dbi_res_set *)buf;
+	mirs2 = *mirs;
+
+	p = buf + sizeof(struct mipc_dbi_res_set);
+	len -= sizeof(struct mipc_dbi_res_set);
+
+	if (len < mirs2->mirs_ilen)
+		return (MIE_IVAL);
+
+	*ident = malloc(mirs2->mirs_ilen + 1);
+	if (*ident == NULL)
+		return (MIE_INTE);
+	memcpy(*ident, p, mirs2->mirs_ilen);
+	*ident[mirs2->mirs_ilen] = '\0';
+	p += mirs2->mirs_ilen;
+	len -= mirs2->mirs_ilen;
+
+	*res = NULL;
+	*resptr = NULL;
+
+	if (mirs2->mirs_pointer) {
+		if (len < mirs2->mirs_rlen) {
+			free(*ident);
+			return (MIE_IVAL);
+		}
+
+		*resptr = malloc(mirs2->mirs_rlen + 1);
+		if (*resptr == NULL) {
+			free(*ident);
+			return (MIE_IVAL);
+		}
+		memcpy(*resptr, p, mirs2->mirs_rlen);
+		*resptr[mirs2->mirs_rlen] = '\0';
+	}
+	else {
+		if (len < (mirs2->mirs_rlen * sizeof(wchar_t))) {
+			free(*ident);
+			return (MIE_IVAL);
+		}
+
+		*res = malloc((mirs2->mirs_rlen + 1) * sizeof(wchar_t));
+		if (*res == NULL) {
+			free(*ident);
+			return (MIE_INTE);
+		}
+		memcpy(*res, p, mirs2->mirs_rlen * sizeof(wchar_t));
+		*res[mirs2->mirs_rlen] = L'\0';
+	}
+
+	return (0);
+}
+
+/*
+ * IPC MIM_IDENT_RES_ADD - Add a resource to an identifier
+ */
+static int
+mtpf_res_add(struct cs_client *csc, struct mipc_head *mih, char *buf,
+    size_t len)
+{
+	struct md_glob *g;
+	struct md_if *mif;
+	struct mipc_dbi_res_set *mirs;
+	wchar_t *rres;
+	char *ident, *resptr;
+	void *res;
+	int error, ptr;
+
+	error = parse_res_set(buf, len, &mirs, &ident, &rres, &resptr);
+	if (error != 0)
+		return (error);
+	res = (rres != NULL) ? (void *)rres : (void *)resptr;
+	ptr = (resptr != NULL);
+
+	g = csc->csc_serv->cs_glob;
+	RW_RLOCK(g, g_lock);
+	if (mirs->mirs_ifidx > g->g_ifs_max)
+		goto out;
+
+	error = 0;
+	if (mirs->mirs_ifidx != 0) {
+		mif = g->g_ifs[mirs->mirs_ifidx];
+		if (mif == NULL)
+			goto out;
+		error = dbr_res_add(&mif->mif_dbr, ident, mirs->mirs_class,
+		    mirs->mirs_type, mirs->mirs_ttl, res, ptr);
+	}
+	else {
+		TAILQ_FOREACH(mif, &g->g_ifs_head, mif_next) {
+			dbr_res_add(&mif->mif_dbr, ident, mirs->mirs_class,
+			    mirs->mirs_type, mirs->mirs_ttl, res, ptr);
+		}
+	}
+	RW_UNLOCK(g, g_lock);

>>> TRUNCATED FOR MAIL (1000 lines) <<<


More information about the p4-projects mailing list