srradia@watmath.UUCP (sanjay Radia) (01/30/85)
The following routines provide a higher level interface to the 4.2 ipc routines for use with servers and cliants in the UNIX and INET domains. The man page has a number of examples which should really go into the ipc-primer manual. ---------------------------Cut Here--------------------------------- # This is a shell archive. Remove anything before this line, then # unpack it by saving it in a file and typing "sh file". (Files # unpacked will be owned by you and have default permissions.) # # This archive contains: # server.3 ipc_getiservaddr.c ipc_getuservaddr.c ipc_initservsocket.c echo x - server.3 cat > "server.3" << '//E*O*F server.3//' .TH SERVER 3 "25 July 1984" .UC 4 .SH NAME ipc_initservsocket, ipc_getiservaddr, ipc_getuservaddr - server/client ipc routines. .SH SYNOPSIS .nf .PP .ft B #include <sys/types.h> #include <sys/socket.h> sock = ipc_initservsocket(servicename, addressformat, socketype, protocol) int sock, addressformat, socketype; char *servicename, *protocol; .PP .ft B #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> ipc_getiservaddr(athost, servicename, protocol, addr) char *athost, *servicename, *protocol; struct sockaddr_in *addr; .PP .ft B #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> ipc_getuservaddr(socketpath, addr, addrlen) char *socketpath; struct sockaddr_un *addr; int *addrlen; .fi .SH DESCRIPTION .BR Ipc_initservsocket is used by a server (daemon) to initialize a socket from which to receive requests from clients. The .I addressformat parameter specifies an address format with which addresses specified in later operations using the socket should be interpreted. The currently understood formats are .PP .RS .nf .ta 1.25i 1.75i AF_UNIX (UNIX path names), AF_INET (ARPA Internet addresses), .fi .RE .PP The socket has the indicated .I socketype which specifies the semantics of communication. Currently defined types are: .PP .RS .nf SOCK_STREAM SOCK_DGRAM .fi .RE .PP For .B AF_INET domain the .I protocol together with the .I servicename uniquely identifies the service port to be used. The service port is obtained from searching for a matching entry in .I /etc/services). .I Protocol specifies a particular protocol the server wishes to use. This protocol is specified in .I /etc/services for each of the services. If .I protocol is NULL then the first matching entry is used. .PP For the .B AF_UNIX domain, the .I servicename is used as the pathname for the socket in the file system. The pathaname is unlinked before binding. It is the resposibility of the caller to ensure that no other server is listing on that socket pathname .I (servicename). The .I protocol parameter is not used for this domain. .PP .BR Ipc_getiservaddr is used to get the address of a server on host .I athost for the .I AF_INET domain. If .I athost is NULL then the local machine is used. This address can later be used to form a connection .I (connect(2)) or when using .B sento or .B sendmsg .I (send(2)). .PP .PP .BR Ipc_getuservaddr is used to get the address of a server for the .I AF_UNIX domain. This address can later be used to form a connection .I (connect(2)) or when using .B sento or .B sendmsg .I (send(2)). .SH ERRORS In case of error, a negative number is returned: .PP .RS .nf .ta 1.25i 1.75i -1 unsupported addressformat. -2 could not create the socket, see perror() and errno. -3 service not found (AF_INET domain) -4 could not bind, see perro() and errno. -5 bad host name. .fi .RE .PP In addition, an external variable .I ipc_error points to a string containing an error message. .SH EXAMPLES Example of client and server using .B udp sockets in the .B AF_INET domain is: .nf client() { char reply[80]; struct sockaddr_in serv_addr; struct sockaddr from; int fromlen = sizeof(from); int s; extern char *ipc_error; if (ipc_getiservaddr(NULL, "SERVER", "udp", &serv_addr) != 0) error(ipc_error); if ((s = socket(AF_INET, SOCK_DGRAM, 0)) <0) error("client:socket : %d\n", s); if (sendto(s, "the request", 12, 0, &serv_addr, sizeof(serv_addr)) <0 ) error("client: request failed"); /* * To be safe, the socket should be made non-blocking. * The client should timeout and retransmit the request. * See recv(2) for details. */ if( recvfrom(s, reply, sizeof(reply), 0, &from, &fromlen)<0) error("client: recvfrom failed"); . . } server() { char buf[80]; int s; struct sockaddr from; int fromlen = sizeof(from); extern char *ipc_error; if((s = ipc_initservsocket("SERVER", AF_INET, SOCK_DGRAM, "udp")) <0) error("server: %s\n", ipc_error); while (recvfrom(s, buf, sizeof(buf), 0, &from, &fromlen)>=0) { . . if (sendto(s, "the reply", 10, 0, &from, fromlen) <0 ) printf("server: reply failed"); . . } } .fi .PP Example of client and server using .B tcp sockets in the .B AF_UNIX domain is: .nf extern char *ipc_error; client() { char buf[80]; struct sockaddr_un from; int fromlen = sizeof(from); struct sockaddr_un serv_addr; int serv_addrlen,s; if (ipc_getuservaddr("SERVER", &serv_addr, &serv_addrlen) != 0) error(ipc_error); if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) <0) error("client:socket : %d\n", s); if (connect(s, &serv_addr, serv_addrlen) <0 ) error("sender:connect"); while (write(s, "nullRequest\n", 6) == 6 ) ; error("client: write failed"); } server() { struct sockaddr_un from; int fromlen = sizeof(from); int s,g; if ((s = ipc_initservsocket("tcp_socket", AF_UNIX, SOCK_STREAM, NULL))<0) error("server: %s\n", ipc_error); listen(s, 5); for (;;) { if ((g = accept(s, &from, &fromlen)) <0) printf("receiver:accept failed"); else serve_request(s); /* server request from socket s */ } } serve_request(s) { char buf[80]; if ((i = read(s, &buf[0], sizeof(buf)-1)) <= 0) printf("serve_request: read error %d\n", i); /* can process request in buf */ . . } .fi .SH SEE ALSO accept(2), bind(2), connect(2), getsockname(2), getsockopt(2), ioctl(2), listen(2), recv(2), select(2), send(2), shutdown(2), socket(2), socketpair(2) .br ``A 4.2BSD Interprocess Communication Primer''. //E*O*F server.3// echo x - ipc_getiservaddr.c cat > "ipc_getiservaddr.c" << '//E*O*F ipc_getiservaddr.c//' #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> /* * SEE server(3l) for details. */ #define E_UNSUPPORTED -1 #define E_SOCKET -2 #define E_SERVICE -3 #define E_BIND -4 #define E_HOST -5 #define NULL 0 char *ipc_error; ipc_getiservaddr(athost, servicename, protocol, addr) char *athost; char *servicename; char *protocol; struct sockaddr_in *addr; { struct servent *sp; struct hostent *hp; char host[30]; if (!athost) { (void) gethostname(&host[0], sizeof(host)); athost = &host[0]; } if ((sp = getservbyname(servicename, protocol)) == (struct servent *) NULL) { ipc_error = "ipc_getiservaddr(): unknow service"; return(E_SERVICE); } if ((hp=gethostbyname(athost)) == (struct hostent *) NULL) { ipc_error = "ipc_getservaddr(): unknown host"; return(E_HOST); } bzero((char *) addr, sizeof(*addr)); bcopy(hp->h_addr, (char *)&addr->sin_addr, hp->h_length); addr->sin_family = hp->h_addrtype; addr->sin_port = sp->s_port; return(0); } //E*O*F ipc_getiservaddr.c// echo x - ipc_getuservaddr.c cat > "ipc_getuservaddr.c" << '//E*O*F ipc_getuservaddr.c//' #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <netdb.h> /* * SEE server(3l) for details. */ #define E_UNSUPPORTED -1 #define E_SOCKET -2 #define E_SERVICE -3 #define E_BIND -4 #define E_HOST -5 ipc_getuservaddr(socketpath, addr, addrlen) char *socketpath; struct sockaddr_un *addr; int *addrlen; { addr->sun_family = AF_UNIX; strcpy(addr->sun_path, socketpath); *addrlen = strlen(socketpath) + sizeof(addr->sun_family); return(0); } //E*O*F ipc_getuservaddr.c// echo x - ipc_initservsocket.c cat > "ipc_initservsocket.c" << '//E*O*F ipc_initservsocket.c//' #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/un.h> #include <netdb.h> #define E_UNSUPPORTED -1 #define E_SOCKET -2 #define E_SERVICE -3 #define E_BIND -4 #define NULL 0 char *ipc_error; ipc_initservsocket(servicename, addressformat, socketype, protocol) char *servicename; char *protocol; int addressformat, socketype; { register s; extern int errno; extern char *strcpy(); errno = 0; if ((s = socket(addressformat, socketype, 0)) < 0) { ipc_error = "ipc_initservsocket(): cannot get socket"; return(E_SOCKET); } switch (addressformat) { case AF_INET: { struct servent *sp; struct sockaddr_in sin; if ((sp = getservbyname(servicename, protocol)) == (struct servent *) NULL) { ipc_error = "ipc_initservsocket(): unknow service"; return(E_SERVICE); } sin.sin_family = AF_INET; sin.sin_port = sp->s_port; sin.sin_addr.s_addr = INADDR_ANY; /*if multi nets connected to my host */ if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { ipc_error = "ipc_initservsocket(): INET bind failed"; return(E_BIND); } return(s); } case AF_UNIX: { struct sockaddr_un sun; /* servicename is pathname for the socket */ (void) unlink(servicename); sun.sun_family = AF_UNIX; (void) strcpy(sun.sun_path, servicename); if (bind(s, (struct sockaddr *)&sun, strlen(sun.sun_path) + 2) < 0) { ipc_error = "ipc_initservsocket(): UNIX bind failed"; return(E_BIND); } return(s); } default: ipc_error = "ipc_initservsocket(): bad paramters"; return(E_UNSUPPORTED); } } //E*O*F ipc_initservsocket.c// exit 0 -- sanjay UUCP: ...!{ utzoo,decvax,ihnp4,allegra}!watmath!srradia ARPA: srradia%watmath%waterloo.csnet@csnet-relay.arpa CSNET: srradia%watmath@waterloo.CSNET