ftp.nice.ch/pub/next/unix/macintosh/uw.4.2.N.bs.tar.gz#/uw/lib/uw_new.c

This is uw_new.c in view mode; [Download] [Up]

/*
 *	uw library - uw_new
 *
 * Copyright 1986 by John D. Bruner.  All rights reserved.  Permission to
 * copy this program is given provided that the copy is not sold and that
 * this copyright notice is included.
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/uio.h>
#include <strings.h>
#include <signal.h>
#include <netdb.h>
#include <ctype.h>
#include "openpty.h"

#include "uwlib.h"

extern char *malloc();
extern char *getenv();

#ifndef htons
/* These should have been defined in <netinet/in.h>, but weren't (in 4.2BSD) */
extern unsigned short htons(), ntohs();
extern unsigned long htonl(), ntohl();
#endif

UWIN
uw_new(uwtype, sin)
uwtype_t uwtype;
struct sockaddr_in *sin;
{
	register UWIN uwin;
	register char *cp, c;
	register int len;
	register int ctlfd;
	int rdsz;
	auto int namelen;
	auto struct sockaddr_in sa, datasin, ctlsin;
	auto struct uwipc uwip;
	extern int errno;

	/*
	 * If our caller didn't supply an address for us to contact,
	 * look in the environment to find it.
	 */
	if (sin == (struct sockaddr_in *)0) {
		if ((cp = getenv(INET_ENV)) == (char *)0) {
			uwerrno = UWE_NXSERV;
			return((UWIN)0);
		}
		sin = &sa;
		sa.sin_family = AF_INET;
		sa.sin_addr.s_addr = 0;
		sa.sin_port = 0;
		bzero(sa.sin_zero, sizeof sa.sin_zero);
		for ( ; isxdigit(c = *cp); cp++) {
			/* Pyramid compiler blows this, must use left shift */
			/* sa.sin_addr.s_addr *= 16; */
			sa.sin_addr.s_addr <<= 4;
			if (isdigit(c))
				sa.sin_addr.s_addr += c-'0';
			else if (islower(c))
				sa.sin_addr.s_addr += c-'a' + 10;
			else
				sa.sin_addr.s_addr += c-'A' + 10;
		}
		if (c == '.') {
			for (cp++; isdigit(c = *cp); cp++)
				sa.sin_port = sa.sin_port*10 + c-'0';
		}
		if (sa.sin_addr.s_addr == 0 || sa.sin_port == 0 ||
		    c != '\0') {
			/* bad address */
			uwerrno = UWE_INVAL;
			return((UWIN)0);
		}
		sa.sin_addr.s_addr = htonl(sa.sin_addr.s_addr);
		sa.sin_port = htons(sa.sin_port);
	}

	/*
	 * Allocate space for a new window structure.
	 */
	if ((uwin = (UWIN)malloc(sizeof(*uwin))) == (UWIN)0) {
		uwerrno = UWE_NOMEM;
		return((UWIN)0);
	}
	uwin->uwi_type = uwtype;
	for (len=0; len < UW_NUMOPTS; len++) /* "len" is a convenient "int" */
		uwin->uwi_options[len].uwi_optfn = (uwfnptr_t)0;
	
	/*
	 * Create sockets for the data and control file descriptors.
	 */
	if ((uwin->uwi_datafd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ||
	    (uwin->uwi_ctlfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		if (uwin->uwi_datafd >= 0)
			(void)close(uwin->uwi_datafd);
		return((UWIN)0);
	}

	/*
	 * Bind these sockets to a local address.  We figure out the
	 * local machine's host number and use it if possible; otherwise,
	 * we fall back to 127.0.0.1 (loopback device).  After binding,
	 * we determine the port number for the control socket, since we
	 * must send that to the server.  Connect to the server.
	 */
	datasin.sin_family = AF_INET;
	datasin.sin_port = 0;
	bzero(datasin.sin_zero, sizeof datasin.sin_zero);
	getmyaddr(&datasin.sin_addr);
	ctlsin.sin_family = AF_INET;
	ctlsin.sin_port = 0;
	bzero(ctlsin.sin_zero, sizeof ctlsin.sin_zero);
	getmyaddr(&ctlsin.sin_addr);
	if (bind(uwin->uwi_datafd, (struct sockaddr *)&datasin, sizeof datasin) < 0 ||
	    bind(uwin->uwi_ctlfd, (struct sockaddr *)&ctlsin, sizeof ctlsin) < 0 ||
	    listen(uwin->uwi_ctlfd, 1) < 0) {
		uwerrno = UWE_ERRNO;
		goto error;
	}
	namelen = sizeof ctlsin;
	(void)getsockname(uwin->uwi_ctlfd, (char *)&ctlsin, &namelen);

	if (connect(uwin->uwi_datafd, sin, sizeof(struct sockaddr_in)) < 0) {
		uwerrno = UWE_ERRNO;
		goto error;
	}

	/*
	 * Now we have enough information to build the new-window command
	 * and send it to the server.  The initial command is sent to the
	 * data port.  Next, we wait for a connection from the server to
	 * our data socket.  Finally, we expect the server to send us a
	 * new window status message on the data fd.
	 */
	len = sizeof uwip.uwip_neww + (char *)&uwip.uwip_neww - (char *)&uwip;
	uwip.uwip_len = htons(len);
	uwip.uwip_cmd = htons(UWC_NEWW);
	uwip.uwip_neww.uwnw_id = 0;	/* let server choose this */
	uwip.uwip_neww.uwnw_type = htons(uwtype);
	uwip.uwip_neww.uwnw_ctlport = ctlsin.sin_port;/* byte order correct */
	if (write(uwin->uwi_datafd, (char *)&uwip, len) < 0) {
		uwerrno = UWE_ERRNO;
		goto error;
	}
	
	namelen = sizeof ctlsin;
	if ((ctlfd = accept(uwin->uwi_ctlfd, (struct sockaddr_in *)&ctlsin, &namelen)) < 0) {
		uwerrno = UWE_ERRNO;
		goto error;
	}
	(void)close(uwin->uwi_ctlfd);
	uwin->uwi_ctlfd = ctlfd;
	uw_optinit(ctlfd, uwin);

	cp = (char *)&uwip.uwip_len;
	rdsz = sizeof uwip.uwip_len;
	while (rdsz > 0 && (len=read(uwin->uwi_datafd, cp, rdsz)) > 0) {
		cp += len;
		rdsz -= len;
	}
	if (len > 0) {
		rdsz = htons(uwip.uwip_len) - sizeof uwip.uwip_len;
		while (rdsz > 0 && (len=read(uwin->uwi_datafd, cp, rdsz)) > 0) {
			cp += len;
			rdsz -= len;
		}
	}
	if (len <= 0) {
		uwerrno = UWE_ERRNO;
		goto error;
	}
	uwerrno = uwin->uwi_uwerr = ntohs(uwip.uwip_status.uwst_err);
	errno = uwin->uwi_errno = ntohs(uwip.uwip_status.uwst_errno);
	if (uwin->uwi_uwerr != UWE_NONE)
		goto error;
	uwin->uwi_id = ntohl(uwip.uwip_status.uwst_id);
	return(uwin);

error:
	(void)close(uwin->uwi_datafd);
	(void)close(uwin->uwi_ctlfd);
	free((char *)uwin);
	return((UWIN)0);
}

static
getmyaddr(addr)
struct in_addr *addr;
{
	register struct hostent *h;
	char hostname[32];
	static int once = 1;
	static struct in_addr myaddr;

	if (once) {
		if (gethostname(hostname, sizeof hostname) < 0) {
			(void)strncpy(hostname, "localhost", sizeof hostname-1);
			hostname[sizeof hostname-1] = '\0';
		}
		if ((h = gethostbyname(hostname)) != (struct hostent *)0)
			myaddr = *(struct in_addr *)h->h_addr;
		else
			myaddr.s_addr = htonl(0x7f000001L);
		once = 0;
	}
	*addr = myaddr;
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.