/* Doesn't work right.  Main thread sucks up all the CPU time polling unless
   we call thr_yield(). */
#include	"unpthread.h"
#include	<thread.h>		/* Solaris threads */

#define	MAXFILES	20
#define	SERV		"80"	/* port number or service name */

struct file {
  char	*f_name;			/* filename */
  char	*f_host;			/* hostname or IP address */
  int    f_fd;				/* descriptor */
  int	 f_flags;			/* F_xxx below */
  int	 f_tid;				/* thread ID */
} file[MAXFILES];
#define	F_CONNECTING	1	/* connect() in progress */
#define	F_READING		2	/* connect() complete; now reading */
#define	F_DONE			4	/* all done */
#define	F_JOINED		8	/* main has pthread_join'ed */

int		nconn, nfiles, nlefttoconn, nlefttoread;
char	get[] = "GET / HTTP/1.0\r\n\r\n";	/* for home page */

int				ndone;		/* number of terminated threads & mutex */
pthread_mutex_t	ndone_mutex = PTHREAD_MUTEX_INITIALIZER;

void	*do_get_read(void *);
void	home_page(const char *, const char *);
void	write_get_cmd(struct file *);

int
main(int argc, char **argv)
{
	int			i, n, maxnconn;
	pthread_t	tid;
	struct file	*fptr;

	if (argc < 5)
		err_quit("usage: web <#conns> <IPaddr> <homepage> file1 ...");
	maxnconn = atoi(argv[1]);

	nfiles = min(argc - 4, MAXFILES);
	for (i = 0; i < nfiles; i++) {
		file[i].f_name = argv[i + 4];
		file[i].f_host = argv[2];
		file[i].f_flags = 0;
	}
	printf("nfiles = %d\n", nfiles);

	home_page(argv[2], argv[3]);

	nlefttoread = nlefttoconn = nfiles;
	nconn = 0;
	while (nlefttoread > 0) {
/* printf("nconn = %d, nlefttoconn = %d\n", nconn, nlefttoconn); */
		while (nconn < maxnconn && nlefttoconn > 0) {
				/* find a file to read */
			for (i = 0 ; i < nfiles; i++)
				if (file[i].f_flags == 0)
					break;
			if (i == nfiles)
				err_quit("nlefttoconn = %d but nothing found", nlefttoconn);

			if ( (n = pthread_create(&tid, NULL, &do_get_read, &file[i])) != 0)
				errno = n, err_sys("pthread_create error");
printf("created thread %d\n", tid);
			file[i].f_tid = tid;
			file[i].f_flags = F_CONNECTING;
			nconn++;
			nlefttoconn--;
		}
thr_yield();

			/* See if one of the threads is done */
		if ( (n = pthread_mutex_lock(&ndone_mutex)) != 0)
			errno = n, err_sys("pthread_mutex_lock error");
		if (ndone > 0) {
			for (i = 0; i < nfiles; i++) {
				if (file[i].f_flags & F_DONE) {
					if ( (n = pthread_join(file[i].f_tid, (void **) &fptr)) != 0)
						errno = n, err_sys("pthread_join error");
		
					if (&file[i] != fptr)
						err_quit("file[i] != fptr");
					fptr->f_flags = F_JOINED;	/* clears F_DONE */
					ndone--;
					nconn--;
					nlefttoread--;
					printf("thread id %d for %s done\n",
							file[i].f_tid, fptr->f_name);
				}
			}
		}
		if ( (n = pthread_mutex_unlock(&ndone_mutex)) != 0)
			errno = n, err_sys("pthread_mutex_unlock error");
	}

	exit(0);
}

void *
do_get_read(void *vptr)
{
	int					fd, n;
	char				line[MAXLINE];
	struct file			*fptr;

	fptr = (struct file *) vptr;

	fd = Tcp_connect(fptr->f_host, SERV);
	fptr->f_fd = fd;
	printf("do_get_read for %s, fd %d, thread %d\n",
			fptr->f_name, fd, fptr->f_tid);

	write_get_cmd(fptr);	/* write() the GET command */

		/* Read server's reply */
	for ( ; ; ) {
		if ( (n = read(fd, line, MAXLINE)) <= 0) {
			if (n == 0)
				break;		/* server closed connection */
			else
				err_sys("read error");
		}
		printf("read %d bytes from %s\n", n, fptr->f_name);
	}
	printf("end-of-file on %s\n", fptr->f_name);
	close(fd);
	fptr->f_flags = F_DONE;		/* clears F_READING */

	if ( (n = pthread_mutex_lock(&ndone_mutex)) != 0)
		errno = n, err_sys("pthread_mutex_lock error");
	ndone++;
	if ( (n = pthread_mutex_unlock(&ndone_mutex)) != 0)
		errno = n, err_sys("pthread_mutex_unlock error");

	return(fptr);		/* terminate thread */
}

void
write_get_cmd(struct file *fptr)
{
	int		n;
	char	line[MAXLINE];

	strcpy(line, "GET ");
	strcat(line, fptr->f_name);
	strcat(line, " HTTP/1.0\r\n\r\n");
	n = strlen(line);
	if (writen(fptr->f_fd, line, n) != n)
		err_sys("writen error");
	printf("wrote %d bytes for %s\n", n, fptr->f_name);

	fptr->f_flags = F_READING;			/* clears F_CONNECTING */
}

void
home_page(const char *host, const char *fname)
{
	int					fd, n;
	char				line[MAXLINE];

	fd = Tcp_connect(host, SERV);

	strcpy(line, "GET ");
	strcat(line, fname);
	strcat(line, " HTTP/1.0\r\n\r\n");
	n = strlen(line);
	if (writen(fd, line, n) != n)
		err_sys("writen error");

	for ( ; ; ) {
		if ( (n = read(fd, line, MAXLINE)) <= 0) {
			if (n == 0)
				break;		/* server closed connection */
			else
				err_sys("read error");
		}
		printf("read %d bytes of home page\n", n);
		/* do whatever with data */
	}
	printf("end-of-file on home page\n");
	close(fd);
}


syntax highlighted by Code2HTML, v. 0.9.1