.TH libsocket "" "" "Library"
.PC "Library of communications routines"
.PP
.B libsocket
is a library of routines that emulate the Berkeley \fBsockets\fR library.
It includes the following functions:
.LB
.if n .ta 2.25i
\fBaccept()\fR	Accept a connection on a socket
\fBbind()\fR	Bind a name to a socket
\fBbitcount()\fR	Count bits in a bit-mask
\fBconnect()\fR	Connect to a socket
\fBendhostent()\fR	Close file \fB/etc/hosts\fR
\fBendnetent()\fR	Close network file
\fBendprotoent()\fR	Close protocols file
\fBendservent()\fR	Close protocols file
\fBffs()\fR	Translate a bit mask into an integer value
\fBgetdtablesize()\fR	Get the number of files a process can open
\fBgethostbyaddr()\fR	Retrieve host information by address
\fBgethostbyname()\fR	Retrieve host information by name
\fBgethostname()\fR	Get the name of the local host
\fBgetnetbyaddr()\fR	Get a network entry by address
\fBgetnetbyname()\fR	Get a network entry by address
\fBgetnetent()\fR	Fetch a network entry
\fBgetpeername()\fR	Get name of connected peer
\fBgetprotobyname()\fR	Get protocol entry by protocol name
\fBgetprotobynumb()\fR	Get protocol entry by protocol number
\fBgetprotoent()\fR	Get protocol entry
\fBgetservbyname()\fR	Get a service entry by name
\fBgetservbyport()\fR	Get a service entry by port number
\fBgetservent()\fR	Get a service entry
\fBgetsockname()\fR	Get the name of a socket
\fBgetsockopt()\fR	Read a socket option
\fBgettimeofday()\fR	Berkeley time function
\fBinet_addr()\fR	Transform an IP address from text to binary
\fBinet_network()\fR	Transform an IP address from text to an integer
\fBlisten()\fR	Listen for a connection on a socket
\fBrandom()\fR	Return a random number
\fBrecv()\fR	Receive a message from a connected socket
\fBrecvfrom()\fR	Receive a message from a socket
\fBselect()\fR	Check whether sockets are ready for activity
\fBsend()\fR	Send a message to a connected socket
\fBsendto()\fR	Send a message to a socket
\fBsethostent()\fR	Open and rewind file \fB/etc/hosts\fR
\fBsetnetent()\fR	Open and rewind file \fB/etc/networks\fR
\fBsethostent()\fR	Open and rewind file \fB/etc/hosts\fR
\fBsetprotoent()\fR	Open the protocols file
\fBsetservent()\fR	Open the services file
\fBsetsockopt()\fR	Set a socket option
\fBshutdown()\fR	Replace function to shut down system
\fBSOCKADDRLEN()\fR	Return length of an address
\fBsocket()\fR	Create a socket
\fBsocketpair()\fR	Create a pair of sockets
\fBsrandom()\fR	Seed the random-number generator
\fBstrcasecmp()\fR	Case-insensitive string comparison
\fBstrcasencmp()\fR	Case-insensitive string comparison
\fBusleep()\fR	Sleep briefly
.PP
Function
.B socket()
creates a socket; the caller dictates the type of
socket to be created, and the communications protocol that it comprehends.
.B socket()
returns a descriptor, which resembles a file descriptor and which
can be passed to the system calls
.B read()
and
.B write()
to exchange information with whatever plugs itself into that socket.
(For details, see the
.B Notes
section at the end of this article.)
.PP
Function
.B bind()
binds the newly created socket to a file that you name.
To await a connection with another process, invoke the function
.BR listen() ;
this alerts the system to the fact that you (via your socket) await
messages of a given type.
Function
.B select()
checks whether one or more sockets are ready to be written to, or hold
data that need to be read.
When a message becomes available, invoke function
.B accept()
to accept communication with the process that wishes to connect to your socket.
These functions generally are used by ``server'' sockets.
.PP
Function
.B connect()
directly establishes connection with a server socket via
its name (that is, via the file to which it is bound).
Once connection is established, information can be exchanged via the \*(CO
system calls
.B read()
and
.BR write() .
.SH "System Files"
The socket library manipulates the following files.
Each is described in its own Lexicon entry:
.LB
.if n .ta 2.25i
\fBhosts\fR	Names and addresses of hosts on the local network
\fBhosts.equiv\fR	Name equivalent hosts
\fBhosts.lpd\fR	Local system name and domain
\fBinetd.conf\fR	Configure the Internet daemons
\fBnetworks\fR	Name remote networks
\fBprotocols\fR	Name supported protocols
\fBservices\fR	List supported TCP/IP services
.SH Example
.II "Dhuse, John"
For following gives a pair of programs that demonstrate sockets.
They were written by John Dhuse (jdhuse@sedona.intel.com).
.PP
The example consists of two programs,
.B server.c
and
.BR client.c .
Compile each with the switch
.BR \-lsocket .
To see how they work, run each in its own virtual console or
.B xterm
window.
Do not run them in the background; otherwise, you will not be able to
work with them interactively.
Be sure to start up
.B server
first, as it creates the socket into which
.B client
plugs itself.
.PP
Each process gives you a prompt; you can type commands into each.
.B server
recognizes the following commands:
.IP \fB?\fR 0.3i
Print the command menu
.IP \fBc\fR
Call
.B select()
to check the socket.
.B client
displays the status of the socket.
.IP \fBs\fR
Send a string to
.BR server .
.B client
prompts for the string, reads up to 20 characters, and writes it to
the socket.
.IP \fBr\fR
Read from the socket.
.B client
prompts for the number of bytes to read,
and clips any response to a maximum of 20.
.IP \fBq\fR
Close the socket and terminate the server process.
.PP
.B server
recognizes the following commands:
.IP \fB?\fR 0.3i
Print the command menu.
.IP \fBc\fR
Call
.B select()
to check the socket.
.IP \fBr\fR
Read from the socket.
.B server
does not prompt for the number of bytes to read,
but tries to read the entire contents of the socket,
up to a maximum of 20 bytes.
.IP \fBe\fR
Echo the read message back to the client.
The server cannot send its own message the client, just echo what it received.
.IP \fBq\fR
Close the socket, terminate the server, and
.B unlink()
the socket file.
.PP
The following gives the source for
.BR server.c :
.DM
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/un.h>
.DE
.DM
main()
{
	int sd, nsd, err,i,j,rdfds[2],wrtfds[2];
	int efds[2],done,r;
	int arg=1;
	struct sockaddr_un server;
	char *sock_name = "u0";
	char buf[20];
	char command,line[80];
	struct timeval timeout;
.DE
.DM
	/* clear our address */
	bzero((char *)&server, sizeof(server));
.DE
.DM	
	/* create socket */
	if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) <= 0) {
		err = errno;
		fprintf(stderr, "server: can't create socket\en");
		fprintf(stderr, "server: errno = %d\en", err);
		exit(EXIT_FAILURE);
	}
.DE
.DM
	server.sun_family = AF_UNIX;
	bcopy(sock_name,server.sun_path,strlen(sock_name));
.DE
.DM
  	/* bind the socket */
	if ((bind(sd, (struct sockaddr *)&server, sizeof(server))) != 0) {
		err = errno;
		fprintf(stderr, "server: can't bind socket\en");
		fprintf(stderr, "server: errno = %d\en", err);
		close(sd);
		exit(EXIT_FAILURE);
	}
.DE
.DM
  	/* listen on the socket */
	if ((listen(sd, 1)) != 0) {
		err = errno;
		fprintf(stderr, "server: can't listen on socket\en");
		fprintf(stderr, "server: errno = %d\en", err);
		close(sd);
		exit(EXIT_FAILURE);
	}
.DE
.DM
	/* accept connections on the socket */
	if ((nsd = accept(sd, (struct sockaddr*)0, (int *)0)) == -1) {
		err = errno;
		fprintf(stderr, "server: can't accept connection\en");
		fprintf(stderr, "server: errno = %d\en", err);
		close(sd);
		exit(EXIT_FAILURE);
	}
.DE
.DM
	printf("accepted client connection fd %d\en",nsd);
        /* set to non-blocking io */
	ioctl(nsd,FIOSNBIO,&arg); 
.DE
.DM
	/* echo every message back to client, exit on terminate string */
	printf("entering command loop\en");
	command = 'a';
	while (command != 'q') {
		printf("server> ");
		scanf("%s",line);
		sscanf(line,"%c", &command);
		switch (command) {
.DE
.DM
		case 'c' :
			/* set up for select */
			rdfds[0] = 1 << nsd; rdfds[1] = 0;
			wrtfds[0] = 1 << nsd; wrtfds[1] = 0;
			efds[0] = 1 << nsd; efds[1] = 0;
			timeout.tv_sec = 0; timeout.tv_usec = 0;
			r = select(nsd+1,rdfds,wrtfds,efds,(struct timeval *)NULL);
			err = errno;
.DE
.DM
			if (r < 0)
		    		printf("select() returned errno %d\en",err);
			else {
		        	if (rdfds[0] & (1 << nsd))
					printf("socket has data to be read\en");
				if (wrtfds[0] & (1 << nsd))
			    		printf("data can be written to socket\en");
				if (efds[0] & (1 << nsd))
					printf("select reports exception on socket\en");
			}
			break;
.DE
.DM
		case 'r' :
                	bzero(&buf[0], sizeof(buf));
			j = read(nsd,buf,sizeof(buf));
			err = errno;
			if (j < 0)
				printf("read() returned errno %d\en",err);
			else
				printf("got %d bytes, msg is >%s<\en",j,buf);
			break;
.DE
.DM
		case 'e' :
			printf("echoing >%s< (%d bytes) to client\en",buf,j);
			write(nsd,&buf[0],j);
			break;
.DE
.DM
		case 'q' :
			close(nsd);
			close(sd);
			unlink(sock_name);
			break;
.DE
.DM
		case '?' :
			printf("commands:\en");
			printf("   c - check the socket\en");
			printf("   ? - this help message\en");
			printf("   r - read from socket\en");
			printf("   e - echo received message to client\en");
			printf("   q - close socket and quit\en");
			break;
.DE
.DM
	        default :
			printf("\en");
			break;
		}
	}
}
.DE
.PP
The following gives the source for
.BR client.c :
.DM
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/un.h>
.DE
.DM
main()
{
	int sd, err, i, j, flags;
	int arg=1;
	struct sockaddr_un client;
	char *address="u0";
	char buf[20];
	char command,line[80];
	int rdfds[2],wrtfds[2];
	struct timeval timeout;
.DE
.DM
	/* clear our address */
	memset((char *)&client,0, sizeof(client));
.DE
.DM	
	/* create socket */
	if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) <= 0) {
		err = errno;
		fprintf(stderr, "client: can't create socket\en");
		fprintf(stderr, "client: errno = %d\en", err);
		exit(EXIT_FAILURE);
	}
.DE
.DM
	/* set to blocking so connect hangs, waiting for connect */
	arg = 0;
       	i = ioctl(sd,FIOSNBIO,&arg);
.DE
.DM
	client.sun_family = AF_UNIX;
	memcpy(client.sun_path,address,2);
.DE
.DM
	/* connect to the socket */
	if (connect(sd, (struct sockaddr *)&client, sizeof(client))) {
		err = errno;
		fprintf(stderr, "client: can't connect socket\en");
		fprintf(stderr, "client: errno = %d\en", err);
		close(sd);
		exit(EXIT_FAILURE);
	}
	printf("connected socket fd = %d\en",sd);
.DE
.DM
	arg = 1;
       	i = ioctl(sd,FIOSNBIO,&arg);
.DE
.DM
	printf("entering command loop\en");
	command = 'a';
.DE
.DM
	while (command != 'q') {
		printf("client> ");
		scanf("%s",line);
		sscanf(line,"%c",&command);
.DE
.DM
		switch (command) {
		case 's' :
			printf("message to send: ");
			scanf("%s",buf);
			i = write(sd,buf,strlen(buf));
			err = errno;
			if (i < 0) 
				printf("write() returned errno %d\en", err);
			else printf("sent >%s< (%d bytes) to server\en",
				       buf,strlen(buf));
			break;
.DE
.DM
		case '?' :
			printf("commands:\en");
			printf("   s - send a message\en");
			printf("   ? - this help messge\en");
			printf("   c - check the socket\en");
			printf("   r - read from socket\en");
			printf("   b - set to blocking I/O\en");
			printf("   n - set to non-blocking I/O\en");
			printf("   q - close socket and quit\en");
			break;
.DE
.DM
		case 'b' :
		        arg = 0;
			ioctl(sd,FIOSNBIO,&arg);
			printf("I/O is blocking\en");
			break;
.DE
.DM
		case 'n' :
		        arg = 1;
			ioctl(sd,FIOSNBIO,&arg);
			printf("I/O is non-blocking\en");
			break;
.DE
.DM
		case 'c' :
		        /* setup query fields */
		        rdfds[0] = 1 << sd; rdfds[1] = 0;
			wrtfds[0] = 1 << sd; wrtfds[1] = 0;
			timeout.tv_sec = 0; timeout.tv_usec = 0;
			i = select(sd+1,rdfds,wrtfds,(int *)NULL,
				   &timeout);
			err = errno;
			if (i < 0) 
				  printf("select() returned error %d\en",err);
			else {
				if (rdfds[0] & (1 << sd))
					printf("socket has data to be read\en");
				if (wrtfds[0] & (1 << sd))
					printf("data can be written to socket\en");
		        }
			break;
.DE
.DM
		case 'r' : 
			printf("number of bytes to read > ");
			scanf("%d",&i);
			if (i > sizeof(buf)) i = sizeof(buf);
		        memset(&buf[0],0, sizeof(buf));
			j = read(sd,buf,i);
			err = errno;
			if (j < 0) 
				printf("read() returned errno %d\en",err);
			else 
				printf("got %d bytes, msg is >%s<\en",j,buf);
			break;
.DE
.DM
		case 'q' :
			close(sd);
			break;
.DE
.DM
		default: 
			printf("\en");
			break;
		}
	}
	exit(EXIT_SUCCESS);
}
.DE
.SH "See Also"
.Xr "device driver," device_dr
.Xr "hosts," hosts
.Xr "hosts.equiv," hosts.equ
.Xr "hosts.lpd," hosts.lpd
.Xr "inetd.conf," inetd.con
.Xr "libraries," libraries
.Xr "msgget()," msgget
.Xr "named pipes," named_pip
.Xr "networks," networks
.Xr "pipe()," pipe.s
.Xr "protocols," protocols
.Xr "semget()," semget
.Xr "services," services
.Xr "shmget()," shmget
.Xr "STREAMS" streams
.SH Notes
The version of sockets included with \*(CO is not built into the kernel.
Rather, it uses a library of routines that use named pipes to emulate
sockets.
You should not invoke the system calls
.B read()
or
.B write()
to manipulate directly any descriptor returned by a call to
.BR socket() ,
because this descriptor defines only one of a set of named pipes required
to mimic a true kernel-level socket.
Header file
.B <sys/socket.h>
replaces these with the macros that perform the task correctly.
This means that in every C file where you perform a
.BR read() ,
.BR write() ,
.BR ioctl() ,
or
.B close()
on a socket, you must include
.BR <sys/socket.h> .
.PP
This library was adapted from Berkeley sources by P.Garbha
(pgd@compuram.bbt.se), and was extensively revised by Mark Williams Company.
.PP
This product includes software developed by the University of California,
Berkeley, and its contributors.
