/*
 * ftpdata.c
 *
 * how to use bind to set up a client-side ftp data connection
 *
 * This code is a hack/example and has no ftp protocol code in it.
 * Look at the function initSocket().
 *	bind is called with port set to 0.
 *	getsockname(2) is called to determine what port the kernel gave us.
 *	At that point we exit.
 *
 * Ftp clients have to get a port from the kernel and then tell the
 * server what the port is so that the server can connect back.
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>

#define TRUE 1
#define FALSE 0

#define TCPPORT 10000
#define BUFSIZE 1024
#define NOREADS 10

main(argc,argv)
char **argv;
{
	int sock;
	int size;
	char buf[BUFSIZE];
	int msgsock;
	struct sockaddr_in gotcha;
	int rc;
	int i;

	sock = initSocket();

	/* tcp starts listening for connections
	*/
	rc = listen(sock,5);
	if ( rc < 0) {
		perror("listen");
		exit(1);
	}

	/* accept one connection, will block here.
	*/
	size = sizeof (struct sockaddr_in);
	msgsock = accept(sock, &gotcha, &size);	

	if (msgsock < 0 ) {
		perror("accept");
		exit(1);
	}

	/* read and echo so many packets
	*/
	for ( i = 0; i < NOREADS; i++) {
		doRead(msgsock, buf, BUFSIZE);
		rc = write(msgsock, buf, BUFSIZE); 
		if ( rc < 0 ) {
			perror("write");
			exit(1);
		}
	}

	/* close sockets
	*/
	close(msgsock);
	close(sock);
}


/* read from socket. Read call issued to kernel
 * may return with incomplete data. This routine
 * must check that and force a complete read.
 */
doRead(sock, buf, amountNeeded)
int sock;
char *buf;
int amountNeeded;
{
	register int i;
	int rc;
	char *bpt;
	int count = amountNeeded;
	int amtread;

	bpt = buf;
	amtread = 0;
 
again:
	if ( (rc = read(sock,bpt,count)) < 0 ) {
		perror("doRead: reading socket stream");
		exit(1);
	}
	amtread += rc;

	if ( amtread < amountNeeded ) {
		count = count - rc;	
		bpt = bpt + rc;
		goto again;
	}
}


int
initSocket() 
{
    int port = 0;
    struct sockaddr_in serv_addr;
    int reuseaddr = 1;
    int sockfd;
    int len;
    
    if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	 perror("server: can't open stream socket"), exit(-1);
    
    /** Bind our local address so that the client can send to us **/
    
    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family 		= AF_INET;
    serv_addr.sin_addr.s_addr 	= htonl(INADDR_ANY);
    serv_addr.sin_port		= htons(0);
    
    if (bind(sockfd, (struct sockaddr *) &serv_addr, len=sizeof(serv_addr)) <0)
	 perror("server: can't bind local address"),exit(-1);
    
    getsockname(sockfd, (struct sockaddr *) &serv_addr, &len);
    printf("serv_addr %d\n", ntohs(serv_addr.sin_port));
    exit(1);
	
    return(sockfd);
}
