/* kshold.c -- create a ksocket node via generic NGM_MKPEER on our own
 * control socket, then HOLD the socket open so the graph stays alive.
 * Naming/binding done externally via ngbmsg (fresh sockets).
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <netgraph/ng_message.h>
#include <netgraph/socket/ng_socket.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stddef.h>
#include <err.h>
#include <errno.h>

int main(int argc, char **argv)
{
	static char mbuf[512];
	struct ng_mesg *msg = (struct ng_mesg *)mbuf;
	struct sockaddr_ng dst;
	struct iovec iov[2];
	struct msghdr mhdr;
	struct ngm_mkpeer mk;
	int s = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL);
	if (s < 0) err(1, "socket");

	memset(&mk, 0, sizeof(mk));
	strcpy(mk.type, argc > 3 ? argv[3] : "ksocket");
	strcpy(mk.ourhook, "k0");
	strcpy(mk.peerhook, argc > 1 ? argv[1] : "inet/dgram/udp");

	memset(msg, 0, sizeof(*msg) + sizeof(mk));
	msg->header.version = NG_VERSION;
	msg->header.typecookie = 851672668;	/* NGM_GENERIC_COOKIE */
	msg->header.cmd = 2;			/* NGM_MKPEER */
	msg->header.arglen = sizeof(mk);
	memcpy(msg->data, &mk, sizeof(mk));

	memset(&dst, 0, sizeof(dst));
	dst.sg_len = offsetof(struct sockaddr_ng, sg_data) + 1;
	dst.sg_family = AF_NETGRAPH;
	dst.sg_data[0] = 0;

	iov[0].iov_base = (caddr_t)&msg->header;
	iov[0].iov_len = sizeof(struct ng_msghdr);
	iov[1].iov_base = (caddr_t)msg->data;
	iov[1].iov_len = sizeof(mk);
	memset(&mhdr, 0, sizeof(mhdr));
	mhdr.msg_name = (caddr_t)&dst;
	mhdr.msg_namelen = dst.sg_len;
	mhdr.msg_iov = iov;
	mhdr.msg_iovlen = 2;
	if (sendmsg(s, &mhdr, 0) < 0)
		err(1, "mkpeer sendmsg");
	{
		struct timeval tv0 = {1, 0};
		setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv0, sizeof(tv0));
		read(s, mbuf, sizeof(mbuf));
	}
	/* NGM_NAME the peer (relative path k0) -- ksocket node */
	{
		struct ngm_name nm;
		memset(&nm, 0, sizeof(nm));
		strcpy(nm.name, argc > 4 ? argv[4] : "ks0");
		memset(msg, 0, sizeof(*msg) + sizeof(nm));
		msg->header.version = NG_VERSION;
		msg->header.typecookie = 851672668;
		msg->header.cmd = 4;		 /* NGM_NAME */
		msg->header.arglen = sizeof(nm);
		memcpy(msg->data, &nm, sizeof(nm));
		iov[1].iov_base = (caddr_t)msg->data;
		iov[1].iov_len = sizeof(nm);
		memset(&dst, 0, sizeof(dst));
		dst.sg_len = offsetof(struct sockaddr_ng, sg_data) + strlen("k0") + 1;
		dst.sg_family = AF_NETGRAPH;
		strcpy(dst.sg_data, "k0");
		mhdr.msg_name = (caddr_t)&dst;
		mhdr.msg_namelen = dst.sg_len;
		if (sendmsg(s, &mhdr, 0) < 0)
			warn("name sendmsg (%s)", strerror(errno));
		read(s, mbuf, sizeof(mbuf));
	}
	printf("mkpeer+name sent, holding %ds (pid %d)\n",
	    argc > 2 ? atoi(argv[2]) : 600, getpid());
	fflush(stdout);
	sleep(argc > 2 ? atoi(argv[2]) : 600);
	return 0;
}
