/*
 * tcp_util.c
 *
 *
 * by Eric Brown
 *    27 October '92
 */
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <winsock.h>
#include <time.h>

#include "lp.h"

char *lp_printcap_server_lookup(char *printer)
{
	return NULL;
} /* lp_printcap_server_lookup() */

int lp_tcp_startup()
{
	WSADATA	WSAData;
	return WSAStartup(0x0001, &WSAData);
} /* lp_tcp_startup() */

void lp_tcp_shutdown()
{
} /* lp_tcp_shutdown() */


/*
 * NOTES:
 *  This code is modified from _UNIX_NETWORK_PROGRAMMING_ by W. Richard Stevens,
 *  pp. 398-399.
 */
int lp_tcp_open(char *host)
{
	struct sockaddr_in	tcp_srv_addr;
	struct sockaddr_in	tcp_my_addr;
	struct hostent		tcp_host_info, *hp;
	unsigned long		inaddr;
	int					fd;
	int					retries;
	int					b_nolinger;
	struct linger		linger;
	
	memset((void *)&tcp_srv_addr, 0, sizeof(tcp_srv_addr));
	tcp_srv_addr.sin_family =AF_INET;
	tcp_srv_addr.sin_port = htons((short)PRINTER_PORT);
	
	/*
	 * First try to convert the host name as a dotted-decimal number.
	 * Only if that fails do we call gethostbyname()
	 */
	if ((inaddr = inet_addr(host)) != INADDR_NONE) {
		memcpy((void *)&tcp_srv_addr.sin_addr, (const void *)&inaddr,
			   sizeof(inaddr));
		tcp_host_info.h_name = NULL;
	}
	else
	{
		if ((hp = gethostbyname(host)) == NULL) {
			fprintf(stderr, "tcp_open: hst name error: %s\n", host);
			return -1;
		} /* if */
		tcp_host_info = *hp;
		memcpy((void *)&tcp_srv_addr.sin_addr, (const void *)hp->h_addr,
			   hp->h_length);
	} /* else */
	
	
	/*
	 * Create an internet domain socket
	 */
	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		fprintf(stderr, "tcp_open: can't get a reserved TCP port\n");
		return -1;
	} /* if */
	
	
	/*
	 * Bind to a privledged port
	 */
	memset((void *)&tcp_my_addr, 0, sizeof(tcp_my_addr));
	tcp_my_addr.sin_family = AF_INET;
	lp_randomize();
	retries = BIND_RETRIES;
	while((tcp_my_addr.sin_port = htons((short)(rand() % MAX_PRIV_PORT)),
		   bind(fd, (struct sockaddr *)&tcp_my_addr, sizeof(struct sockaddr)))) {
			if (WSAGetLastError() == WSAEADDRINUSE && retries-- > 0)
				continue; /* Try again */
			else {
				fprintf(stderr, "tcp_open: Couldn't bind.\n");
				closesocket(fd);
				return -1;
			} /* else */
	} /* while */
	if (retries == 0) {
		fprintf(stderr, "tcp_open: Tried %d ports, couldn't bind to any.\n",
				BIND_RETRIES);
		closesocket(fd);
		return -1;
	} /* if */
	

	/*
	 * Connect to the server
	 */
	if (connect(fd, (struct sockaddr *)&tcp_srv_addr, sizeof(struct sockaddr)) < 0) {
		fprintf(stderr, "tcp_open: can't connect to server\n");
		closesocket(fd);
		return -1;
	} /* if */
	
	
	/*
	 * Let us linger for 1 AND ONLY 1 second!
	 *  Without this bit of code, I found that doing an lpq or lprm
	 *  immediately after an lpr would frequently fail! -Eric.
	 */
	b_nolinger = (int)FALSE; /* turn off DONTLINGER = turn on LINGER */
	linger.l_onoff = 1;
	linger.l_linger = 1; /* 1 second */
	setsockopt(fd, SOL_SOCKET, SO_DONTLINGER, (char *)&b_nolinger, sizeof(b_nolinger));
	setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *)&linger, sizeof(linger));


	return(fd);
} /* tcp_open() */


void lp_randomize()
{
	srand((unsigned)time(NULL));
} /* lp_randomize() */

