NetBSD-5.0.2/regress/sys/kern/kqueue/write/inet/inet.c

Compare this file to the similar file:
Show the results in this format:

/*	$NetBSD: inet.c,v 1.8 2008/04/28 20:23:06 martin Exp $	*/

/*-
 * Copyright (c) 2002 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Luke Mewburn.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>
#include <sys/event.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/wait.h>

#include <netinet/in.h>

#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <inttypes.h>

void	dumpkevent(struct kevent *);

void
dumpkevent(struct kevent *event)
{
	printf(
"kevent: ident 0x%02lx filter %d flags: 0x%02x, fflags: 0x%02x, data %" PRId64 "\n",
	    (long) event->ident, event->filter, event->flags, event->fflags,
	    event->data);
}

static int port;

static void
inetwrite(void)
{
	struct timespec		timeout;
	struct timeval		then, now, diff;
	struct kevent		event[5];
	struct sockaddr_in	sa;
	int			kq, fd, n, i, match, count;
	char			buffer[128];
	int	nevents = 0;

        kq = kqueue();
        if (kq == -1)
                err(1, "iw: kqueue");
	
	fd = socket(PF_INET, SOCK_STREAM, 0);
	if (fd == -1)
		err(1, "iw: socket");
	memset((void *)&sa, 0, sizeof(sa));

	sa.sin_family = AF_INET;
	sa.sin_port = port;
	sa.sin_addr.s_addr = htonl(0x7f000001);
	if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1)
		err(1, "iw: connect");

	n = sizeof(sa);

	EV_SET(&event[0], fd, EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, 0);
	n = kevent(kq, event, 1, NULL, 0, NULL);
	if (n == -1)
		err(1, "iw: kevent(1)");
printf("iw: registered fd %d\n", fd);
	
sleep(5);
		/*
		 * start writing
		 */
	timeout.tv_sec = 3;
	timeout.tv_nsec = 0;
	count = 0;
	for (; nevents < 10;) {
		if (gettimeofday(&then, NULL) == -1)
			err(1, "iw: gettimeofday then");
		n = kevent(kq, NULL, 0, event, 5, &timeout);
		if (gettimeofday(&now, NULL) == -1)
			err(1, "gettimeofday now");
		timersub(&now, &then, &diff);

		printf("iw: kevent returned %d in %ld.%06ld\n", n,
		    diff.tv_sec, diff.tv_usec);
		if (n == -1)
			err(1, "kevent");
		else if (n == 0)
			continue;

		nevents += n;

		match = -1;
		for (i = 0; i < n; i++) {
			printf("iw: event[%d]: ", i);
			dumpkevent(&event[i]);
			if (event[i].ident == fd)
				match = i;
		}
printf("iw: match is %d\n", match); usleep(10000);
		if (match == -1)
			continue;

		i = snprintf(buffer, sizeof(buffer),
		    "iw: |----> count %d <------------------------------------------------------------------------------------------------------------------------------------------|\n", count++);
		n = write(fd, buffer, i);
		if (event[match].flags & EV_ERROR) {
			printf("iw: error received: %d %s\n",
			    (int)event[match].data,
			    strerror((int)event[match].data));
			break;
		} else if (event[match].flags & EV_EOF) {
			printf("iw: EOF received\n");
			break;
		}
	}
	printf("iw: exiting with %s\n",
		(n >= 10) ? "success" : "failure");
	_exit((n >= 10) ? EXIT_SUCCESS : EXIT_FAILURE);
}

int
main(int argc, char **argv)
{
	struct timespec		timeout;
	struct timeval		then, now, diff;
	struct kevent		event[5];
	struct sockaddr_in	sa;
	socklen_t		salen;
	int			sock, fd, kq, i, n, match;
	char			buffer[128];
	pid_t child;
	int status;

	if (argc != 1)
		errx(1, "Usage: %s", argv[0]);

        kq = kqueue();
        if (kq == -1)
                err(1, "ir: kqueue");
	
	sock = socket(PF_INET, SOCK_STREAM, 0);
	if (sock == -1)
		err(1, "ir: socket");
	memset((void *)&sa, 0, sizeof(sa));
	sa.sin_family = AF_INET;
	if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) == -1)
		err(1, "ir: bind");

		/*
		 * start listening
		 */

	if (listen(sock, 5) == -1)
		err(1, "ir: listen");
	salen = sizeof(sa);
	if (getsockname(sock, (struct sockaddr *)&sa, &salen) == -1)
		err(1, "ir: getsockname");
	port = sa.sin_port;
	printf("ir: pid %d bound to port %d\n", getpid(), ntohs(sa.sin_port));

	if ((child = fork()) == 0) {
		inetwrite();
		_exit(EXIT_FAILURE);
	}

printf("ir: waiting 5 seconds before accept()\n"); sleep(5);
	
	timeout.tv_sec = 5;
	timeout.tv_nsec = 0;

		/* set a kevent on the listen socket */
	EV_SET(&event[0], sock, EVFILT_READ, EV_ADD | EV_ENABLE | EV_ONESHOT,
	    0, 0, 0);
	n = kevent(kq, event, 1, NULL, 0, NULL);
	if (n == -1)
		err(1, "ir: kevent(1)");
printf("ir: registered sock %d\n", sock);

	for (;;) {
		if (gettimeofday(&then, NULL) == -1)
			err(1, "ir: gettimeofday then");
		n = kevent(kq, NULL, 0, event, 1, &timeout);
		if (gettimeofday(&now, NULL) == -1)
			err(1, "ir: gettimeofday now");
		timersub(&now, &then, &diff);

		printf("ir: kevent returned %d in %ld.%06ld\n", n,
		    diff.tv_sec, diff.tv_usec);
		if (n == -1)
			err(1, "ir: kevent");
		else if (n == 0)
			continue;
		dumpkevent(event);
		break;
	}


		/*
		 * accept connection, start reading
		 */
	salen = sizeof(sa);
	fd = accept(sock, (struct sockaddr *)&sa, &salen);
	if (fd == -1)
		err(1, "ir: accept");
	printf("ir: got connection from 0x%x port %d\n",
	    ntohl(sa.sin_addr.s_addr), ntohs(sa.sin_port));

	EV_SET(&event[0], fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
	n = kevent(kq, event, 1, NULL, 0, NULL);
	if (n == -1)
		err(1, "ir: kevent(1)");
printf("ir: registered fd %d\n", fd);
	
	for (;;) {
		if (gettimeofday(&then, NULL) == -1)
			err(1, "ir: gettimeofday then");
		n = kevent(kq, NULL, 0, event, 5, &timeout);
		if (gettimeofday(&now, NULL) == -1)
			err(1, "ir: gettimeofday now");
		timersub(&now, &then, &diff);

		printf("ir: kevent returned %d in %ld.%06ld\n", n,
		    diff.tv_sec, diff.tv_usec);
		if (n == -1)
			err(1, "ir: kevent");
		else if (n == 0)
			continue;

		match = -1;
		for (i = 0; i < n; i++) {
			printf("ir: event[%d]: ", i);
			dumpkevent(&event[i]);
			if (event[i].ident == fd)
				match = i;
		}
printf("ir: match is %d\n", match); /* sleep(1); */
		if (match == -1)
			continue;

		n = read(fd, buffer, 128);
		if (n < 0)
			err(1, "read");
		buffer[n] = '\0';
buffer[0] = '\0';
		printf("[%d] %s", n, buffer);
		if (event[match].flags & EV_ERROR) {
			printf("ir: error received: %" PRId64 " %s\n",
			    event[match].data,
			    strerror((int)event[match].data));
			break;
		} else if (event[match].flags & EV_EOF) {
			printf("ir: EOF received\n");
			break;
		}
	}
	if (waitpid(child, &status, 0) != child)
		err(1, "ir: waipid returned bad pid");
	return (WEXITSTATUS(status));
}