Socket programming

Socket programming

duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. US Government Users Restricted Rights – Use. All rights reserved.© Copyright International Business Machines Corporation 2000. .

. . . . Using sendmsg() and recvmsg() to pass descriptors . . 16 Major components of DNS for sockets . . Format of DNS queries and responses for sockets Format of the DNS header section for sockets . . . . . . . . . . Socket address structure and characteristics . . . . 107 Examples: Using sendmsg() and recvmsg() APIs to handle incoming connections . . . . . . 49 Socket network functions . . . . . . . . . Configuring AF_TELEPHONY sockets to telephony domain sockets . . . . . . . . . . . . . 90 Examples: UDP connectionless client/server introduction . . . . . . .Contents Part 1. . . . . . . . . 26 27 29 30 30 33 34 37 37 43 . . . . . . . . . . 129 Examples: Establishing communications using the send_file() and accept_and_recv() APIs . . When to use IP-to-LU mapping. . . . . . . . . . . . . . . . 66 Chapter 7. 77 Example: Changing a configuration . SSL programming protocols . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Using select() for I/O multiplexing . . . . . . . . . 125 Example: Establishing SSL server and client communications . . . . . . . . . . . . . Setting the out-of-band data for sockets . . . . Type parameter for socket() . . 70 Example: Accepting a connection using the telephony domain socket . . Format of the DNS question section for sockets Format of the DNS answer. . . . . . . . . . . . . . . . . Configuring the socket environment . . . . 25 Requirements for configuring a socket environment Prerequisite information to configure IP over SNA . . 49 51 . . . . . 103 Examples: Using givedescriptor() and takedescriptor() APIs to handle incoming connections . Error information for the recvmsg() API . . . . . . . . 123 Examples: Sending and receiving a multicast datagram . . . . . . . . 19 . . . . . . . . . . . . . . . . 57 . 1 Chapter 1. . . . Print this topic . . . . . . . . . Configuring AS/400 client SOCKS support . . Configuring UNIX domain sockets . What is a socket?. . . . . 65 . . Using sockets to signal applications . . . . . . . . . 136 Chapter 4. . . . . . . Error information for the sendmsg() API. . 84 Examples: Connecting an SIOCSENDQ server and client . . . 83 Examples: Connecting a TCP server and client. . . . . Setting up the socket application environment . . . authority. 54 . . 3 Chapter 2. . . . 113 Examples: Using multiple accept() APIs to handle incoming connection requests . . . . . . . 2000 iii . 12 AnyNet support for sockets . . . . Improving performance of the socket environment . How do sockets work? . Optimal setting of the listen() back_log parameter sendmsg() and recvmsg() API considerations . . . . 57 . . . . . . . . . . . . . . 69 Example: Making a connection using the telephony domain socket . . . . . . . . Returning blocked socket functions . . Using send_file() and accept_and_recv() APIs . . 19 Address family protocols for socket() . Debugging configuration for IP over SNA . . . . . 53 . . . . . . . . . . . . . and additional sections for sockets . . . . 99 Example: Writing an iterative server program 101 Examples: Using the spawn() API to create child processes . . . . . . . Socket programming . . . . . 74 Example: Connecting multiple IP networks with multiple SNA networks . . . . . . . . . . 56 . . Coding aspects of the socket environment . . . . . . . . . . Examples: Using sockets . . 82 Examples: TCP connection-oriented client/server introduction . . 26 . . 94 Examples: Connecting a UDP server and client 95 Examples: Connection-oriented server designs introduction . . . . . 7 OS/400 socket and BSD implementation differences 10 Using AS/400 client SOCKS support to communicate outside a firewall. . . . 57 © Copyright IBM Corp. . . 122 Example: Threadsafe network routines for using gethostbyaddr_r() . . . . . . . . . 46 Chapter 6. 72 Example: Connecting a single IP network with a single SNA network . . . . . 118 Example: Code for the connection-oriented common client . . . 51 . . 22 Chapter 5. . 55 . . 62 63 . . 44 . Socket header files . . . . . . . . . . . 5 Chapter 3. . .

iv Socket programming .

2000 1 .Part 1. As of V4R3. Print this topic” on page 3 Socket programming topics: For information on how to develop a socket application or to obtain detailed socket conceptual information and configuration programming examples. “Chapter 7. What is a socket?” on page 5 v “Chapter 3. socket system functions and the socket network functions are threadsafe. “Chapter 5. How do sockets work?” on page 7 v v v v “Chapter 4. “Chapter 6. View and print a PDF version of this topic: “Chapter 1. Socket programming Socket programming shows how to use socket application program interfaces (APIs) to establish communication links between remote and local processes. Socket address structure and characteristics” on page 19 Setting up the socket application environment” on page 25 Improving performance of the socket environment” on page 49 Examples: Using sockets” on page 69 Socket API reference information: Socket API tables © Copyright IBM Corp. Socket programming information is intended for programmers who use the Integrated Language Environment (ILE) C for AS/400 language to develop applications that handle socket functions. see: v “Chapter 2.

2 Socket programming .

. click File. 3. Navigate to the directory in which you would like to save the PDF. 4. Click Save.Chapter 1. 2000 3 . save a PDF on your workstation for viewing or printing: Open the PDF in your browser (click the link above). select Socket programming. 5.html . In the menu of your browser.adobe. Print this topic You can view or download a PDF version of this document for viewing or printing. To 1. You can download a copy from http://www. To view or download the PDF version.. 2. Click Save As. © Copyright IBM Corp.com/prodindex/acrobat/readstep. You must have Adobe® Acrobat® Reader installed to view PDF files.

4 Socket programming .

It is similar to dialing a telephone number (an identifier) and making a connection with another party that is offering a service (for example. or when it exchanges messages with them. v You can name a socket and use it to communicate with other sockets in a communication domain. v You can create sockets in pairs. v Sockets perform the communication when the server accepts connections from them. and a dialog between the programs will follow. Typical system configuration places the server on one machine. Sockets are useful for both stand-alone and network applications. Instead. v A socket exists as long as the process maintains an open link to the socket. a plumber).Chapter 2. The clients connect to the server. © Copyright IBM Corp. with the clients on other machines. That integer is called a socket descriptor. The connection that a socket provides can be connection-oriented or connectionless. the connection is established. Connection-oriented communication implies that a connection is established. The client does this by connecting to the distinct name that the server program has designated. the server program designates a name that identifies where to reach it (much like a post office box). The plumber verifies that you have reached the correct party. and the connection remains active as long as both parties require it. You may have to send another letter to reestablish communication. Socket characteristics: Sockets share the following characteristics: v A socket is represented by an integer. The client of the service (the client program) must request the service of the server program. exchange information. 2000 5 . By sending a letter to a post office box. Connectionless communication implies that no connection is established over which a dialog or data transfer can take place. The program that provides the service (the server program) establishes the connection. When the receiver of the call (the server) answers the telephone. you cannot be absolutely sure the letter is received. It assigns itself a name that identifies where to obtain that service. The processes that use a socket can reside on the same system or on different systems on different networks. and then disconnect. Sockets commonly are used for client/server interaction. What is a socket? A socket is a communications connection point (endpoint) that you can name and address in a network.

6 Socket programming .

The client-to-server data exchange takes place when a client connects to the server through a socket. the socket on the server process waits for requests from a client. To do this. the server waits for clients to request a service. Note: IBM based the AS/400 system sockets on Berkeley Software Distributions (BSD) 4. The following figure shows the typical flow of events (and the sequence of issued functions) for a connection-oriented socket session. An explanation of each event © Copyright IBM Corp. and bring the client and server together. The server performs the client’s request and sends the reply back to the client.3 sockets. The two types of sockets are compatible. 2000 7 . the server first establishes (binds) an address that clients can use to find the server. The two endpoints establish a connection. How do sockets work? A socket has a typical flow of events. When the address is established. In a connection-oriented client-to-server model. but differences between OS/400 sockets and BSD sockets do exist.Chapter 3.

8 Socket programming .follows the figure.

you can use any of the socket API data transfer functions. Clients and servers have many data transfer functions from which to choose. The arrows in the following figure show the position of a socket. that socket cannot actively initiate connection requests. Socket APIs allow applications to interact with the transport or networking layers of the typical communications model. Note: The socket APIs are located in the communications model between the application layer and the transport layer. and others. you can enable sockets to communicate with server programs that run on a system outside of a firewall (a very secure host). Servers must bind a name to be accessible from the network. The server must issue the bind() and listen() functions successfully before it can issue an accept() function to accept an incoming connection request. 3. it can bind a unique name to the socket. recv(). When an application has a socket descriptor. How do sockets work? 9 . The socket() function creates an endpoint for communications and returns a socket descriptor that represents the endpoint. it issues a close() function to release any system resources acquired by the socket. The listen() API is issued after a socket is allocated with a socket() function and the bind() function binds a name to the socket. 6. Servers use stream sockets to accept a client connection request with the accept() function. 7. a network configuration does not allow connections between a secure internal network and a less secure external network. read(). The listen() function indicates a willingness to accept client connection requests. and the communication layer that the socket provides. When a connection is established between stream sockets (between client and server). 4. 2. 5.1. When a listen() is issued for a socket. Typically. The client application uses a connect() function on a stream socket to establish a connection to the server. write(). The socket APIs are not a layer in the communication model. A listen() function must be issued before an accept() function is issued. However. such as send(). Chapter 3. When a server or client wants to cease operations.

v /etc/resolv. List of protocols that are used in the Internet. are BSD semantics. The UNIX-type APIs contain the information that pertains to socket APIs. /etc/networks. respectively. You do not use a valid address or address length. except for AF_INET sockets over SNA. the OS/400 implementation supplies the following database files. The socket is using a connectionless transport service.Sockets are also a part of IBM’s AnyNet implementation for the Multiprotocol Transport Networking (MPTN) architecture. Some BSD implementations do not support the linger timer for close(). The semantics. the socket is no longer connected when all of these conditions are met: 1. The Information Center provides specific OS/400 API reference information and general API concepts.conf Configure this information for OS/400 implementation by using the CFGTCP menu. QUSRSYS File QATOCHOST QATOCPP QATOCPS QATOCPN Contents List of host names and the corresponding IP addresses. and /etc/protocols For these files. /etc/services. v connect() On a BSD system. OS/400 socket and BSD implementation differences Sockets are a Berkeley Software Distributions (BSD) interface. MPTN architecture provides the ability to operate a transport network over additional transport networks and to connect application programs across transport networks of different types. You issue a connect() against a socket that was previously connected to an address. 3. such as the return codes that an application receives and the arguments available on supported functions. and you may need to make changes to a typical BSD socket application to run it on AS/400 systems. List of services. 2. The following list summarizes the differences between the OS/400 implementation and the BSD implementation: v /etc/hosts. and the specific port and protocol that a service uses List of networks and the corresponding IP addresses. v close() The OS/400 implementation supports the linger timer for close(). 10 Socket programming . Some BSD semantics are not available in the OS/400 implementation. which serve the same functions. a client can do the following: – Create an AF_UNIX socket by using socket() – Connect to a server by using connect() – Bind a name to its socket by using bind() The OS/400 implementation does not support this scenario (the bind() fails). v bind() On a BSD system.

a BSD implementation ends blocking input operations with a zero output value when they are blocking and another process or thread issues a shutdown(). You can disconnect a connectionless transport socket for which you issued a connect() by setting the address_length parameter to zero and issuing another connect().The OS/400 implementation does not support this scenario (the connect() fails and the socket remains connected). On a BSD implementation. It also resets the _res structure. the blocking output function ends with the [EPIPE] errno value. Setting the backlog to a valid value results in the system using in the value as the backlog v OOB data In the OS/400 implementation. in some cases. The backlog value is not between zero and {SOMAXCONN} 2. You then set SO_OOBINLINE on. issuing a listen() with the backlog parameter set to a value that is less than zero or greater than {SOMAXCONN} does not result in an error. with a socket type of SOCK_DGRAM. v sendmsg() and recvmsg() The OS/400 implementation of sendmsg() and recvmsg() allows up to and including {MSG_MAXIOVLEN} I/O vectors. does not use the backlog parameter. v ioctl() – On a BSD system. The system received OOB data. FIONREAD only returns the length of data.1} I/O vectors. v res_xlate() and res_close() These functions are included in the resolver routines for the OS/400 implementation. v shutdown() The OS/400 implementation of shutdown() may block if an output function is currently blocked on the socket descriptor. On the OS/400 implementation. the FIONREAD request returns the length of the data plus the length of the address. The BSD implementation. How do sockets work? 11 . 2. The OS/400 implementation simply fails any subsequent input Chapter 3. Similarly. 3. v listen() On a BSD system. You can use res_close() to close a socket that was used by res_send() with the RES_STAYOPEN option set. The system considers the initial OOB byte normal data. The BSD implementation allows {MSG_MAXIOVLEN . v protocol parameter of socket() As a means of providing additional security. no user can create a SOCK_RAW socket specifying a protocol of IPPROTO_TCP or IPPROTO_UDP. but uses an algorithm to determine the final result for the backlog value. the system does not discard OOB data under the following conditions: 1. res_xlate() translates DNS packets from EBCDIC to ASCII and from ASCII to EBCDIC. The OS/400 implementation returns an error if both of the following occur: 1. You do not set SO_OOBINLINE. – Not all requests available on most BSD implementations of ioctl() are available on the OS/400 implementation of ioctl().

A common example of a proxy server is an HTTP proxy server. or some other action is taken to remove it from a waiting state. You must use the SO_REUSEADDR option to bind any other sockets to the same port number with an address of a. the OS/400 implementation does not change the local address from INADDR_ANY to a. a connect() on a socket of family AF_INET and type SOCK_DGRAM causes the system to change the address to which the socket is bound to the address of the interface that is used to reach the address specified on the connect(). Typically such a network configuration does not allow communications that originate from the secure host to route on the less secure network. To maintain downward compatibility with previous releases of OS/400.c.b. they can relay the reply back to the applications on the originating host. and then connect it to an address of a. v Signals Here are a few differences relating to signal support: – BSD implementations issue a SIGIO signal each time an acknowledgement is received for data that is sent on an output operation. On an OS/400 implementation. Proxy servers perform a number of tasks for HTTP clients: v They hide your internal network from outside systems. The proxy servers can then forward these requests to the real server on the less secure network.b. type SOCK_STREAM) sockets to communicate with server programs that run on systems outside a firewall. address a.c. – The default action for the SIGPIPE signal is to end the process in BSD implementations. If this IP address that the socket is bound to is a. 12 Socket programming . v SO_SNDBUF and SO_RCVBUF options The values set for SO_SNDBUF and SO_RCVBUF on a BSD system provide a greater level of control than on an OS/400 implementation.c. getsockname() continues to return INADDR_ANY after the connect() is performed.c. Proxy servers that exist on the firewall help manage required access between secure hosts and less secure networks. these values are taken as advisory values. v SO_REUSEADDR option On BSD systems.e. v They protect the host from direct access by outside systems. v They can filter data that comes in from outside if properly designed and configured.b. Additionally.e. and vice-versa. in this example.function with a zero output value. if you bind a socket of type SOCK_DGRAM to address INADDR_ANY.b. Applications that run on hosts in a secure internal network must send their requests to firewall proxy servers to navigate the firewall. Using AS/400 client SOCKS support to communicate outside a firewall AS/400 client SOCKS support enables programs that use (address family AF_INET. However.b. the system changes your socket so it is now bound to the IP address of the interface that was chosen to route packets to address a. The OS/400 sockets implementation does not generate signals related to outbound data.c.c.. A firewall is a very secure host that a network implementer places between a secure internal network and a less secure external network.e now appears on getsockname() instead of INADDR_ANY.b.d. the OS/400 implementation uses a default action of ignore for the SIGPIPE signal. For example. the blocking input function continues to block until data is received.d. In contrast.e.

Chapter 3. and a SOCKS proxy on the firewall.HTTP proxy servers handle only HTTP clients. A SOCKS server can act as a proxy for any TCP client connection that is established by using the sockets API. When configured. the system automatically directs certain outbound connections to the SOCKS server that you specified on the SOCKS page. a Telnet proxy. When the client receives the request. See “Configuring AS/400 client SOCKS support” on page 30 to establish the secure client host to a SOCKS server. and the other leads from the less secure network to the SOCKS server. The key advantage to AS/400 client SOCKS support is that it enables client applications to access a SOCKS server transparently without changing any client code. Notice that two separate TCP connections are used for the secure client that is accessing a server on the Internet. A common alternative to running multiple proxy servers on a firewall is to run a more robust proxy server known as a SOCKS server. The following figure shows a common firewall arrangement with an HTTP proxy. You do not need to make any changes to the secure client application. How do sockets work? 13 . One connection leads from the secure host to the SOCKS server.

Up to this point only outbound TCP connections that originate from the secure client were discussed. an application can explicitly code Rbind() in the pertinent source code. Alternatively. The Rbind() inbound connection must be from the same IP address that was used by the outbound connection that the connect() established. which defines bind() to be Rbind(). Note: The FTP client uses Rbind(). Rbind() should not be used. the Secure client must issue a connect() call. If an application does not require inbound connections across a SOCKS server. In order for Rbind() to operate.the SOCKS server establishes a separate external TCP/IP connection to the server in the less secure network. An Rbind() call from the secure client system allows this communication. It makes this call by recompiling the FTP client code with the __Rbind preprocessor #define. the FTP client calls the Rbind() function instead of a bind() function. It does not have direct access to the secure client. The following illustration shows a detailed overview of how socket functions interact with a SOCKS server transparent to the application. and the call must result in an outbound connection over the SOCKS server. FTP protocol allows the FTP server to establish a data connection because of a request from the FTP client to send files or 14 Socket programming . The SOCKS server then relays data between the internal and external TCP/IP connections. AS/400 client SOCKS support also lets you tell the SOCKS server to allow an inbound connection request across a firewall. In the example. Note: The remote host on the less secure network connects directly to the SOCKS server.

When configured. How do sockets work? 15 .data. The destination address that the FTP client specifies on the connect() is the IP address and port of the FTP server located on the less secure network. The secure host system is configured through the SOCKS page to direct this connection through the SOCKS server. Chapter 3. 1 FTP client initiates an outbound TCP connection to a less secure network through a SOCKS server. the system automatically directs the connection to the SOCKS server that was specified through the SOCKS page.

AnyNet is a family of products that carry out portions of the MPTN architecture. the SNA over IP version of AnyNet is a good choice. The term AnyNet refers to the concept of having any combination of API visible addresses and actual transport provider protocols. the address is sent through the ″control connection″ Socket CTLed to the FTP server that is located on the less secure network. the IP over SNA version of AnyNet is a good choice. The FTP server connects to the SOCKS server and not directly to the secure host. The SOCKS server establishes a data connection with the FTP client and relays data between the FTP client and the FTP server. For example. In this example. You must pair outbound and inbound connections over the SOCKS server for a particular thread. all Rbind() inbound connections should immediately follow the outbound connection over the SOCKS server. MPTN architecture provides for the following: v The ability to run application programs that were designed to operate on one transport network over additional transport networks. 3 4 AnyNet support for sockets AS/400 sockets over Systems Network Architecture (SNA) are also a part of IBM’s AnyNet implementation for the Multiprotocol Transport Networking (MPTN) architecture. errno ECONNABORTED is encountered on the accept(). (You can write APPC programs to the Intersystem Communications 16 Socket programming . or IP addresses over an SNA network are combinations that are defined by AnyNet. In other words. Many SOCKS servers allow a fixed length of time for the server to connect to the Secure client. Prior to AnyNet. v The ability to connect application programs across transport networks of different types. This is the address to which the FTP server connects. They allow applications that are written for one type of transport to run over a different type of transport network. SNA addresses over an IP network. The socket logically binds to the SOCKS server IP address coupled with a port that is selected through the SOCKS server. getsockname() returns the SOCKS server address. and your existing transport network limited your choice of APIs. One example is Advanced Program-to-Program Communications (APPC) programs that run over an IP network. If the server does not connect within this time.2 A socket is opened and Rbind() is called to establish an inbound TCP connection. this inbound connection is from the same destination-outbound IP address that was specified above. v SNA over IP If you have APPC programs and you want to run them over an IP network (in addition to an SNA network). AnyNet/400 support offers the following multiprotocol uses: v Internet Protocol (IP) over SNA If you have existing sockets programs and want to run them over an SNA network. your choice of API dictated your choice of transport. When established. You cannot attempt to intervene non-SOCKS connections relating to this thread before the Rbind() runs.

For example. SNA.) For more information on SNA over IP. Chapter 3. and IPX networks (see the following figure). Gateways allow sockets programs on SNA networks to communicate with sockets programs on IP networks.Function (ICF) or Common Programming Interface Communications application programming interfaces. v IP over Internetwork Packet Exchange (IPX) This AnyNet implementation involves sockets that have an address_family of AF_INET and that use IP addresses and reside on a Novell protocol network. see the APPC Programming book. The choice of destination addresses determines which type of network you use. How do sockets work? 17 . Applications that use the socket application programming interfaces (APIs) and that use Internet addressing can run over TCP. AnyNet allows you to mix and match your choice of application programs with your choice of networks in ways that were not previously possible. The same program can run simultaneously over multiple types of networks. the same sockets program can run over both IP and SNA networks.

18 Socket programming .

2000 19 . their related protocols. The application specifies the transport provider on the protocol parameter of the socket() function. Socket address structure and characteristics Sockets use the sockaddr address structure to pass and to receive addresses. The AS/400 socket APIs support these address families: v AF_INET v AF_UNIX v AF_NS v AF_TELEPHONY The use of these address families. which defines the exact format for its specific addressing requirements. sockaddr structure parts: sockaddr consists of the following parts: v The short integer that defines the address family (the value that is specified for address family on the socket() call) v Fourteen bytes that are reserved to hold the address itself Note: The length of 14 bytes is a placeholder for the address.Chapter 4. AF_INET address family: © Copyright IBM Corp. and examples of relevant structures follow. char sa_data[14]. Socket parameters: When an application creates a socket with the socket() function. The address_family parameter on the socket() function specifies the address structure that is used on socket functions. Each of the transport providers defines a similar address structure. This structure does not require the socket API to recognize the addressing format. }. The structure is generic because it does not define the format of the address. it must identify the socket by specifying these parameters: v The address family (domain in which the socket operates) v The socket type Address family protocols for socket() Address family protocols provide the network transportation of application data from one machine to another (or from one process to another within the same machine). The address can exceed this length. sockaddr structure: struct sockaddr { u_short sa_family.

Sequenced Packet eXchange (SPX) SPX UDP. The sin_family field is the address family (always AF_INET for TCP and UDP). TCP/UDP. This address is a 32-bit integer. The default value is no. struct in_addr sin_addr.xxx.h> header file contains the sockaddr_in structure definition. See Internet Addresses for more information. where each field is the decimal representation of one byte (8 bits) of the address. The ALWANYNET (Allow ANYNET support) network attribute allows you to select the use of a transport other than TCP/IP for AF_INET socket applications. Note: The ALWANYNET network attribute also affects APPC over TCP/IP.In Internet Protocol terminology. struct sockaddr_in { short sin_family. SNA. The <netinet/in. The following table lists the various combinations of socket types and protocols that you can use with AF_INET sockets: Table 1. the use of AF_INET over an SNA transport is not active. see . For example. Each node on a network is known as a host and has a unique address called an Internet address. For information on the use of this attribute with APPC over TCP/IP. and the sin_addr field is the Internet address. You express an address in the form xxx. }. APPC over IPX Configuration-Overview 20 Socket programming . SNA. AF_INET socket combinations Socket type STREAM SEQPACKET DGRAM RAW Protocol TCP. This network attribute can be either yes or no.128. The sin_zero field is reserved. set the ALWANYNET status to no to improve CPU utilization. or APPC over IPX support. Internetwork Packet eXchange (IPX) IP You can use more than one transport provider for the AF_INET address family. To use AF_INET sockets over a TCP/IP transport. Systems Network Architecture (SNA).1.xxx. For information on the use of this attribute with APPC over IPX.99. The sin_port field is the port number.xxx. the addresses for this address family are Internet Protocol (IP) addresses. char sin_zero[8]. see Appendix A. Transmission control protocol (TCP) and user datagram protocol (UDP) use the sockaddr_in address structure. APPC Over TCP/IP Configuration . you express the address whose hexadecimal representation is X'82638001' as 130. and you must set it to hexadecimal zeros. u_short sin_port. and IPX/SPX protocol layers can be active on the same socket at the same time. If the current status (the default status) is no.

AF_INET sockets over TCP/IP can specify a type of SOCK_RAW. For the AF_UNIX address family. A true socket is the communications connection (endpoint) that you obtain when you issue a socket() or an accept() function.h> header file contains the sockaddr_un address structure definition. char sns_zero[2]. and the sns_zero field is unused and must be hexadecimal zeros. struct ns_addr sns_addr. The address is a path name to an entry that is in a hierarchical file system. select the transport provider by specifying NNSPROTO_SPX. In effect. Socket address structure and characteristics 21 . Note: Although the address family is AF_NS. the application program specifies any protocol between 0 and 255 (except for TCP and UDP protocols). This means that the socket will communicate directly with the network layer that is known as Internet Protocol (IP). the 2-byte port numbers are referred to as sockets. The <netns/ns. This protocol number then flows in the IP headers when machines are communicating on the network. }. The communications mechanism between the two processes on the same machine is specific to that machine. and a 2-byte port number. The sun_path field is the pathname. AF_NS address family: This address family uses addresses that follow Novell or Xerox NS protocol definitions. For SOCK_DGRAM sockets. This is the usual communication layer for the TCP or UDP transport provider. }. It consists of a 4-byte network. When you use SOCK_RAW sockets. The sns_family field is the address family. char sun_path[126]. Chapter 4. The <sys/un. AF_UNIX address family: The system uses this address family for communicating between two programs that are on the same physical machine. when the address family equals AF_NS. select the transport provider by specifying NNSPROTO_IPX. OS/400 supports Novell NS but does not support Xerox NS. For address family AF_NS and for the SOCK_STREAM or SOCK_SEQPACKET socket. The sns_addr field is the address. The sun_family field is the address family.h> header file contains the sockaddr_ns address structure definition. Sockets with address family AF_NS use the sockaddr_ns address structure: struct sockaddr_ns { unsigned short sns_family. protocol specifications do not apply because protocol standards are not involved. Do not confuse them with the customary definition of a socket. Sockets with address family AF_UNIX use the sockaddr_un address structure: struct sockaddr_un { short sun_family. a 6-byte host (node). the application program is the transport provider because it must provide for all the transport services that the UDP or the TCP transport normally provides.

Establish an end-to-end connection by using the bind(). Do not specify 0 as the protocol parameter for any of the socket types with AF_NS. and stel_zero is a reserved field. The telephony address consists of a 2-byte length followed by a telephone number of up to 40 digits (0 . you must accomplish this at the application level. The stel_family field is the address family. The AF_TELEPHONY addresses are telephone numbers that consist of up to 40 digits (0 . AS/400 supports the following socket types: Stream (SOCK_STREAM): This type of socket is connection-oriented. and OS/400 does not support Xerox NS. accept(). }. SOCK_STREAM sends data without errors or duplication. The system supports AF_TELEPHONY sockets only as connection-oriented (type SOCK_STREAM) sockets. 2. which are contained in sockaddr_tel address structures. struct tel_addr { unsigned short t_len. This restriction occurs because Berkeley Software Distributions (BSD) implementations use Xerox NS. The <nettel/tel. SOCK_STREAM considers the data to be a stream of bytes. you can use stream sockets over 22 Socket programming . If guaranteed delivery is desired. listen(). and receives the data in the sending order. struct tel_addr stel_addr.Notes: 1. The sockets forming the endpoints of a connection in this domain are really the called (passive endpoint) and calling (active endpoint) parties of a telephone call. char stel_zero[4]. Keep in mind that a connection in the telephony domain provides no more reliability than that of the underlying telephone connection.9). struct sockaddr_tel { short stel_family. It does not impose record boundaries on the data. }. AF_TELEPHONY address family: Telephony domain sockets (sockets that use the AF_TELEPHONY address family) permit the user to initiate (dial) and complete (answer) telephone calls through an attached ISDN telephone network using standard socket APIs. SOCK_STREAM builds flow control to avoid data overruns. OS/400 supports Novell NS.9). Type parameter for socket() The type of socket that is used provides the connection that enables the transportation of data from one machine to another (or from one process to another within the same machine). and connect() functions.h> header file contains the tel_addr and sockaddr_tel structure definitions. The stel_addr field is the telephony address. Sockets with address family AF_TELEPHONY use the sockaddr_tel address structure. In the AS/400 implementation. char t_addr[40]. such as in fax applications that use this family.

Transmission Control Protocol (TCP), Systems Network Architecture (SNA), Internetwork Packet eXchange (IPX) networks, and to communicate with systems outside a secure host (firewall). Datagram (SOCK_DGRAM): In Internet Protocol terminology, the basic unit of data transfer is a datagram. This is basically a header followed by some data. The datagram socket is connectionless. It establishes no end-to-end connection with the transport provider (protocol). The socket sends datagrams as independent packets with no guarantee of delivery. You can lose or duplicate data. Datagrams can arrive out of order. The size of the datagram is limited to the data size that you can send in a single transaction. For some transport providers, each datagram can use a different route through the network. You can issue a connect() function on this type of socket. However, on the connect() function, you must specify the destination address that the program sends to and receives from. In the AS/400 implementation, you can use datagram sockets over user datagram protocol (UDP), SNA, and IPX networks. Sequenced packet (SOCK_SEQPACKET): Establish an end-to-end connection for sequenced packet sockets. However, this type of socket imposes a format on the data. SOCK_SEQPACKET maintains record boundaries, and is visible to the socket application program. Support for out-of-band data depends on the address family that is used for the socket. In the AS/400 implementation, you can use sequenced packet sockets over Sequenced Packet eXchange (SPX) sockets. Raw (SOCK_RAW): This type of socket allows direct access to lower-layer protocols, such as Internet Protocol (IP) and Internet Control Message Protocol (ICMP). SOCK_RAW requires more programming expertise because you manage the protocol header information that is used by the transport provider. At this level, the transport provider may dictate the format of the data and the semantics that are transport-provider specific.

Chapter 4. Socket address structure and characteristics

23

24

Socket programming

Chapter 5. Setting up the socket application environment
Communication between application programs running on different systems in a network requires more than coding the sockets functions. You must set up an environment for the socket system functions to operate successfully. The following figure is a general picture of how other elements support socket system functions.

Use the following information to set up the socket environment: v Configuring the socket environment, which includes requirements and prerequisite information v Coding aspects of the socket environment

© Copyright IBM Corp. 2000

25

For each system in the network. and HPR configuration examples.Requirements for configuring a socket environment Configuring a network over Transmission Control Protocol/Internet Protocol (TCP/IP) or over Systems Network Architecture (SNA) transports requires creating standard configuration objects such as lines. If you do not already have an IP network identifier. For more details and alternatives to defining an SNA network. You may find it helpful to show the topology of the network (how each system connects to adjacent systems in the network). Debug the IP over SNA configuration. 7. controllers. see the APPC. 26 Socket programming . 6. Get an IP network identifier. 2. You need the following communications objects for AF_INET sockets over SNA. 5. 3. and device descriptions for TCP/IP. This is a range of IP addresses unique to your company. (optional) Configure the SOCKS server to communicate with a secure client host. see the IBM AnyNet Guide to APPC book: over TCP/IP for Windows v APPC line description v APPC controller description v APPC device descriptions See IP over IPX for more information about IP over IPX configuration. (optional) Set the out-of-band data. AF_INET sockets over TCP or User Datagram Protocol (UDP) require line descriptions. from the Internet Network Information Center 2. Configure the socket environment. and devices. Prerequisite information to configure IP over SNA Following is a list of the prerequisite information needed to configure IP over SNA: 1. Put together an SNA network layout including each system that will use IP over SNA. (optional) Configure the AF_TELEPHONY domain sockets. (optional) Configure the UNIX domain sockets. For additional information about TCP/IP descriptions. Obtain the prerequisite information needed to configure IP over SNA. The processes needed to configure IP over SNA follow: 1. see Configuring TCP/IP . APPN. obtain the following information: v SNA network identifier v SNA local location names (SNA local LU names) v SNA APPN node type (if you are using APPN) v SNA APPN control point name (if you are using APPN) v Additional empty spaces for the addition of IP addresses in a later step Use the Display Network Attributes (DSPNETA) and Change Network Attributes (CHGNETA) commands to identify and define (respectively) this information for your system. For information on communications objects. controller descriptions. you can get one . 4.

Map the addresses in the IP over SNA subnet to each system that will support IP over SNA. Then. and the host portion is unique to each system (host) in the network. An IP address has two parts: The network portion and the host portion. you can use subnetworks. Configuring the socket environment For specific examples of configuration. The 1 bits define the subnetwork portion of the IP address (which must include at least the network portion). 3. Make sure that you allow enough space for at least one unique IP address for each system that is using IP over SNA. see the socket configuration examples found in “Chapter 7. Class and size of network Class A (Large) Class B (Medium) Class C (Small) Range 1 .) Use the following CL commands: ADDIPSIFC Add IP over SNA Interface Chapter 5. 3. for example.127 128 . Subnetworks use the two parts of the address to define a set of IP addresses that are treated as group. 4. Setting up the socket application environment 27 . A subnetwork can be used. 4 Bytes 3. The network portion is unique to each company. Define the subset of your IP network addresses (your IP network identifier) for use by IP over SNA support. which is a series of bits. 2. You can determine this by looking at the two high-order bits in the IP address. You configure a subnetwork by defining a mask. 3 Host ID Bytes 2.191 192 .223 Network ID Byte 1 Bytes 1. Where the network portion ends and the host portion begins is different for each class of IP address. The general steps to perform configuration are as follows: 1. to define which addresses should be routed over the SNA network instead of the IP network. 4 Byte 4 The IP network portion can represent a very large network that spans multiple geographic sites. Each system (or node) in the SNA network must have at least one unique SNA address. the system performs a logical AND operation on these bits and the IP address. The 0 bits define the host portion. Designate the IP (Internet Protocol) addresses that are assigned to the local host. (These IP addresses are normally referred to as interfaces. Note: Systems that remain in the IP network do not need SNA names because the system routes them through an AnyNet gateway. To make this situation easier to manage. Make sure that you allow enough space for any future additions to the network as well. Examples: Using sockets” on page 69. 2 Bytes 1. you need more if you want to use multiple LU names per system.You may need to add systems to your SNA network for AnyNet gateways or nodes that you want to migrate from the IP network to AnyNet support. You need one IP address for each LU name that will send or receive using IP over SNA support. The address is the combination of the SNA network identifier and the SNA local location name (SNA LU name). This means at least one IP address for each system.

The Convert Network Identifier/Location Name into IP Address (CVTIPSLOC) command determines the IP address from an SNA location name. activate the AnyNet support on your system by entering CHGNETA ALWANYNET(*YES) on the AS/400 system. see “When to use IP-to-LU mapping” on page 66 and “Debugging configuration for IP over SNA” on page 29. Finally. This requires designating the SNA location names (LU names) that are associated with each IP address for each remote host. 3. Note: For specific information on the parameters for the commands listed for configuration. b. see the CL command information. Two additional commands are available to assist in doing the IP-to-LU mapping: a. The system requires these routes whenever a remote host is not part of the same IP network. (The first gateway must be on the same network as the local host. Use the following CL commands: ADDIPSLOC Add IP over SNA Location CHGIPSLOC Change IP over SNA Location RMVIPSLOC Remove IP over SNA Location The Add IP over SNA Location (ADDIPSLOC) command is used to map the IP address of a particular system to its SNA network ID and SNA local LU name. Designate the IP routes to the remote hosts. Map the IP addresses to Systems Network Architecture (SNA) network ID and SNA local LU name pairs. Note: For more information on the use of the CVTIPSIFC and CVTIPSLOC commands.) You can use the following CL commands: ADDIPSRTE Add IP over SNA Route RMVIPSRTE Remove IP over SNA Route 4. You must reach a host that is not part of the same network in one of the following ways: v By using a gateway v From an IP address defined in the local host that has direct access to the remote network The IP route indicates the first gateway on the path to the remote host. You are now ready to run sockets programs over an SNA network! 28 Socket programming .CHGIPSIFC Change IP over SNA Interface RMVIPSIFC Remove IP over SNA Interface 2. The Convert IP Address into Network Identifier/Location Name (CVTIPSIFC) command determines the SNA location name from an IP address.

Note: When FTP fails. v The ADDIPSIFC command is missing on the client system. or line varied off on the client or the server system while still in use. The following table shows common errors for an IP over SNA configuration. The Start Mode (STRMOD) CL command can help you determine if your SNA configuration is correct. v The ADDIPSLOC command that is on the client system found a location name that is on a non-APPC device description. Setting up the socket application environment 29 . To get a detailed reason. The TCP/IP FTP command can help you determine if your AnyNet configuration is correct. v The mode could not be added to the device on the client system. ECONNABORTED v Line error. Common errors for an IP over SNA configuration Sockets error (value of errno) Possible causes EACCES v The user is not authorized to transport on the client system. run a sockets program that reports the value for errno when the failure occurs. Determine the remote location name from the destination IP address by using the Convert IP over SNA Interface (CVTIPSIFC) command. If you get the User prompt. EHOSTUNREACH v The ADDIPSLOC command is missing on the client system. 2. controller. it does not give a detailed reason for the failure. the AnyNet configuration is correct. Chapter 5. The message you receive when STRMOD completes tells you whether it was successful. but TCP still started. v The user is not authorized to an APPC device description that is on the server system. ECONNREFUSED v AnyNet is not active on the client system (ALWANYNET attribute is set to *NO). v Device. Table 2. v The ADDIPSLOC command that is on the client system failed to find a location name. v The type of service points to a nonexistent mode description that is on the client system. You need the remote location name as input to the STRMOD command. v The user is not authorized to the APPC device description that is on client system. EADDRNOTAVAIL v AnyNet is not active on the client system (ALWANYNET attribute is set to *NO).Debugging configuration for IP over SNA Use these commands to debug IP over SNA configurations: 1. v The listen() API is not active on the server system.

You can in the Technical Studio for additional tips also go to Firewall for AS/400 and concepts. On the secure client system. Enter your connection information on the SOCKS page. To configure client SOCKS support. Click the SOCKS tab. see Firewall: Getting started. Refer to the appropriate ISDN manual for additional information. You can define the secure client SOCKS configuration entries by using the SOCKS tab. Note: The system saves the secure client SOCKS configuration data in the QASOSCFG file of the QUSRSYS library on the secure client host system. Configuring AS/400 client SOCKS support You must perform two actions on the secure client host to use a SOCKS server: 1. 3. define all outbound client TCP connections that are directed to the SOCKS server on the client system. do the following: 1. 30 Socket programming . and TCP did not start. Common errors for an IP over SNA configuration (continued) Sockets error (value of errno) Possible causes ETIMEDOUT v The ADDIPSLOC command that is on the client system points to a location name that does not exist. 2. Create an ISDN network interface that describes the user interface. Use the CRTNWIISDN command.Table 2. 2. complete the following steps: 1. Configuration of the SOCKS server. In Operations Navigator. To configure an application that uses the telephony domain sockets. Click Properties. EUNATCH AnyNet is not active on the client system (ALWANYNET attribute is set to *NO). or is on a system that is not responding in the APPN network. AS/400 client SOCKS support operates with any SOCKS server that supports Version 4 SOCKS protocols. v The messages (especially inquiry messages) on message queue QSYSOPR are waiting for a reply. The SOCKS tab has substantial help on configuring the Secure client system for AS/400 client SOCKS support. 5. For more information on AS/400 client SOCKS support. You will find this tab under the AS/400 Operations Navigator function of Client Access/400 for Windows 95/NT. For instructions on how to configure your SOCKS server on the AS/400 firewall. see “Using AS/400 client SOCKS support to communicate outside a firewall” on page 12. Right-click TCPIP. See the following figure for an example of one way to create the interface. Configuring AF_TELEPHONY sockets to telephony domain sockets You must configure the telephony network device and associate a telephony domain socket with a network device (a telephone) before making or accepting calls. expand your AS/400 server —> Network —> Protocols —> TCP/IP. 4.

Creating the outbound connection list 4. Command Entry RCHASD4M Request level: 4 Previous commands and messages: > CRTCNNL CNNL(TELEOUT) NETTYPE(*NORTHAM) RMVCHR(*NETTYPE) Connection list TELEOUT created. > ADDCNNLE CNNL(TELEIN) ENTRY(TELANY) RMTNBR(*ANY) INFTRFTYPE(*FAXMODEM) Entry TELANY added to connection list TELEIN. press Enter. telephone numbers to use in making calls. Creating the ISDN network interface 2. Refer to the following figure for an example. through its connection list entries. ===> _________________________________________________________________________________ _________________________________________________________________________________ ________________________________________________________________________________ F3=Exit F4=Prompt F9=Retrieve F10=Include detailed messages F11=Display full F12=Cancel F13=Information Assistant F24=More keys Figure 1. Create the network telephony device. Create outbound connection lists. Chapter 5. press Enter.RCHASD4M Request level: 4 Previous commands and messages: > CRTNWIISDN NWID(TELE01) RSRCNAME(BRI001) ONLINE(*NO) NETTYPE (*NORTHAM) CH LENTRY((1 *SWT)) PCLENTRY((*PPP *LOAD 1)) SPID((1 015551598)) X31NFYCLS(* NONE) SETUPDIF(*NOLLCIE) X31DIF(*NONE) ACTTMR(16) REACTTMR(*NONE) Network interface description TELE01 created. This connection list describes. > ADDCNNLE CNNL(TELEOUT) ENTRY(TELEFAX1) RMTNBR(918885551212) INFTRFTYPE(*F AXMODEM) Entry TELEFAX1 added to connection list TELEOUT. telephone numbers to use in accepting calls. Command Entry Bottom Type command. Create inbound connection lists. See the next figure for an example. Setting up the socket application environment 31 . ===> _____________________________________________________________________________ _____________________________________________________________________________ ___________________________________________________________________________ F3=Exit F4=Prompt F9=Retrieve F10=Include detailed messages F11=Display full F12=Cancel F13=Information Assistant F24=More keys Figure 2. > ADDCNNLE CNNL(TELEOUT) ENTRY(TELEANY) RMTNBR(*ANY) INFTRFTYPE(*FAXMODEM) Entry TELEANY added to connection list TELEOUT. Use the CRTCNNL and ADDCNNLE commands for this step. through its connection list entries. Bottom Type command. > CRTCNNL CNNL(TELEIN) NETTYPE(*NORTHAM) RMVCHR(*NETTYPE) Connection list TELEIN created. 3. Use the CRTCNNL and ADDCNNLE commands for this step. This connection list describes.

===> ____________________________________________________________________________ ____________________________________________________________________________ _________________________________________________________________________ F3=Exit F4=Prompt F9=Retrieve F10=Include detailed messages F11=Display full F12=Cancel F13=Information Assistant F24=More keys Figure 3. and use this pointer as input for the SIOCSTELRSC command. press Enter. Bottom Type command. displays the socket connection: 32 Socket programming . Create the PPP line and associate it with the ISDN network interface. and the controller. the device is activated and associated with the job that issued the command. A WRKCFGSTS CFGTYPE(*LIN) CFGD(TELTLIN) command. 5. the connection lists. Vary on the network interface. and line 7. as illustrated in the next figure. 8. and device. > CRTLINPPP LIND(TELELIN) RSRCNAME(*NWID) SWTNWILST((TELE01 *B*CALC)) CNNL STOUT(TELEOUT) CNNLSTOUTE(TELEANY) CNNLSTIN(TELEIN) NETCTL(TELECTL) Line description TELELIN created. as illustrated in the next figure. 6. where TELTLIN is the PPP line name. Use the CRTLINPPP command. Use the CRTCTLNET command. Resolve the device name to a system pointer. Command Entry RCHASD4M Request level: 4 Previous commands and messages: > CRTDEVNET DEVD(TELEDEV) TYPE(*TEL) ONLINE(*NO) Description for device TELEDEV created. Create the network controller and associate it with the device. Creating the device.Use the CRTDEVNET command. as illustrated in the following figure. When the SIOCSTELRSC request completes. controller. > CRTCTLNET CTLD(TELECTL) ONLINE(*NO) DEV(TELEDEV) Description for controller TELECTL created. controller. PPP line.

Configuring UNIX domain sockets UNIX domain sockets (sockets that use the AF_UNIX address family) can be connection-oriented (type SOCK_STREAM) or they can be connectionless (type SOCK_DGRAM). The socketpair() function returns two unnamed and connected socket descriptors. This multiple association permits an application to listen for and answer calls on more than one device through a single socket. the client program does not have to call the bind() function because the system assigns an unused port number automatically. the bind() fails. Thus. . . press Enter. however. Setting up the socket application environment 33 .. __________ Starting characters Type options. AF_UNIX is the only address family to support the socketpair() function.Work with Configuration Status RCHASD4M 11/06/98 16:45:46 Position to . . 1=Vary on 2=Vary off 5=Work with job 8=Work with description 9=Display mode status 13=Work with APPN status. The sockets program calls the bind() function. Both types can be reliable because no external communication functions connect the two processes. a UNIX domain socket program should always call an unlink() function to remove the directory entry when it ends. you can associate more than one device with a socket.. WRKCFGSTS display after running SIOCSTELRSC request for device The device will remain associated with the socket until the socket closes. Finally. On connectionless sockets. The semantics and functions available to the sockets programmer are the same as when using AF_INET sockets. Opt: ___ ___ ___ Description: TELTLIN TELTCTL TELTDEV Status: -------------Job-------------CONNECT PENDING ACTIVE ACTIVE QPADEV0003 TELUSE 031395 Bottom Parameters or command ===> ___________________________________________________________________________________ F3=Exit F4=Prompt F12=Cancel F23=More options F24=More keys Figure 4. Note: Path names in the file system are NLS-enabled. The name space for UNIX domain sockets consists of path names. If the path name already exists. the system discards packets if it receives data so fast that the system runs out of buffers. . and creates an entry in the file system directory. With UDP datagram sockets. To create a UNIX domain socket. UNIX domain datagram sockets act differently than UDP datagram sockets. a sockets program specifies AF_UNIX for the address family when it calls a socket() or socketpair() function. The Chapter 5.

Note: The value that indicates which byte the OOB marker points to is set on a system basis (all applications use that value). the system does not automatically assign a path name for the client. (For information on using the Change TCP Attributes (CHGTCPA) command to change which byte this marker points to. all client programs that use UNIX domain datagrams must call the bind() function. Note: The exact path name specified on the client’s bind() is what is passed to the server. An example path name that an application might use for this address family is /tmp/myserver or servers/thatserver. Socket applications that use this value must use it consistently between the client and server applications. Only sockets that have an address family of AF_INET and a type of SOCK_STREAM support OOB data. A relative path name is a path that is not listed by starting with slash (/). Setting the out-of-band data for sockets Out-of-band (OOB) data is user-specific data that only has meaning for connection-oriented (stream) sockets. OOB data is received independent of its position in the stream (independent of the order in which it was sent). The system transmits the data in the order sent. things are a little more complex: v The sockets API keeps track of OOB data that is received on a system by using an OOB marker. you have a path name that is not fully qualified (no / was specified).server can then send a datagram back to that port number. the server cannot send the client a datagram unless it is running with the same current directory. program B is notified of its arrival. However. Thus. if the client specifies a relative path name. It is sent after any data that is buffered. The transmission of OOB data is the same as the transmission of regular data. and sendmsg() functions. when it is sent from program A to program B. The ioctl() SIOCATMARK request determines if the read pointer is pointing to the last OOB byte. With servers/thatserver. with UNIX domain datagram sockets. The OOB marker points to the last byte in the OOB data that was sent. This value must be consistent between the local and remote ends of a TCP connection. The system generally receives stream data in the same order sent. 34 Socket programming . sendto(). Thus. This occurs because the data is marked in such a way that. OOB data does not take precedence over any nonbuffered data. see the alphabetical listing of commands. Note: If you send multiple occurrences of OOB data. You send OOB data by specifying the MSG_OOB flag on the send(). On the receiving side. In other words. the OOB marker points to the last OOB byte of the final OOB data occurrence. This means that the location of the entry in the file system hierarchy should be determined relative to the current working directory.

or recvfrom() function (with the MSG_OOB flag set) to receive OOB data. otherwise. Chapter 5. an input operation processes data up to the OOB marker. Furthermore. OOB data is not lost if you send multiple occurrences of OOB data: v The system does not discard the OOB data if you did not set SO_OOBINLINE. the OOB byte is deleted. (If it is specified. Also. If a receive function is issued with the MSG_OOB flag not set and normal data is received. and there is no OOB data to receive. If you set the socket option SO_OOBINLINE. even though it received the OOB byte. or recvfrom() function with the MSG_OOB flag set. when OOB data sent is greater than one byte. the OOB data from the preceding occurrence is lost. recvmsg(). if the system sent OOB data. (Normal data means that the receiving program can receive data without specifying the MSG_OOB flag. Setting up the socket application environment 35 . the position of the OOB data for the final OOB data occurrence is remembered. v If you did not set SO_OOBINLINE. and then set SO_OOBINLINE on. The receiving program can still determine whether the read pointer is at the OOB marker.v Independent of whether you receive OOB data inline or not. the system returns an error of [EINVAL]). all of the OOB data sent is stored in the normal data stream.) The last byte of the OOB data that was sent is not stored in the normal data stream. but received OOB data. The system considers the initial OOB byte normal data. – You have set the socket option SO_OOBINLINE. and the receiving program issued an input function to receive the OOB data. You can retrieve data by issuing one of the three receive functions without specifying the MSG_OOB flag. You can retrieve this byte only by issuing a recv(). then the OOB marker is still valid. v You can use a recv(). Set the socket option SO_OOBINLINE. but you sent OOB data. recvmsg(). the system considers all the bytes except for the last byte as normal data. if the system sends multiple occurrences of OOB data. An error of [EINVAL] is returned if one of the receive functions has completed and one of the following occurs: – You have not set the socket option SO_OOBINLINE .

36 Socket programming .The following two figures show what happens when you receive OOB data.

such as: Chapter 5. v Understand SSL programming protocols to provide communications privacy over the Internet. Socket header files Part of the socket APIs consist of structures and defined macros that are shipped as header files (files that you can include in a user program).Coding aspects of the socket environment Here are some coding considerations to help you set up the socket environment: v Find and install the socket header files for use with the socket function. v Use sendmsg() and recvmsg() APIs to pass descriptors to design simpler logic for server and worker jobs. Setting up the socket application environment 37 . Programs that use the socket functions must include one or more header files that contain information that is needed by the functions. v Use the send_file() and accept_and_recv() APIs to transfer files over connected sockets faster and easier.

select the OS/400 Openness Includes option.h> Description Defines prototypes for those network library routines that convert Internet address and dotted-decimal notation. The following table lists the header files used by socket functions. For example. On an OS/400 command line. 2. The OS/400 Openness Includes are packaged as part of OS/400.h> and <sys/types. enter GO LICPGM. for example.v v v v Macro definitions Data type definitions Structure definitions Function prototypes You can find the header files in the QSYSINC library. Header files for the sockets APIs File name <arpa/inet. 4. File: ARPA Member: INET <arpa/nameser.h> Defines Internet name server macros and structures that are needed when the system uses the resolver routines.h> The application programmer must include <sys/socket.h> in the program for the accept() function to run successfully. On the Install Licensed Programs display. which you can optionally install.h> #include <sys/socket. Table 3. #include <sys/types. Load the media that contains the OS/400 Openness Includes. File: ARPA Member: NAMESER 38 Socket programming . select the Install licensed programs option. The Description column states the purpose of the header file and gives the file name and member name of the header file in QSYSINC. 3. the format for accept() lists the following header files. and contain the header files. inet_makeaddr(). To install the QSYSINC library: 1. The syntax of each socket function lists the header files required for that function (see the socket API information). On the resulting Work with Licensed Programs menu. Make sure that QSYSINC is on your system before you compile programs that use these header files.

File: NETINET Member: IN Chapter 5.h> Defines prototypes. variables. macros. and the rtentry and rtconf structures that are associated with ioctl() requests that affect routing entries. variables.h> Defines prototypes.h> Description Defines macros and variables for error reporting. Setting up the socket application environment 39 . File: NET Member: IF <net/route. member ERRNO in library QCLE.h> Defines prototypes. Header files for the sockets APIs (continued) File name <error. variables. <fcntl.h> Contains data definitions for the network library routines. File: H Member: ERRNO Note: This file also exists as file H. macros. and the sockaddr_in structure to use with Internet domain sockets. and structures for control-type functions. File: H Member: FCNTL <net/if. macros. variables. for example.Table 3. File: H Member: ROUTE <netdb. macros. and the ifreq and ifconf structures that are associated with ioctl() requests that affect interfaces. fcntl().h> Defines prototypes. Defines the following structures: v hostent and hostent_data v netent and netent_data v servent and servent_data v protoent and protoent_data File: H Member: NETDB <netinet/in.

You must include this file in AF_NS socket applications.h> Defines macros. and structures that are associated with setting IP options. variables. File: NETNS Member: NS <netns/sp. and structures that are associated with the Internet Control Message Protocol.h> Description Defines macros.h> Defines ioctl structures for IPX ioctl() requests.Table 3. and structures that are associated with setting TCP options. Header files for the sockets APIs (continued) File name <netinet/ip. variables. File: NETNS Member: SP 40 Socket programming .h> Defines AF_NS socket structures and options. File: NETINET Member: IP_ICMP <netinet/tcp. May be needed in AF_NS socket applications. File: NETNS Member: IDP <netns/ipx. File: NETINET Member: TCP <netns/idp.h> Defines macros.h> Defines SPX packet header. May be needed in AF_NS socket applications. File: NETNS Member: IPX <netns/ns. File: NETINET Member: IP <netinet/ip_icmp. variables.h> Defines IPX packet header. May be needed in AF_NS socket applications.

and the following structures: v SSLInit v SSLHandle File: H Member: SSL <sys/ioctl. File: SYS Member: IOCTL <sys/param.h> Defines additional macros. File: H Member: PARAM <sys/signal. in addition to miscellaneous macros and prototypes. File: SYS Member: SIGNAL Chapter 5. File: H Member: RESOLV <ssl. Header files for the sockets APIs (continued) File name <nettel/tel.h> Defines some limits to system fields. You must include this file in AF_TELEPHONY socket applications. ioctl().Table 3. macros. for example. macros. and structures for I/O control-type functions.h> Defines Secure Sockets Layer (SSL) prototypes. and functions that are used by signal routines.h> Description Defines sockaddr_tel structure and related structures and macros. Setting up the socket application environment 41 . File: NETTEL Member: TEL <resolv. variables.h> Defines prototypes. structures. types.h> Contains macros and structures that are used by the resolver routines. variables.

macros.h> Defines prototypes. Also includes prototypes. Header files for the sockets APIs (continued) File name <sys/socket.h> Defines various data types.h> Defines prototypes.h> Defines prototypes. and the sockaddr_un structure to use with UNIX domain sockets. File: SYS Member: UN <unistd. variables. variables. and structures that are associated with time functions. File: SYS Member: TYPES <sys/uio. and structures that are associated with the select() function. variables. variables. macros. File: SYS Member: TIME <sys/types. File: SYS Member: UIO <sys/un.h> Description Defines socket prototypes.Table 3.h> Contains macros and structures that are defined by the integrated file system. macros. Needed when the system uses the read() and write() system functions. File: H Member: UNISTD 42 Socket programming . and the following structures: v sockaddr v msghdr v linger You must include this file in all socket applications. and structures that are associated with I/O functions. macros. You must include this file in all socket applications. macros. File: SYS Member: SOCKET <sys/time. variables.

The SSL protocol is a layered protocol.0. FTP. and SSL Version 3. The OS/400 implementation supports SSL Version 3.SSL programming protocols The Secure Sockets Layer (SSL) is a popular set of security protocols that were originally developed by Netscape Communications Corporation. Secure Sockets Layer APIs Function SSL_Create() SSL_Destroy() SSL_Handshake() SSL_Init() SSL_Read() SSL_Write() Description Enable SSL support for the specified socket descriptor End SSL support for the specified SSL session Initiate the SSL handshake protocol Initialize the current job for SSL Receive data from an SSL-enabled socket descriptor Write data to an SSL-enabled socket descriptor If you plan to use the SSL APIs to create secure-enabled applications.0 with 2. and message forgery. an SSL-enabled browser accesses an SSL-enabled Hypertext Transfer Protocol (HTTP) server with a Universal Resource Locator (URL) that begins HTTPS rather than HTTP. This RFC Engineering Task Force (IETF) defines Transport Layer Security (TLS). The SSL APIs in the OS/400 implementation follow: Table 4. tampering.0. SMTP. SSL provides communications privacy over the Internet. SSL Version 2. The protocol allows client/server applications to communicate in a way that is designed to prevent eavesdropping. among others. but they are not identical. and Telnet.0 protocol. The OS/400 implementation does not support a new Request for Comment (RFC) that is progressing through the Internet RFC process to become a standard. The OS/400 SSL APIs support server and client authentication. For example. The TLS protocol is based heavily on the SSL Version 3. (The standard HTTP server uses port 80).0 compatibility. OS/400 provides a set of SSL APIs. An SSL-enabled application usually needs to use a different port than an application that is not SSL-enabled. you must first obtain and install one of the following licensed programs: v Cryptographic Access Provider 40–Bit (5769-AC1) Chapter 5. An application that uses SSL for secure communications basically is a client/server application that is written using sockets. The SSL APIs allow a client/server application that is written using sockets to use SSL protocol for secure communication. a URL of HTTPS attempts to open a connection to port 443 of the server system. Setting up the socket application environment 43 . Application protocols that require secure communications are HTTP. In most cases. There are multiple versions of the SSL protocol defined. This protocol is used on top of a reliable transport such as Transmission Control Protocol (TCP) to provide secure communications for an application.

Note: Both a server program and the client programs with which it communicates must provide a certificate for an SSL handshake to succeed. It calls connect() to activate a connection for a client program. An application that uses the sockets and SSL APIs contains the following elements: v A call to socket() to obtain a socket descriptor. The SSL_Init() call identifies the key ring file from which the certificate and private key are obtained for all SSL sessions established for a job. to do the following: 1. typically a server. wait for the accept() API to complete) 2. typically a worker. See Secure Sockets Layer (SSL) APIs for more information. A server must also provide the private key that is associated with its certificate or its key ring file. which you can install as part of the OS/400 System Openness Includes option. When you create ILE programs or service programs that use the OS/400 SSL APIs. Some cryptographic objects. to handle all the data transfer operations when the descriptor is open 44 Socket programming . v A call to close() to destroy the connected sockets. QSYS/QSOSSLSR. are required parameters for SSL APIs. v A call to SSL_Create() to enable SSL support for the connected socket. it automatically binds to the SSL service program. and accept() to activate a connection for a server program. you do not need to explicitly bind to the SSL service program. v A call to SSL_Init() to initialize the job environment for SSL processing. v Socket calls to activate a connection. The ILE C language programs provide the use of the SSL APIs. such as key ring files. Passing an open descriptor between jobs allows one process. Allow another process. or it calls bind(). The SSL APIs require some cryptographic objects. Using sendmsg() and recvmsg() to pass descriptors The ability to pass an open descriptor between jobs can lead to a new way of designing client and server applications. which are required in order to use the SSL APIs.v Cryptographic Access Provider 56–Bit (5769-AC2) v Cryptographic Access Provider 128–Bit (5769-AC3) You must also install the OS/400 Openness Includes (5769SS1). listen(). This documentation does not contain information about configuring or obtaining cryptographic objects. An SSL_Init() call must succeed at least once in a job. The SSL APIs use header (include) files from the library QSYSINC. establish a connection. v Calls to SSL_Read() and SSL_Write() to receive and send data. Detailed information about each of the OS/400 SSL APIs is available in the SSL API information. Do everything that is required to obtain the descriptor (open a file. v A call to SSL_Destroy() to disable SSL support for the socket. v A call to SSL_Handshake() to initiate the SSL handshake negotiation of the cryptographic parameters. Because the SSL service program is part of the system binding directory. such as key ring files or certificates.

This design also allows easy support for different types of worker jobs. Setting up the socket application environment 45 . The sendmsg() and recvmsg() APIs offer many advantages over the givedescriptor() and takedescriptor() APIs: v Portability The givedescriptor() and takedescriptor() APIs are nonstandard and unique to AS/400. AS/400 provides these sets of APIs that can pass descriptors between AS/400 jobs: v spawn() v givedescriptor() and takedescriptor() v sendmsg() and recvmsg() The spawn() API starts a new AS/400 job (often called a ″child job″) and gives certain descriptors to that child job. v Performance Applications that use the sendmsg() and recvmsg() APIs tend to perform slightly better than those that use the givedescriptor() and takedescriptor() APIs in these areas: – Elapsed time – CPU utilization – Scalability The amount of performance improvement for an application depends on the extent that the application passes descriptors. such as the following: – What type of descriptor is it? – What should the worker job do with it? The sendmsg() and recvmsg() APIs allow you to transfer data. Typically the worker job obtains the job identifier and transfers it over to the server job with a data queue. only one of the worker jobs receives the descriptor. v Unknown worker job ID The givedescriptor() API requires the server job to know the job identifier of the worker job. you may want to use the sendmsg() and recvmsg() APIs instead. v Communication of control information Often the worker job needs to know additional information when it receives a descriptor. v Pool of worker jobs You may want to set up a pool of worker jobs so that a server can pass a descriptor and only one of the jobs in the pool receives it. v Adaptive server design Chapter 5. which may be control information. When the server calls sendmsg(). or the sendmsg() and recvmsg() APIs.This design results in simpler logic for both the server and the worker jobs. along with the descriptor. use the givedescriptor() and takedescriptor() APIs. The server can make a simple check to determine which type of worker should receive the descriptor. You can use the sendmsg() and recvmsg() APIs to accomplish this by having all of the worker jobs wait on a shared descriptor. The sendmsg() and recvmsg() do not require the extra overhead to create and manage this data queue. If the child job is already active. If the portability of an application between AS/400 and UNIX is important. the givedescriptor() and takedescriptor() APIs do not.

The job that calls sendmsg() does not require any information about the worker job. Use the sendmsg() API to send a descriptor over one of the AF_UNIX sockets created by socketpair(). and recv(). Call spawn() to create a child job that inherits the other end of the socket pair. The server then does a socket(). The child job was not active when the server called sendmsg(). A server can do the following: 1. 3. getsockname(). You can use the sendmsg() and recvmsg() APIs to pass an array of descriptors. and an accept(). it calls recvmsg() and receives the first descriptor and the control data that was in the queue. See “Examples: Establishing communications using the send_file() and accept_and_recv() APIs” on page 136 for the examples concerning the 46 Socket programming . the server pulls off the next available job ID from the data queue. When the accept() API completes.When a server is designed by using the givedescriptor() and takedescriptor(). bind(). you typically use a data queue to transfer the job identifiers from worker jobs over to the server. Problems arise when many incoming connection requests are occuring at once and not enough worker jobs are available. An example of how you can use the sendmsg() API to pass a descriptor to a job that does not exist follows. Pass more than one descriptor at a time: The givedescriptor() and takedescriptor() APIs allow only one descriptor to pass at a time. The child job calls recvmsg() to receive the descriptor that the server passed. Use the socketpair() API to create a pair of AF_UNIX sockets. In many environments. The accept_and_recv() is a combination of three socket functions: accept(). the descriptor for the incoming connection and any control data are put in an internal queue for the AF_UNIX socket. v Inactive worker job The givedescriptor() API requires the worker job to be active while the sendmsg() API does not. listen(). The sendmsg() API requires only that you set up an AF_UNIX socket connection. If the data queue that contains the worker job identifiers is empty. They do not need to know which worker job is going to handle each incoming connection. When a worker job becomes available. Using send_file() and accept_and_recv() APIs These socket APIs enable faster and easier file transfers over connected sockets. or the server creates additional worker jobs. Servers that use sendmsg() and recvmsg() APIs to pass descriptors remain unhindered during heavy activity. It then passes the inbound connection to that worker job. the server blocks waiting for a worker job to become available. 2. When a server calls sendmsg(). neither of these alternatives are desirable because additional incoming requests may fill the listen backlog. The send_file() verb enables the sending of file data directly from a file system over a connected socket with a single API call. The send_file() and accept_and_recv() APIs are especially useful for file-serving applications such as Hypertext Transfer Protocol (HTTP) servers.

communications configuration that use the send_file() and accept_and_recv() APIs. Chapter 5. Setting up the socket application environment 47 . See the Socket APIs for additional information on the send_file() and accept_and_recv() APIs.

48

Socket programming

Chapter 6. Improving performance of the socket environment
You can enhance the performance of the socket environment in several ways. The following topics provide considerations in planning a socket environment. See the topics listed below for specific details: v v v v v v v “Socket network functions” “Optimal setting of the listen() back_log parameter” on page 51 “sendmsg() and recvmsg() API considerations” on page 51 “Using sockets to signal applications” on page 55 “Returning blocked socket functions” on page 56 “Using select() for I/O multiplexing” on page 57 “Major components of DNS for sockets” on page 57

v “Format of DNS queries and responses for sockets” on page 57 v “When to use IP-to-LU mapping” on page 66

Socket network functions
Socket network functions allow application programs to obtain information from the host, protocol, service, and network files. You can access the information by name, by address, or by sequential processing of the file. Setting up communications between programs that run across networks requires these network functions (or routines). AF_UNIX sockets are not used because they require the communicating programs to exist on the same physical machine. The routines do the following: v Map host names to network addresses v Map network names to network numbers v Map protocol names to protocol numbers v Map service names to port numbers v Convert the byte order of Internet network addresses v Convert Internet address and dotted decimal notation Included in the network routines is a group of routines called resolver routines. These routines make, send, and interpret packets for name servers in the Internet domain, and do name resolution. The resolver routines normally get called by gethostbyname() and gethostbyaddr(), but you can call them directly. For reference information on the network routines, see the Socket APIs. For more information about the files that support the network functions, see the Network function files information. Network function files: The use of the AF_INET sockets depends on the following AS/400 database files:
QUSRSYS QATOCHOST File contents List of host names and the corresponding IP addresses.

© Copyright IBM Corp. 2000

49

QUSRSYS QATOCPP QATOCPS QATOCPN QASOSCFG

File contents List of protocols that are used in the Internet. List of services, and the specific port and protocol that a service uses. List of networks and the corresponding IP addresses. Detailed network configuration information that describes how to correctly access specific systems or networks through a firewall.

The database files above serve the same purpose as the following files found on some other systems: /etc/hosts /etc/protocols /etc/services /etc/networks /etc/socks.conf The network function files contain useful network information that is used by the socket network functions. A set of network functions that affect hosts, protocols, services, and networks uses each file, respectively. For example, the following functions use the hosts file: endhostent() and endhostent_r() gethostbyaddr() and gethostbyaddr_r() gethostbyname() and gethostbyname_r() gethostent() and gethostent_r() sethostent() and sethostent_r() See the Socket APIs for more information on the above functions. The protocols and services files come preloaded with standard information. The protocols file contains a list of valid protocols that are used in the Internet. The services file contains a mapping of services to ports. (There is a limited number of UDP and TCP port numbers that are reserved for well-known services, such as File Transfer Protocol (FTP).) You must load the hosts and networks files with the host names and networks and their corresponding addresses. All of these files may require maintenance to keep their contents up to date. The user interface for managing these files consists of CL commands and Work with displays. You can use the following CL commands to access the host database file: v ADDTCPHTE (Add TCP/IP Host Table Entry) v RMVTCPHTE (Remove TCP/IP Host Table Entry) v CHGTCPHTE (Change TCP/IP Host Table Entry) v RNMTCPHTE (Rename TCP/IP Host Table Entry) v MRGTCPHT (Merge TCP/IP Host Tables) For information on configuring host table information with these commands, see the TCP/IP Configuration and Reference book.

50

Socket programming

v The number and rate of connection requests the server can expect over a given period of time. see the CL Programming book. the system creates them. Does it handle each connection request itself. the system loads the service files and protocol files with entries at first use. or does it pass the actual processing of the connection to a child or worker job? The manner used to handle each connection affects the time that the server takes to handle one connection before it can handle the next one. General machine performance and the manner in which storage pools that are used by the server are allocated may determine how the server performs. sendmsg() and recvmsg() API considerations Following are suggestions to enhance the performance of the sendmsg() and recvmsg() APIs. v The system processor size. The shorter the time it requires. consider the following: v Each connection request in the backlog uses at least 1KB of storage. the smaller you can set the backlog. Chapter 6. To help you determine how much main storage a connection request in the listen back_log parameter uses. The setting of the TCP/IP configuration switch determines which host file is checked first. v Each connection request can use an additional storage amount equal to the size of the TCP receiving buffer. This storage amount is used only if the remote peer (client) sends data after the connection is established and put in the listen backlog. If one does not have the data. Server performance affects how long it takes to accept a connection request. Optimal setting of the listen() back_log parameter The optimal setting of the listen backlog value depends on the following factors: v The manner in which the server processes connection requests. More connection requests coming in over a shorter period of time require a larger backlog value. service.) Installation exit programs determine if the files exist. In addition. Note: You can obtain host data either from the Domain Name System or the OS/400 host database file. then the other is checked. (You can access the configuration switch by using option 12 (Change TCP/IP domain information) on the Configure TCP/IP (CFGTCP) menu. Improving performance of the socket environment 51 . the smaller the backlog value can be. You can determine the TCP receive buffer size by looking at the TCPRCVBUF parameter value on the Change TCP Attributes (CHGTCPA) CL command. and network table commands and their parameters.You can use the following CL commands to access the network database file: v WRKNETTBLE (Work with Network Table Entries) v ADDNETTBLE (Add Network Table Entry) v RMVNETTBLE (Remove Network Table Entry) For specific information on the protocol. If the required files do not exist. This helps determine the listen backlog value. The faster the server performs.

You can write an application that calls recvmsg() to handle the case in which only part of (or none of) the control information is received. The value that is stored in this field shows how many bytes of descriptor data are transferred. v Be careful when you use a single sendmsg() call to pass descriptors and control data over a SOCK_STREAM connection. v The msg_accrightslen field in the message header structure indicates how many descriptors to send or receive. This is usually done by the listening or server job or thread. You may have a blocked recvmsg() that completes only part or none of the control data. descriptors. Then you can use the spawn() API to create a child job that inherits one of the sockets that was created by the socketpair() API. the value stored in the msg_accrightslen field should be 4. the server job must specify the AF_UNIX address that was bound by the worker job. 52 Socket programming . you must establish an AF_UNIX socket connection between the server and the worker jobs. Therefore. and have the worker job issue connect(). The listening or server job usually passes the descriptor to the worker job or thread. a worker process accesses a database file to extract and format information for sending to the remote peer through the socket descriptor and its associated connection. passing descriptors with the sendmsg() and recvmsg() APIs is more complex than using the givedescriptor() and takedescriptor() APIs. This behavior does not occur when you pass descriptors and control data over a SOCK_DGRAM socket. the application should use the recvmsg() API to receive the rest of the control data that was sent. You can use this field only if the address family is AF_UNIX. – Have the server and worker jobs use unconnected AF_UNIX datagram sockets. the system returns an EINVAL errno. v You can use the msg_accrights field in the message header structure to point to an array of descriptors for sending or receiving. If this situation occurs. the worker usually does not perform the connection ″bring-up″ or initiation. As a result of this flexibility. if you pass one descriptor. A few of ways that you can establish this AF_UNIX socket are: – Have the server job listen on an AF_UNIX socket. Use this field only if the address family is AF_UNIX. When you call sendmsg(). After the server and worker jobs each have an AF_UNIX socket. Depending on the design of the server. There are also a number of considerations to be aware of when you use these APIs to pass descriptors between AS/400 jobs: v To pass a descriptor between AS/400 jobs with the sendmsg() and recvmsg() APIs. The descriptor that is passed does not have to be an AF_UNIX socket. The worker job can use recvmsg() to receive it. Each descriptor is 4 bytes in length. It could then receive a response or set of data from the remote peer and update the database accordingly. You can use these APIs to send data buffers.The sendmsg() and recvmsg() APIs are extremely flexible. For example. the server job can use sendmsg() to pass a descriptor. Note: A worker job or a worker thread refers to a process or subprocess (thread) that does data processing by using the socket descriptor. or both. If you pass descriptors and the value in this field is less than 4. – Use the socketpair() API to create a pair of connected AF_UNIX sockets.

msg_iovlen = 0. struct iovec iov[1]. the worker job could receive additional data buffers that were sent after the descriptor was sent. When you use givedescriptor() and takedescriptor().msg_iov = NULL. but before it receives the descriptor.iov_base = buffer. the system maintains the data buffers and the descriptors in separate queues.msg_iov = iov. the worker jobs perform the authority checking and auditing. The return code from sendmsg() or recvmsg() is zero because the system did not send or receive data. msg. Improving performance of the socket environment 53 . When you pass a descriptor only. The system must receive all the data buffers and descriptors from a given sendmsg() with a single recvmsg() call by the worker job.msg_iovlen = 1. The sendmsg() and recvmsg() APIs have additional information concerning errors. It also means that the worker job can receive the descriptor long after the data buffer has been received.iov_len = 0. See “Error information for the sendmsg() API” and “Error information for the recvmsg() API” on page 54 for the details. v When you pass descriptors over a SOCK_DGRAM socket. There are two ways that you can specify a data length of zero in the message header structure: – Pass only one iov vector buffer and set the length of that iov buffer to zero: struct msghdr msg. or vice versa. – Set the msg_iov pointer to NULL and set the msg_iovlen field to zero: struct msghdr msg. v The worker job that calls recvmsg() to receive a descriptor must be running with one of two things: – The same user profile that the server job was running when it called sendmsg() – *ALLOBJ special authority The authority checks what the sendmsg() and recvmsg() APIs do when descriptors passed are similar to those that the givedescriptor() and takedescriptor() APIs do. For example. the server job does the authority checking and auditing. or both. This can cause some unusual behaviors. the system links together the data buffers and the descriptors from a given sendmsg() call. Note: Some systems do not maintain socket implementation descriptors and data buffers in separate queues when you pass them over a SOCK_STREAM socket.v When you pass descriptors over a SOCK_STREAM socket. iov[0]. especially if the nondescriptor data flows are intermixed with the passing of descriptors. Chapter 6. msg. Any data buffer or descriptor that is not received is discarded and reclaimed by the operating system. v The sendmsg() and recvmsg() APIs allow you to pass a descriptor with no data buffer. you must specify the length of the data buffer as zero. This means that the worker job can receive the data buffer. the descriptor. msg. msg. The main difference is that when you use sendmsg() and recvmsg() to pass descriptors. iov[0]. Error information for the sendmsg() API The following list provides assistance in determining whether the sendmsg() API is performing properly.

the value that it returns in the msg_accrightslen field is one of two things: – The total number of descriptors that were sent to this socket that could be received (SOCK_STREAM) – The number of descriptors that were sent with the next datagram (SOCK_DGRAM). and it returns immediately. If the system did not send a descriptor. This number may not match the descriptor number that the server job specified in the msg_accrights field when it called sendmsg(). or a -1 if an error occurred. the buffer that the msg_accrights field points to remains unchanged. If you call sendmsg() and specify a descriptor and 10 bytes of data. the recvmsg() call immediately returns with 0 (bytes of data) and the msg_accrightslen field is 4 (one descriptor). unless one of the following is true: – You specified the length of the data buffer on the recvmsg() call as zero. if you call recvmsg() with a zero data length buffer. If an error 54 Socket programming . the sendmsg() API returns a -1 and sets the errno variable. If the value that was passed for msg_accrightslen is less than the value that is to be returned. only the first three descriptors are returned to the user. The system ignores the error that occurs when the recvmsg() API attempts to receive the descriptor. For example. Check the msg_accrightslen field in the message header structure when the recvmsg() API completes to determine how many descriptors were received. or a -1 if an error occurred. you must receive all the previous data that was sent to this socket prior to calling recvmsg(). sendmsg() returns a 10 if it was successful. the recvmsg() call immediately returns with 0 (bytes of data). – You specified the length of the data buffer on the sendmsg() call as zero.v The sendmsg() API returns with the number of bytes that were sent. the value recvmsg() returns in the msg_accrightslen field is 12. In either case. If you used a SOCK_STREAM connection. v You can use the recvmsg() API to receive a descriptor and a zero length data buffer. v If the recvmsg() API receives a data buffer but no descriptor. These numbers are often different. and the msg_accrightslen field is 0 (no descriptor). The system uses msg_accrightslen field in the message header structure to indicate how many bytes of descriptor data (four bytes for each descriptor) to send. If a descriptor was sent but not received. v When you specify the MSG_PEEK flag on a recvmsg() call. The value returned in the msg_accrightslen field is a multiple of four because each descriptor is 4 bytes in length. if the system sends three descriptors. If the system cannot send a descriptor. v If an error occurs when you use sendmsg() to send one or more descriptors. Error information for the recvmsg() API The following list provides assistance in determining whether the recvmsg() API is performing properly. v If the server job sends five descriptors with a single sendmsg() call and the worker job calls recvmsg() with the msg_accrightslen field set to 12 (three descriptors). it does not block. The sendmsg() API never updates this descriptor. it returns the number of bytes of data that were received. the old value is unchanged. it does not send the associated data buffer. v The recvmsg() API returns the number of bytes that are received. However. v The descriptor number that recvmsg() returns in the msg_accrights field when it completes is the next available number in the descriptor table of that job.

First it must set the process ID or the process group ID as described above for the SIGURG signal. a SIGPIPE signal is delivered to the process that issued the operation that is receiving the errno value. Whenever an application receives [EPIPE] as an errno on a socket function. An application requests the system to send the SIGIO signal in two steps. Improving performance of the socket environment 55 . If an application issues these requests on a listening socket. Chapter 6. To remain compatible with previous releases of the OS/400 implementation. v Issuing an ioctl() call and specifying the FIOSETOWN or the SIOCSPGRP value for the request parameter. If you use a SOCK_DGRAM socket. the operating system reclaims the additional descriptors. or when most anything happens on any type of socket. The application should ensure that it is able to handle receiving a signal before it requests the system to send signals. error conditions.occurs on any of the first three descriptors. For example. the fourth and fifth descriptor that were sent are not checked. newly accepted sockets will also have the same process ID or process group ID as well as the same information with regard to sending the SIGIO signal. the OS/400 implementation uses a default behavior of ignore for the SIGPIPE signal. If you pass the descriptors over a SOCK_STREAM connection. A socket can also generate synchronous signals on error conditions. This ensures that there are no negative effects to the existing applications by the addition of the signals function. v SIGURG is a signal that is sent when you receive out-of-band (OOB) data on a socket for which OOB data is supported. OOB data. v Issue the ioctl() call and specify the FIOASYNC value for the request parameter. This is to inform the system where the application wants the signal delivered. Second. you can condition a socket with an address family of AF_INET and a type of SOCK_STREAM to send a SIGURG signal. This second step requests the system to generate the SIGIO signal. by default the SIGPIPE signal ends the process that received the errno value. On a Berkeley Software Distributions (BSD) implementation. That is. One way to set a signal handler is by issuing the sigaction() call. an additional recvmsg() call is necessary to receive the remaining descriptors. Note that you can do these steps in any order. There are two asynchronous signals that sockets will send to an application. You can do this by setting up signal handlers. v SIGIO is a signal that is sent when normal data. the values set by the requests are inherited by all sockets that are returned to the application from the accept() function. An application requests the system to send the SIGURG signal by one of the following methods: v Issuing a fcntl() call and specifying a process ID or a process group ID with the command parameter value of F_SETOWN. Using sockets to signal applications An application program can request asynchronous notification (request that the system send a signal) when a condition that the application is interested in occurs. the application must do either of the following: v Issue the fcntl() call and specify the F_SETFL command with the FASYNC flag.

Sockets provide a method that enables application programs to issue functions that prevent blocking so that the function returns without delay. Returning blocked socket functions When an application issues one of the socket input functions. Finally. You can do this in one of two ways: v Call fcntl() to turn on the O_NONBLOCK flag v Call ioctl() to turn on the FIONBIO flag When the socket is running in this nonblocking mode.When a signal is delivered to a process that is blocked on a sockets function. A connect() may return with [EINPROGRESS]. an error code of [EWOULDBLOCK] indicates that the call was unsuccessful. it must either poll the descriptors or use the select() call to determine why the signal was received. it returns immediately. the function blocks and does not return until there is data to read. The functions for which this will occur are: v v v v v v v v accept() connect() read() readv() recv() recvfrom() recvmsg() select() v send() v sendmsg() v sendto() v write() v writev() Signals do not provide the application program with a socket descriptor that identifies where the signaled condition actually exists. This allows the application’s signal handler to run. connect() and accept() can block while waiting for connection establishment with the target programs. the function returns with the [EINTR] errno value. and there is no data to read. which means that the connection initiation has started. Similarly. The socket functions that can block are: v accept() v v v v v read() readv() recv() recvfrom() recvmsg() v send() 56 Socket programming . You can then use select() to determine when the connection has completed. an application can block a socket output function when it cannot send data immediately. For all other functions that are affected by running in the nonblocking mode. if it cannot complete a function without blocking. If the application program is using multiple socket descriptors.

The DNS has these major components: v Domain name space and resource records: Specifications for a tree-structured name space and the data associated with the names v Name servers: Server programs that hold information about the domain tree structure and that set information. see Request for Comment (RFCs) 1034 and 1035. see the API by category information. The global information used by these routines is kept in the _res structure. see Sockets APIs. Chapter 6. For a description of the individual network routines. You can use these routines to make. v Resolvers: Programs that extract information from name servers in response to client requests. and perform name-caching for performance. or any other object that is represented by a descriptor. select() allows an application to specify sets of descriptors to do the following: v To determine whether there is data to read v To determine whether there is data to write v To determine whether an exception condition is present. send. They also provide function for ASCII-to-EBCDIC and EBCDIC-to-ASCII conversion.v v v v sendmsg() sendto() write() writev() Using select() for I/O multiplexing When an application wants to wait for multiple conditions at the same time. Improving performance of the socket environment 57 . The resolvers provided in the OS/400 implementation are socket functions that provide communication with a name server. it needs a common point at which it can wait. Major components of DNS for sockets AS/400 systems provide applications with access to the Domain Name System (DNS) through the resolver functions. The select() function is that common point. Format of DNS queries and responses for sockets This information provides a view of the formats for the queries and responses that are used between Domain Name System (DNS) functions (routines). The select() function also allows the application to specify if it wants to wait for data to become available. and interpret packets. The descriptors that you can specify in each set can be socket descriptors. For information on the _res structure. The application can specify how long to wait. For more information on domain names. file descriptors.

Name compression reduces the size of the messages. This scheme replaces an entire domain name with a pointer to a prior occurrence of the same name. (Their presence depends on the type of message. A 58 Socket programming . There are two common methods that enable faster query and response times.) The question section contains fields that describe a question to a name server. The additional records section holds information that relates to the query. while caching data lessens the amount of network traffic. Name compression: To reduce the size of messages. The authority section points toward an authoritative name server. The answer section holds the answer to the question. the DNS uses a compression scheme that eliminates the repetition of domain names in a message. but is not strictly an answer for the question.All message packets have a single format divided into five sections as shown in the following figure: The header section is always present and specifies which of the remaining sections are present.

The OFFSET field specifies an offset from the start of the message. This compression scheme allows one of the following forms to represent domain names in a message: v A sequence of labels that end in a NULL v A pointer v A sequence of labels that end in a pointer For example.IBM. a message may use the following three domain names: RCHLAND. Improving performance of the socket environment 59 .RCHLAND.COM RCHNAME.pointer eliminates repetition in the labels list.COM Chapter 6.COM IBM. The following figure shows the pointer format. A zero offset would specify the first byte of the ID field in the header. The first two bits are always on.IBM.

The following figure is an example of how compression might represent these names with all other fields ignored: 60 Socket programming .

If the time to live has expired.RCHLAND.IBM. the system never checks the cache for the answer.options.IBM. the system does not cache responses that are received as a result of an inverse query.COM is shown at offset 20. Chapter 6. If you set RES_AAONLY (authoritative answers only) in _res.COM is shown at offset 46 followed by a pointer to indicate the location of the full domain name. Caching data: You can cache responses to DNS queries by using OS/400 sockets in an effort to lessen the amount of network traffic.COM is defined at offset 64 as a pointer since it was used previously in its entirety. The cache is updated as needed. Improving performance of the socket environment 61 . it sends the query to the network. the cache is checked for an answer to the query before any attempt to send it on the network is performed. Also. Also. If you do not set RES_AAONLY. the query is always sent on the network. the system returns the answer to the user as the answer to the query. The system does not cache nonauthoritative answers. and the system sends the query to the network. If the system finds the answer and the time to live has not expired. In this case. The system caches answers from the network if the responses are authoritative. the entry is removed. if the system does not find the answer in the cache. The domain name for RCHNAME. The domain name for IBM.The domain name for RCHLAND.

A 1-bit field specifying whether this message is a query (0) or a response (1). This bit is set if the responding name server is an authority for the domain name in the question section. It is set by the originator of the query and copied to the response. QR OPCODE A 4-bit field specifying the kind of query in the message. The possible values defined in the <arpa/nameser. The system copies the ID to the corresponding reply and can use it to match up replies to queries. The contents of the answer section may have multiple 62 Socket programming .Format of the DNS header section for sockets The header section of the Domain Name System (DNS) is always present in the packet.h> header file are as follows: 0 1 2-15 AA A standard query (QUERY) An inverse query (IQUERY) Reserved for future use A 1-bit field containing the authoritative answer. The following figure shows the fields in the header format. ID A 16-bit field containing the identifier assigned by the program that generates the query.

The name server was unable to process this query due to a problem with the name server. TC RD RA Z A 1-bit field specifying whether this message was truncated due to a length greater than that permitted on the transmission channel. RCODE A 4-bit field to specify the response code.owner names because of aliases.The name server was unable to interpret the query.h> header file are as follows: 0 1 2 3 4 5 6-15 NOERROR . If set. ARCOUNT An unsigned 16-bit field specifying the number of resource records in the additional records section. If it is zero. NOTIMP . If it is zero. there is no authority section. it directs the name server to pursue the query recursively. A 1-bit field that specifies whether or not you want recursion. Possible values that are defined in the <arpa/nameser. If it is zero. ANCOUNT An unsigned 16-bit field specifying the number of resource records in the answer section. A 1-bit field that is set or cleared in a response denoting whether recursive query support is available in the name server. FORMERR . You must set this field to zero. If it is zero. NXDOMAIN .The name server does not support the requested kind of query.This code signifies that the domain name in the query does not exist.No error condition. REFUSED . Usually.The name server refuses to perform the specified operation for policy reasons. there is no answer section. SERVFAIL . NSCOUNT An unsigned 16-bit field specifying the number of name server resource records in the authority section. there is no question section. this section contains one entry for the QDCOUNT Chapter 6. A 3-bit field reserved for future use. The AA bit corresponds to the name that matches the query name or the first owner name in the answer section. there is no additional records section. Format of the DNS question section for sockets The following figure shows the format of the question section for the Domain Name System (DNS). QDCOUNT An unsigned 16-bit field specifying the number of entries in the question section. Reserved for future use. Improving performance of the socket environment 63 .

QTYPE A 16-bit field that specifies the type of query. QNAME A variable-length field specifying a domain name represented in a sequence of labels. Possible values are as follows: T_A Host address.field in the format shown. T_HINFO Host information. T_ANY Wildcard match. QCLASS A 16-bit field specifying the class of the query. No padding is used in this field. These labels consist of a length followed by that number of bytes. Possible values are as follows: C_IN ARPA Internet. T_SOA Start of authority zone. T_NS Authoritative server. T_PTR Domain name pointer. It is ended by hexadecimal zeros. T_WKS Well-known service. T_CNAME Canonical name. 64 Socket programming . T_TXT Text strings. T_MX Mail routing information.

This field will determine the format of RDATA. These are defined in the <arpa/nameser. NAME A variable-length field specifying the domain name to which this resource record pertains. The following figure shows the format for each of those records. Format of the DNS answer. and additional sections for sockets The answer. authority. authority. Chapter 6.C_ANY Wildcard match. Improving performance of the socket environment 65 .h> header file. This format has a variable number of resource records. The number of records is specified in the corresponding count fields of the header. TYPE A 16-bit field that specifies the type of resource record. and additional sections all have the same format for the Domain Name System (DNS).

you have a different minimum number of system-generated (wildcard) characters in the LU name. RDATA A variable-length string that describes the resource record. you essentially allow the system to do the mapping according to a predictable pattern. and C networks. When to use IP-to-LU mapping Algorithmic mapping is an alternative to using one-to-one mappings. Consider the algorithmic version of IP-to-LU mapping only if you are willing to rename or add LU names.1.1. Your IP addresses for SNA (the IP subnetwork used for SNA LU names) follow a pattern. if you are going to use IP addresses 193. and NAME03. (for instance.CLASS A 16-bit field specifying the class of data in RDATA. The TYPE and CLASS fields determine the format. (The class A address has more bits of the IP address assigned to the host identifier portion than the class B address). Internet addresses have two parts: v A network identifier v A host identifier on the network The 4-byte address is divided between the network identifier and the host identifier in three ways according to the class and size of the network. The question mark character in the AnyNet/400 mapping commands (location template (LOCTPL) parameter) represents these system-generated characters. TTL A 32-bit field specifying the number of seconds this resource record may cache before discarding it. 193. Do not use algorithmic IP-to-LU mapping if you want to maintain existing logical unit (LU) names that you have on a network. These are defined in the <arpa/nameser. use the one-to-one mapping version.2. you could use the algorithmic version. Algorithmic mapping Depending on the class of your IP address. With algorithmic mapping. 66 Socket programming .1. and 193. Use algorithmic IP-to-LU mapping only if both the following are true. If your LU names do not follow a pattern.1. NAME02. and LONDON).1. The host identifier portion of the IP address varies by class. NEWYORK. RDLENGTH A 16-bit field specifying the length of RDATA. To preserve existing LU names that do not follow a predictable pattern.1. For example. These characters represent the positions in the LU name that will vary depending on the IP address that is used in this algorithm. PARIS. 1.h> header file. The following table shows how the address is divided for class A. you could use the algorithmic version.1. B. use one-to-one mapping. For example. if your LU names were NAME01. The LU names you plan to use for IP over SNA follow a pattern that includes an unchanged part and a variable part.3 for IP over SNA. 2.

you can use these commands to determine how the mapping is done. The location-name template is a 3-to-8-character template used by the system for generating location (LU) names that are based on the IP address specified on socket system calls.191 192 . An example follows: ADDIPSLOC RMTDEST('192. Each question mark character represents a single character that is generated by the system.255. therefore. 3 Host ID Bytes 2.127 128 . 2. the following location-name templates are valid: v ABCD???? v A??????? v AB??CD?? v A?B?C?D? Use the Add IP over SNA Location (ADDIPSLOC) command to configure IP-to-LU mapping.Class and size of network Class A (Large) Class B (Medium) Class C (Small) Range 1 . For example.0') + SUBNETMASK('255.223 Network ID Byte 1 Bytes 1.191 192 . Improving performance of the socket environment 67 . this is a class C IP address.1. 4 Byte 4 For example. The system generates the remaining characters based on the class of the IP address.255. You can use a question mark anywhere within the location-name template except in the first character position.127 128 . As a general practice. The network identifier is 125. for a Class B network. do either or both of the following: Chapter 6. If your mapping is not successful.223 A question mark character (?) identifies system-generated location-name characters. The template must specify some of the characters for the location name. The host identifier is 1.3. When you have entered at least one ADDIPSLOC command.2. 125.3 identifies a unique Internet address within a class A network.2. 2 Bytes 1.1.2. use the Convert IP Address into Network Identifier/Location Name (CVTIPSIFC) command and the Convert Network Identifier/Location Name into IP Address (CVTIPSLOC) command to see if you can map the IP addresses to LU names or vice versa. 4 Bytes 3. Class and size of network Range User-specified location-name characters 1 to 3 1 to 4 1 to 6 Minimum number of system-generated location-name characters 5 4 2 Class A (Large) Class B (Medium) Class C (Small) 1 .0') + LOCTPL('NAME??') The example shows two system-generated characters in the location template (LOCTPL) parameter. 3.

O. Another case where the algorithm may not work is when the host portion of the IP address is not large enough to accommodate the characters in your LU name. Do this if the system-generated part of your LU names contains characters not returned by the algorithm (the letters E.v Remove your mapping entry (by using the Remove IP over SNA Location (RMVIPSLOC) command) and add a new entry (by using the Add IP over SNA Location (ADDIPSLOC) command). v Use some one-to-one mapping entries in addition to or instead of algorithmic entries. I. and U). 68 Socket programming .

v Socket configuration The socket configuration examples show how to configure the following Internet Protocol (IP) and Systems Network Architecture (SNA) environments: – A single IP network and single SNA network – A multiple IP networks and multiple SNA networks – A change to an existing configuration v Socket API and SSL These examples contain C programs that use the AS/400 sockets APIs. Examples: Using sockets These examples represent the most commonly used socket applications while managing to cover a variety of socket environments and connection configurations. The Information Center provides more information concerning general API descriptions and specific socket APIs. The examples in the following table show how to use the sockets APIs in a number of different environments.Chapter 7. Environment Transmission Control Protocol (TCP) Examples provided Additonal information These server program and Connection-oriented client program examples environment information illustrate socket APIs written for a connection-oriented protocol: – TCP server and client – SIOCESNDQ server and client User Datagram Protocol (UDP) The connectionless protocol server and client examples illustrate the sockets APIs that are written for the UDP client and server. You can design a connection-oriented socket server on the AS/400 in a number of ways. 2000 69 . v Telephony domain socket These examples use the telephony domain socket to make a connection and to accept a call. The most common examples are as follows: – Iterative server example – spawn() server and spawn() worker example – givedescriptor() server and takedescriptor() worker example – sendmsg() server and recvmsg() worker example – Multiple accept() server and multiple accept() worker example Connectionless environment information Connection-oriented server designs Connection-oriented server designs information © Copyright IBM Corp.

h> /* String Functions /* String Functions /* Pointer types /* /* /* /* Sockets Telephony address family Error codes Error codes */ */ */ */ */ */ */ int main() { /******************************************************************/ /* Miscellaneous declares */ /******************************************************************/ int xSock. Threadsafe network routines IP multicasting This example code uses the gethosbyaddr_r() API. 70 Socket programming . /******************************************************************/ /* Resolve device name to system pointer */ /******************************************************************/ _SYSPTR pDev.h> <errno. /* Template for resolve */ char pName[]="FRED ". xRC.h> #include <string. #include <stdio. /* Device name */ struct TelResource xResource.h> <nettel/tel. /* System pointer to device */ _RSLV_Template_T xTemp. The AS/400 Secure Sockets Layer (SSL) APIs provide secure communications between a server and a client.h> #include #include #include #include <sys/socket. Use the following code to enable the socket to make the connection with a client. AS/400 SSL AS/400 send_file() and accept_and_recv() v ILE RPG to ILE C sockets These examples are found in chapter 5 of the Who Knew You Could Do That with RPG IV? A SorcererÆs Guide to System Access and More redbook.Environment Examples provided Additonal information This client job works with all five types of servers that are listed in the connection-oriented server designs examples Connection-oriented common This example provides the client code for the client job.h> <sys/ioctl. xLength.h> #include <miptrnam. These examples show how to send and receive multicast datagrams. Example: Making a connection using the telephony domain socket Programs can communicate with each other through a telephony domain socket. /* SIOCSTELRSC structure */ /******************************************************************/ /* Socket address structure */ /******************************************************************/ struct sockaddr_tel xAddr. The AS/400 environment uses the send_file() and accept_and_recv() APIs to transfer the contents of a file between processes on a network.

trResourceList=&pDev xRC=ioctl(xSock.sizeof(xAddr)). return(-1). xTemp./******************************************************************/ /* Buffers */ /******************************************************************/ char pSendBuffer[1024]. /******************************************************************/ /* Open a socket */ /******************************************************************/ xSock = socket(AF_TELEPHONY..trCount=1. return(-1). if (xRC<0) { perror("ioctl() failed").1024. memset(&xResource. close(xSock)."18005551212".sizeof(xResource)).stel_family=AF_TELEPHONY. } /******************************************************************/ /* Send the contents of the send buffer */ /******************************************************************/ xRC=send(xSock.0). if (xSock<0) { perror("socket() failed").0x00.&xResource). xTemp..0).Obj. xResource.. close(xSock).. memcpy(xTemp.pSendBuffer.Name.SOCK_STREAM. _RSLVSP2(&pDev.0x00.stel_addr. 30). pName. return(-1).Type_Subtype = WLI_DEVD. } /******************************************************************/ /* Receive a reply */ /******************************************************************/ Chapter 7. xRC=connect(xSock. xAddr. } /******************************************************************/ /* Associate the socket with a device */ /* . } /******************************************************************/ /* Connect to a remote resource (dial a call) */ /******************************************************************/ memset(&xAddr..issue the ioctl to perform the association */ /******************************************************************/ memset(&xTemp.sizeof(xTemp)). close(xSock).fill in the structure for this request */ /* . xResource. if (xRC<0) { perror("connect() failed").t_addr.. Examples: Using sockets 71 . return(-1). char pRecvBuffer[1024].0x00. if (xRC<0) { perror("send() failed").sizeof(xAddr)).Obj.stel_addr.SIOCSTELRSC.t_len=11. xAddr.(struct sockaddr*)&xAddr. memcpy(xAddr.&xTemp).resolve the device name to a system pointer */ /* .11).Auth = _AUTH_NONE.

} Example: Accepting a connection using the telephony domain socket Programs can communicate with each other through a telephony domain socket. /* Template for resolve */ char pName[]="GEORGE ". resolve the device name to a system pointer */ /* .h> /* String Functions */ /* String Functions */ /* Pointer types */ /* /* /* /* Sockets */ Telephony address family */ Error codes */ Error codes */ int main() { /*********************************************************************/ /* Micellaneous declares */ /*********************************************************************/ int xSock.pRecvBuffer. } /*****************************************************************/ /* . if (xSock<0) { perror("socket() failed"). fill in the structure for this request */ /* .h> <sys/socket. return(-1).. /******************************************************************/ /* Open a socket */ /******************************************************************/ xSock = socket(AF_TELEPHONY.h> <errno. char pRecvBuffer[1024]. if (xRC<0) { perror("recv() failed").SOCK_STREAM.xRC.h> <nettel/tel. close(xSock).next. return(-1).first.h> <miptrnam. return(0).1024. /* SIOCSTELRSC structure */ /*****************************************************************/ /* Socket address structure */ /*****************************************************************/ struct sockaddr_tel xAddr. /* System pointer to device */ _RSLV_Template_T xTemp. #include #include #include #include #include #include #include <stdio..xNewSock. /* Device name */ struct TelResource xResource. /*****************************************************************/ /* Resolve device name to system pointer data areas */ /*****************************************************************/ _SYSPTR pDev. close and return */ /******************************************************************/ close(xSock).0)...xRC=recv(xSock.h> <sys/ioctl.h> <string. issue the ioctl to perform the association */ 72 Socket programming .xLength. Use the following code to enable the socket to accept a connection from the server.. } /******************************************************************/ /* All done..0).finally. /*****************************************************************/ /* Buffers */ /*****************************************************************/ char pSendBuffer[1024].

Type_Subtype = WLI_DEVD. close(xNewSock). xAddr.0x00.0x00. if (xRC<0) { perror("recv() failed").0x00. _RSLVSP2(&pDev. xResource.&xResource). return(-1).trResourceList=&pDev xRC=ioctl(xSock.t_len=TELADDR_LEN.Name. } /*****************************************************************/ /* Send a reply */ Chapter 7.stel_addr.1024. 30)./*****************************************************************/ memset(&xTemp.0). return(-1).sizeof(xAddr)). if (xRC<0) { perror("bind() failed"). return(-1). xTemp.TELADDR_ANY.sizeof(xAddr)). xResource. memcpy(xTemp. } /*****************************************************************/ /* Bind to a local number (using TELADDR_ANY means to accept */ /* calls for any number in the inbound connection list's entries)*/ /*****************************************************************/ memset(&xAddr. close(xSock). close(xSock).Obj. close(xSock). xRC=bind(xSock. if (xRC<0) { perror("listen() failed").0x00. xTemp.Obj.t_addr. pName.sizeof(xTemp)). return(-1).TELADDR_LEN). return(-1). memset(&xResource.pRecvBuffer. close(xSock).sizeof(xAddr)). xNewSock=accept(xSock.&xTemp).Auth = _AUTH_NONE. xAddr. xLength = sizeof(xAddr).SIOCSTELRSC. } /*****************************************************************/ /* Receive some data */ /*****************************************************************/ xRC=recv(xNewSock. if (xNewSock<0) { perror("accept() failed"). close(xSock).trCount=1.sizeof(xResource)).&xLength).(struct sockaddr*)&xAddr. if (xRC<0) { perror("ioctl() failed"). Examples: Using sockets 73 .stel_addr. } /*****************************************************************/ /* Listen for incoming calls */ /*****************************************************************/ xRC=listen(xSock. } /*****************************************************************/ /* Accept an incoming call */ /*****************************************************************/ memset(&xAddr.(struct sockaddr*)&xAddr.stel_family=AF_TELEPHONY.5). memcpy(xAddr.

For example. This command example is based on the assumption that an existing IP network has a network ID of 123.0).5. close(xNewSock). The choice of IP addresses that are shown in the example leaves gaps in the numbering of the IP addresses. The following figure shows an existing SNA network 74 Socket programming . return(-1). if (xRC<0) { perror("send() failed"). close(xNewSock). v The existing LU names do not follow a pattern that would allow the algorithmic-mapping option to map the IP address to LU names.101 and 123.5. The example uses a subnet mask of *HOME (this is the same as *HOST).5.1024.pSendBuffer.5. You can accomplish the IP-to-LU name-mapping in two different ways. You would use this one-to-one mapping option for the following reasons: v You do not want to define new LU names. The gaps allow room for future additions to the network.4.4. close(xSock).100.4. By following a pattern. The example provided uses a one-to-one mapping of IP addresses to LU names.4.4. return(0). you can avoid the confusion that is caused when two systems try to use the same IP addresses. } /*****************************************************************/ /* All done. close both sockets and return */ /*****************************************************************/ close(xSock). while other regions would use IP addresses between 123. You can perform these same functions by using a menu interface initiated by options from the Configure IP over SNA (CFGIPS) menu.200. The other way to is use an algorithm to map portions of the IP address to portions of the LU name. See “When to use IP-to-LU mapping” on page 66 for more information./*****************************************************************/ xRC=send(xNewSock. One way is a one-to-one mapping by specifying a corresponding LU name for each IP address. } Example: Connecting a single IP network with a single SNA network This example lists the commands that you use to configure a single Internet Protocol (IP) network with a single Systems Network Architecture (SNA) network. This mapping means that exactly one IP address makes up each subnetwork group.2 and 123. Allow room for future additions of IP addresses and follow a pattern that makes sense for your network.0. new departments in region 1 would use IP addresses between 123.5.

0 and 255. Performing an AND operation on 123.255.1 through 123.5.4. These are the addresses for the IP to use over SNA support.4.255.5.4.255.254.0 gives a subset of IP network addresses of 123.that the system is to add to the IP network. The command example uses the subnet mask of 255.0.255. Examples: Using sockets 75 .5. Chapter 7. This allows for 253 different IP addresses and up to 253 different SNA LU names.

Each system requires a unique IP address.1') SUBNETMASK(*HOST) RMTNETID(PALLET1) LOCTPL(BLUE1) ADDIPSLOC RMTDEST('123. If you want all systems to be able to communicate with each other.4. On department 1’s system. v The subnet mask.5.4.2') SUBNETMASK(*HOST) RMTNETID(PALLET1) LOCTPL(SILVER1) ADDIPSLOC RMTDEST('123. use the ADDIPSLOC command to map the IP address of that system to its SNA network ID and SNA local LU name.4. use the following commands: ADDIPSIFC INTNETADR('123. For each system in the network. All the systems use the ADDIPSLOC command to allow any system in the network to communicate with any other system in the network.100') SUBNETMASK(*HOST) RMTNETID(PALLET1) LOCTPL(RED1) 76 Socket programming .5. The example shows you how to use of the Add IP over SNA Location (ADDIPSLOC) command to specify these pieces of information: v The IP address that you have assigned to this system. Each system must be able to map both its IP address and the destination IP address to the corresponding LU names.1') SUBNETMASK('255.255.0') ADDIPSLOC RMTDEST('123. all systems must map all IP-over-SNA addresses to the correct LU names.255.5.5.The following figure shows the IP addresses that are assigned to the SNA network.4.

On each system that is configured.100') SUBNETMASK(*HOST) RMTNETID(PALLET1) LOCTPL(RED1) ADDIPSLOC RMTDEST('123.5. the commands listed include a Change Network Attributes (CHGNETA) command to activate the AnyNet support on the AS/400 system.4.2') + SUBNETMASK('255.255.100') SUBNETMASK(*HOST) RMTNETID(PALLET1) LOCTPL(RED1) ADDIPSLOC RMTDEST('123.200') SUBNETMASK(*HOST) RMTNETID(PALLET1) LOCTPL(PURPLE1) CHGNETA ALWANYNET(*YES) On department 2’s system.5.4. Chapter 7.100') SUBNETMASK('255.255.4.4.4.4.5.4.1') SUBNETMASK(*HOST) RMTNETID(PALLET1) LOCTPL(BLUE1) ADDIPSLOC RMTDEST('123.5.5.200') SUBNETMASK(*HOST) RMTNETID(PALLET1) LOCTPL(PURPLE1) CHGNETA ALWANYNET(*YES) On the headquarters’ system.255.ADDIPSLOC RMTDEST('123.0') ADDIPSLOC RMTDEST('123. 2. use the following commands: ADDIPSIFC INTNETADR('123.255. use the following commands: ADDIPSIFC INTNETADR('123.5.1') SUBNETMASK(*HOST) RMTNETID(PALLET1) LOCTPL(BLUE1) ADDIPSLOC RMTDEST('123.4.5. They need to be the same because this example assumes that all nodes have a need to talk to each other. use the following commands: ADDIPSIFC INTNETADR('123.5.2') SUBNETMASK(*HOST) RMTNETID(PALLET1) LOCTPL(SILVER1) ADDIPSLOC RMTDEST('123.4. Example: Connecting multiple IP networks with multiple SNA networks This example lists the commands that you use to configure multiple Internet Protocol (IP) networks with multiple Systems Network Architecture (SNA) networks.200') SUBNETMASK('255.4.5.5.4.0') ADDIPSLOC RMTDEST('123.5.5.200') SUBNETMASK(*HOST) RMTNETID(PALLET1) LOCTPL(PURPLE1) CHGNETA ALWANYNET(*YES) On region 1’s system.4.4.255.100') SUBNETMASK(*HOST) RMTNETID(PALLET1) LOCTPL(RED1) ADDIPSLOC RMTDEST('123.5.200') SUBNETMASK(*HOST) RMTNETID(PALLET1) LOCTPL(PURPLE1) CHGNETA ALWANYNET(*YES) Notes: 1. each set of commands is basically the same.4. You can perform these same functions by using a menu interface initiated by options from the Configure IP over SNA (CFGIPS) menu. Except for the initial Add IP over SNA Interface (ADDIPSIFC) command.1') SUBNETMASK(*HOST) RMTNETID(PALLET1) LOCTPL(BLUE1) ADDIPSLOC RMTDEST('123.0') ADDIPSLOC RMTDEST('123.5.5. Examples: Using sockets 77 .255.5. You can take advantage of these similar commands by shipping a control language (CL) program to each system.4.4.2') SUBNETMASK(*HOST) RMTNETID(PALLET1) LOCTPL(SILVER1) ADDIPSLOC RMTDEST('123.2') SUBNETMASK(*HOST) RMTNETID(PALLET1) LOCTPL(SILVER1) ADDIPSLOC RMTDEST('123.

v Only the NEWYORK system of Company 1 and the NYC system of Company 2 need to contact the other company’s network node (or system). Each company that wants to communicate with IP over SNA has a different IP network ID and a different SNA network ID.3. v Company 2 has an existing IP network with a network ID of 111. Also.2. each company wants to communicate with its network.0.0. as well as with the other company’s network.0.This is a more complicated scenario than connecting a single IP network with a single SNA network. This command example is based on the following assumptions: v Company 1 has an existing IP network with a network ID of 222. 78 Socket programming .4.

The following figure shows the existing SNA network.255.3.127.255. Company 1 uses a subnet mask of 255. To determine IP addresses for the SNA network. Examples: Using sockets 79 .4.128.3. This works out to 126 different IP addresses and up to 126 different Chapter 7.1 through 222. This allows SNA to use IP addresses of 222.4.

255.254. This allows you to use the IP addresses of 111. On Company 1’s San Francisco system.2.0.3. Company 2 will use a subnet mask of 255.3. This provides 253 different IP addresses and up to 253 different SNA LU names. The following figure shows the IP addresses that are given out to the SNA network. use the following commands: 80 Socket programming .SNA LU names.255.1 through 111.2.

2.255.4.7') SUBNETMASK(*HOST) RMTNETID(COMPANY1) LOCTPL(NEWYORK) ADDIPSLOC RMTDEST('222.76') SUBNETMASK(*HOST) RMTNETID(COMPANY1) LOCTPL(HOUSTON) ADDIPSLOC RMTDEST('111.3.7') SUBNETMASK(*HOST) RMTNETID(COMPANY1) LOCTPL(NEWYORK) ADDIPSLOC RMTDEST('222.100') SUBNETMASK(*HOST) RMTNETID(COMPANY2) LOCTPL(HONGKONG) ADDIPSLOC RMTDEST('111.2.128') ADDIPSLOC RMTDEST('222.3.2.3.4.1') SUBNETMASK(*HOST) RMTNETID(COMPANY2) LOCTPL(LONDON) ADDIPSLOC RMTDEST('111.4.4.3.7') SUBNETMASK('255.3. use the following commands: ADDIPSIFC INTNETADR('222.2.1') SUBNETMASK('255.76') SUBNETMASK(*HOST) RMTNETID(COMPANY1) LOCTPL(HOUSTON) CHGNETA ALWANYNET(*YES) On Company 2’s Hong Kong system. Specify the route definition with the Add IP over SNA Route Entry (ADDIPSRTE) command.3. use the following commands: ADDIPSIFC INTNETADR('222.255.16') SUBNETMASK(*HOST) RMTNETID(COMPANY1) LOCTPL(SANFRAN) ADDIPSLOC RMTDEST('222.128') ADDIPSLOC RMTDEST('222.76') SUBNETMASK(*HOST) RMTNETID(COMPANY1) LOCTPL(HOUSTON) CHGNETA ALWANYNET(*YES) On Company 1’s New York system.3.2.3. use the following commands: ADDIPSIFC INTNETADR('111.4.3.2.4.4.3.3.3.255.4.4.3.3.200') SUBNETMASK(*HOST) RMTNETID(COMPANY2) LOCTPL(NYC) ADDIPSRTE RMTDEST('111.255.4.255. Examples: Using sockets 81 .3.0') ADDIPSLOC RMTDEST('111.3.3.255.2.4.2.128') ADDIPSLOC RMTDEST('222.ADDIPSIFC INTNETADR('222.4.255.4. On Company 1’s Houston system.3.246') SUBNETMASK(*HOST) RMTNETID(COMPANY2) LOCTPL(PARIS) CHGNETA ALWANYNET(*YES) On Company 2’s London system. use the following commands: ADDIPSIFC INTNETADR('111.16') SUBNETMASK('255.3.2.255.3.100') SUBNETMASK('255.7') SUBNETMASK(*HOST) RMTNETID(COMPANY1) LOCTPL(NEWYORK) ADDIPSLOC RMTDEST('222.200') SUBNETMASK(*HOST) RMTNETID(COMPANY2) LOCTPL(NYC) Chapter 7.2.76') SUBNETMASK('255.3.16') SUBNETMASK(*HOST) RMTNETID(COMPANY1) LOCTPL(SANFRAN) ADDIPSLOC RMTDEST('222.3.16') SUBNETMASK(*HOST) RMTNETID(COMPANY1) LOCTPL(SANFRAN) ADDIPSLOC RMTDEST('222.3.255.0') ADDIPSLOC RMTDEST('111.255.7') CHGNETA ALWANYNET(*YES) The commands used for the New York system need to include a route definition.200') SUBNETMASK(*HOST) RMTNETID(COMPANY2) LOCTPL(NYC) ADDIPSLOC RMTDEST('111.3.2. The New York system of Company 1 is connected as an intercompany link to the New York system of Company 2.200') SUBNETMASK(*HOST) NEXTHOP('222.100') SUBNETMASK(*HOST) RMTNETID(COMPANY2) LOCTPL(HONGKONG) ADDIPSLOC RMTDEST('111.1') SUBNETMASK(*HOST) RMTNETID(COMPANY2) LOCTPL(LONDON) ADDIPSLOC RMTDEST('111.

3.200') SUBNETMASK('255.100') SUBNETMASK(*HOST) RMTNETID(COMPANY2) LOCTPL(HONGKONG) ADDIPSLOC RMTDEST('111.3.2.7') SUBNETMASK(*HOST) RMTNETID(COMPANY1) LOCTPL(NEWYORK) ADDIPSRTE RMTDEST('222. use the following commands: 82 Socket programming .0') ADDIPSLOC RMTDEST('111.2.2.2.1') SUBNETMASK(*HOST) RMTNETID(COMPANY2) LOCTPL(LONDON) ADDIPSLOC RMTDEST('111. Consider data security when passing data between separate companies. use the following commands: ADDIPSIFC INTNETADR('111. To do this.3.3.2. Assume that the change you want to make is to allow the PARIS system in Company 2 to connect to the HOUSTON system in Company 2. the application itself needs to provide security for the data.3.2. The coding information that changes in this example originates from the coding information in those examples.1') SUBNETMASK(*HOST) RMTNETID(COMPANY2) LOCTPL(LONDON) ADDIPSLOC RMTDEST('111.2. On Company 2’s Paris system.2.3.3.255.2.3.7') SUBNETMASK(*HOST) NEXTHOP('111.4.2.4. Specify the route definition with the Add IP over SNA Route Entry (ADDIPSRTE) command.246') SUBNETMASK(*HOST) RMTNETID(COMPANY2) LOCTPL(PARIS) CHGNETA ALWANYNET(*YES) On Company 2’s New York system.3.255. use the following commands: ADDIPSIFC INTNETADR('111.ADDIPSLOC RMTDEST('111.3.200') SUBNETMASK(*HOST) RMTNETID(COMPANY2) LOCTPL(NYC) ADDIPSLOC RMTDEST('111. The first thing to do is have the PARIS system start a connection to the HOUSTON system.3.100') SUBNETMASK(*HOST) RMTNETID(COMPANY2) LOCTPL(HONGKONG) ADDIPSLOC RMTDEST('111.3.200') CHGNETA ALWANYNET(*YES) Just as with Company 1.255. the New York system of Company 2 needs to include a route definition. Example: Changing a configuration This example lists the commands that you use to change configuration functions.246') SUBNETMASK(*HOST) RMTNETID(COMPANY2) LOCTPL(PARIS) CHGNETA ALWANYNET(*YES) Note: This example shows connections for passing data between Company 1 and Company 2. Read the “Example: Connecting a single IP network with a single SNA network” on page 74 or “Example: Connecting multiple IP networks with multiple SNA networks” on page 77 examples before reading this one.3.246') SUBNETMASK(*HOST) RMTNETID(COMPANY2) LOCTPL(PARIS) ADDIPSLOC RMTDEST('222. When you use both an SNA network and an IP network.2.2. You can perform these same functions by using a menu interface initiated by options from the Configure IP over SNA (CFGIPS) menu.200') SUBNETMASK(*HOST) RMTNETID(COMPANY2) LOCTPL(NYC) ADDIPSLOC RMTDEST('111.255.3.0') ADDIPSLOC RMTDEST('111.246') SUBNETMASK('255. Session-level security is available within an SNA network.

2.7') SUBNETMASK(*HOST) NEXTHOP('111. To do this.2.246') SUBNETMASK(*HOST) NEXTHOP('222.7') Examples: TCP connection-oriented client/server introduction These server and client examples illustrate socket APIs written for a connection-oriented protocol such as Transmission Control Protocol (TCP).246') SUBNETMASK(*HOST) RMTNETID(COMPANY2) LOCTPL(PARIS) ADDIPSRTE RMTDEST('111. including those used by SIOCSENDQ.4.246') Have the HOUSTON system start a connection to the PARIS system.3.4.3.2.v Use the following command to tell the PARIS system what SNA NETID and LU name to use: ADDIPSLOC RMTDEST('222. use the following command: ADDIPSRTE RMTDEST('222. use the following commands: ADDIPSLOC RMTDEST('111.3.3. Examples: Using sockets 83 .4.3.3. The TCP server example and SIOCESNDQ server example use the following sequence of function calls: v socket() v bind() v listen() v accept() The TCP client example and SIOCESNDQ client example use the following sequence of function calls: v socket() v connect() Chapter 7. To do this.76') SUBNETMASK(*HOST) RMTNETID(COMPANY1) LOCTPL(HOUSTON) v Tell the PARIS system that the remote destination is in the SNA network but not in the IP subnetworks that are defined by the IP-over-SNA interfaces.

h> #include <stdlib. */ /* File contain Macro. Examples: Connecting a TCP server and client Following are connection-oriented examples where sockets use TCP to connect a server to a client. Data Type and Structure */ /* definitions along with Function prototypes.h> /* in qsysinc library */ #include <sys/time.h> #include <errno. Example: Connecting a TCP server to a client /***********************************************/ /* Header files needed to use the sockets API. */ /***********************************************/ /* in qcle/h file */ #include <stdio.h> 84 Socket programming .h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> #include <string. and a client to a server.The following figure illustrates the client/server relationship of the sockets API for a connection-oriented protocol.

} /**********************************************/ /* The setsockopt() function is used to allow */ /* the local address to be reused when the server */ /* is restarted before the required wait time */ /* expires. char temp. rc.sin_addr. The statement also */ /* identifies that the INET (Internet Protocol) */ /* address family with the TCP transport (SOCK_STREAM) */ /* will be used for this socket. which allows the system to */ /* connect to any client that used port 3005. timeout. char buffer[BufferLength]. In this example. struct timeval timeout. on = 1. /**********************************************/ /* The socket() function returns a socket descriptor */ /* representing an endpoint. /************************************************/ /* After the socket descriptor is created. serveraddr. */ Chapter 7. struct sockaddr_in serveraddr. length = sizeof(int). serveraddr. Examples: Using sockets 85 . fd_set read_fd. 0)) < 0) { perror("socket() failed").s_addr = htonl(INADDR_ANY). exit(-1). sizeof(on))) < 0) { perror("setsockopt() failed").tv_sec = 10. exit(-1). the user sets the */ /* s_addr to zero. sizeof(struct sockaddr_in)). */ /* socket. int totalcnt = 0. 0x00.sin_port = htons(SERVPORT). close(sd). a bind() */ /* function gets a unique name for the socket./* BufferLength is 250 bytes #define BufferLength 250 /* Server port number */ #define SERVPORT 3005 */ void main() { /*********************************************/ /* Variable and structure definitions. timeout. */ /*********************************************/ int sd. */ /************************************************/ /* Get a socket descriptor */ if ((sd = socket(AF_INET.tv_usec = 0. sd2. */ /***********************************************/ /* Allow socket descriptor to be reuseable */ if ((rc = setsockopt(sd. SOL_SOCKET. serveraddr. } /* bind to an address */ memset(&serveraddr. SOCK_STREAM. SO_REUSEADDR.sin_family = AF_INET. (char *)&on.

*/ /***********************************************/ /* Wait for up to 10 seconds on */ /* select() for data to be read. exit(-1). This means that the */ /* system can queue 10 connection requests before */ /* the system starts rejecting incoming requests. close(sd). provided the */ /* connection request does the following: */ /* .NULL. FD_SET(sd2. NULL)) < 0) { perror("accept() failed").&timeout). rc = select(sd2+1.&read_fd.Uses streams sockets (TCP) */ /* . */ FD_ZERO(&read_fd).&read_fd)) ) { /* Read data from the client. close(sd). if ( (rc == 1) && (FD_ISSET(sd2. */ /* the backlog is set to 10. In this */ /* example. sizeof(serveraddr))) < 0) perror("bind() failed"). } /***********************************************/ /* The select() function allows the process to */ /* wait for an event to occur and to wake up */ /* the process when the event occurs. } /*************************************************/ /*The listen() function allows the server to accept */ /* incoming client connections.Attempts to connect to the specified port */ /***********************************************/ /* accept() the incoming connection request. the system notifies the process */ /* only when data is available to read. use the read() function to read */ /* 250 bytes of the character a's that the */ /* client sent.{ /*************************************************/ if ((rc = bind(sd (struct sockaddr *)&serveraddr. while(totalcnt < BufferLength) { /***********************************************/ /* When select() indicates that there is data */ /* available. exit(-1). close(sd).\n"). /***********************************************/ /* The server will accept a connection request */ /* with this accept() function. */ if ((sd2 = accept(sd.NULL. 10)) < 0) { perror("listen() failed"). exit(-1). (struct sockaddr *)NULL.*/ /*************************************************/ /* Up to 10 clients can be queued */ if ((rc = listen(sd. } printf("Ready for client connect(). */ /***********************************************/ 86 Socket programming . In this example.&read_fd).Is part of the same address family */ /* . */ totalcnt = 0.

exit(-1). &temp.\n"). close(sd2). close(sd). if (rc < 0) { perror("read() failed"). &length). close(sd2). */ /************************************/ /* write() the 250 bytes of 'a's */ /* back to the client. } else if (rc == 0) { printf("partner program has issued a close()"). */ rc = write(sd2. if (rc == 0) { /********************************/ /* Print out the asynchronously */ /* received error. close(sd2). } else totalcnt += rc. exit(-1). if (rc != totalcnt) { perror("write() failed"). /* Get the error number. close(sd2). close(sd). BufferLength-totalcnt). */ /********************************/ errno = temp. buffer. SO_ERROR. exit(-1). Examples: Using sockets 87 . */ rc = getsockopt(sd2. close(sd2). /************************************/ /* Echo the 250 bytes of a's back */ /* to the client by using the write() */ /* function. exit(-1).} } else if (rc < 0) { perror("select() failed"). close(sd). &buffer[totalcnt]. perror("SO_ERROR was"). totalcnt). } else /* rc == 0 */ { printf("select() timed out. } /* read() from client */ rc = read(sd2. SOL_SOCKET. } close(sd). } /*****************************************/ Chapter 7. close(sd). exit(-1).

h> #include <string. char temp. 'a'. char server[255].h> /* in qsysinc library */ #include <sys/types.h> #include <errno.h> #include <unistd. Data Type and */ /* Structure definitions along with Function */ /* prototypes. int totalcnt = 0. /* will send 250 bytes of 'a' */ memset(buffer.h> #include <netinet/in. exit(0). or */ /* set the server name in the #define */ /* SERVER. 250). */ /*****************************************/ /* Close the connection to the client and */ /* close the server listening socket. close() */ /* the socket descriptor that was returned */ /* from the accept() verb and close() the */ /* original socket descriptor. 88 Socket programming . */ /***********************************************/ /* in qcle/h file */ #include <stdio. length = sizeof(int). Example: Connecting a TCP client to a server The following example shows how to connect a socket client program to a connection-oriented server. char buffer[BufferLength]. */ void main(int argc. close(sd). struct sockaddr_in serveraddr. rc.} /* When the data has been sent.h> #include <netdb.h> #include <arpa/inet. char *argv[]) { /****************************************/ /* Variable and structure definitions.h> /* BufferLength is 250 bytes #define BufferLength 250 */ /* Host name of server system */ #define SERVER "SERVERHOSTNAME" /* Server's port number */ #define SERVPORT 3005 /* Pass in 1 parameter which is either the */ /* address or host name of the server. */ /******************************************/ close(sd2). struct hostent *hostp. */ /* File contains Macro.h> #include <sys/socket.h> #include <stdlib. /***********************************************/ /* Header files needed to use the sockets API. */ /****************************************/ int sd.

*/ /* The statement also identifies that the */ /* INET (Internet Protocol) address family */ /* with the TCP transport (SOCK_STREAM) */ /* will be used for this socket. memset(&serveraddr. argv[1]). */ Chapter 7. } memcpy(&serveraddr. Examples: Using sockets 89 . */ if ((rc = connect(sd. exit(-1). serveraddr. } /*********************************************/ /* Send 250 bytes of a's to the server using */ /* the write() function. */ /*********************************************/ /* Write() 250 'a's to the server.s_addr = inet_addr(server)) == (unsigned long)INADDR_NONE) { /*************************************************/ /* When passing the host name of the server as a */ /* parameter to this program. } if (argc > 1) strcpy(server. use the gethostbyname() */ /* function to retrieve the address of the host server. if ((serveraddr. else strcpy(server. close(sd).sin_addr.sin_addr)). 0x00.sin_addr. */ /***********************************************/ /* Connect() to server. SERVER). sizeof(serveraddr. SOCK_STREAM. /* h_errno is usually defined */ /* in netdb. serveraddr.sin_port = htons(SERVPORT). */ /***************************************************/ /* get host address */ hostp = gethostbyname(server). exit(-1). 0)) < 0) { perror("socket() failed"). } /***********************************************/ /* After the socket descriptor is received. sizeof(struct sockaddr_in)).h_errno). (struct sockaddr *)&serveraddr.sin_family = AF_INET. hostp->h_addr. the */ /* connect() function is used to establish a */ /* connection to the server. sizeof(serveraddr))) < 0) { perror("connect() failed"). if (hostp == (struct hostent *)NULL) { printf("HOST NOT FOUND --> "). */ /******************************************/ /* get a socket descriptor */ if ((sd = socket(AF_INET. exit(-1)./******************************************/ /* The socket() function returns a socket */ /* descriptor representing an endpoint.h */ printf("h_errno = %d\n". close(sd).

close() */ /* the socket descriptor. SOL_SOCKET. while(totalcnt < BufferLength) { /***************************************/ /* Wait for the server to echo the 250 */ /* bytes of a's back by using the */ /* read() function. buffer. if (rc == 0) { /* Print out the asynchronously */ /* received error. SO_ERROR. } close(sd). exit(-1).h> #include <sys/socket. } else if (rc == 0) { printf("partner program has issued a close()"). sizeof(buffer)). close(sd).h> #include <stdlib. BufferLength-totalcnt). } else totalcnt += rc. &length). if (rc < 0) { perror("write() failed"). } Examples: Connecting an SIOCSENDQ server and client Following are socket server program examples that use TCP. perror("SO_ERROR was"). it should use an application-level acknowledgement.h> 90 Socket programming . the SIOCSENDQ server does not perform an application-level acknowledgement for the receipt of data. */ /***************************************/ /* Read data from the server. close(sd). rc = getsockopt(sd.rc = write(sd. } /****************************************/ /* When the data has been read. */ rc = read(sd. exit(-1). &temp. } totalcnt = 0. If it did have control. */ errno = temp. exit(0). This is to simulate a SCIOSENDQ client that uses a server that it has no control over from a programming standpoint. if (rc < 0) { perror("read() failed"). Example: Connecting an SIOCSENDQ server to a client #include <stdio. In this example. &buffer[totalcnt]. exit(-1). */ /****************************************/ /* Close socket descriptor from client side. */ close(sd).

int listen_sd. (struct sockaddr *)&addr. 0). The statement also */ /* identifies that the INET (Internet Protocol) */ /* address family with the TCP transport (SOCK_STREAM) */ /* will be used for this socket. close(listen_sd). } /******************************************/ /* Bind the socket */ /******************************************/ memset(&addr. addr. } /*********************************************/ /* Inform the user that the server is ready */ /*********************************************/ printf("The server is ready\n"). close(listen_sd). addr. } /*******************************************/ /* Set the listen backlog */ /* The listen() function allows the server */ /* to accept incoming client */ /*******************************************/ rc = listen(listen_sd. if rc < 0 /*******************************************/ /* After the socket descriptor is created. 0. exit(-1). if (rc < 0) { perror("listen() failed").sin_addr. /*****************************************/ /* The socket() function returns a socket descriptor */ /* representing an endpoint.sin_family = AF_INET. /*****************************************/ /* Create an AF_INET stream socket to receive */ /* incoming connections on */ /******************************************/ listen_sd = socket(AF_INET. exit(-1).s_addr = htonl(INADDR_ANY). */ /* a bind() function is done to get */ /* a unique address for the socket. 5). exit(-1). SOCK_STREAM. accept_sd.sin_port = htons(SERVER_PORT). /*******************************************/ Chapter 7. sizeof(addr)). Examples: Using sockets 91 . char *argv[]) { int rc. */ /*******************************************/ if (listen_sd < 0) { perror("socket() failed"). char buffer[0x10000]. sizeof(addr)). rc = bind(listen_sd. /* 64K */ struct sockaddr_in addr. addr.h> #define SERVER_PORT 12121 main(int argc.#include <netinet/in. */ /*******************************************/ { perror("bind() failed").

0). NULL). */ /*********************************************/ { rc = recv(accept_sd.h> <netinet/in. close(listen_sd). close(accept_sd). } printf("Received %d bytes\n". the server program does not perform application-level acknowledgement for the receipt of data. /********************************************/ /* To assist in the purpose of this example. sizeof(buffer). This is done in a */ /* loop as all of the data may not have arrived */ /* at the time of the first recv(). In this example. #include #include #include #include <stdio. if (accept_sd <0) { perror("accept() failed").h> <stdlib. /**************************************/ /* Close down the incoming connection */ /* and the connected socket descriptor */ /*************************************/ close(accept_sd). exit(-1).h> <sys/socket. exit(-1). do /*********************************************/ /* The recv() function will receive the data */ /* sent from the client. NULL. /**********************************************/ sleep (1) /**********************************************/ /* Receive a message from the client */ /**********************************************/ printf(" wait for client to send us a message\n").h> 92 Socket programming . /*******************************************/ /* The server accepts a connection request */ /* with this accept() function */ /*******************************************/ accept_sd = accept(listen_sd. }while (rc !=0)./* Wait for an incoming connection */ /*******************************************/ printf("Waiting on accept()\n"). if (rc < 0) { perror("recv() failed"). rc). buffer.*/ /* the server sleeps 1 second before it continues.*/ /* This gives the client a chance to issue the */ /* send() function first. close(listen_sd). } Example: Connecting an SIOCENDQ client to a server The following is a socket client program example that uses TCP and the SIOCENDQ ioctl(). } printf(" accept completed successfully\n"). /*************************************/ /* Close down the listen socket and */ /* listen socket descriptor */ /*************************************/ close(listen_sd).

0).h> #define SERVER_PORT 12121 { main(int argc. Examples: Using sockets 93 . /* 64K */ struct sockaddr_in addr. /****************************************/ /* Send data buffer to the server job. SOCK_STREAM. addr. addr. bufflen. rc. int sockfd. exit(-1). 0. exit(-1). */ /* Send the data to the server using the */ /* send() function. close(sockfd). sizeof(addr)). exit(-1). /****************************************/ Chapter 7. /****************************************/ /* Create an AF_INET stream socket. buffer.#include <sys/ioctl.*/ /* The statement also identifies that the */ /* INET (Internet Protocol) address family */ /* with the TCP transport (SOCK_STREAM) */ /* will be used for this socket */ /****************************************/ sockfd = socket(AF_INET. sizeof(struct sockaddr_in)).s_addr = htonl(INADDR_ANY). if (rc < 0) { perror("connect").sin_port = htons(SERVER_PORT).sin_addr. close(sockfd). len). The connect() */ /* function is used to establish a connection */ /* to the server */ /****************************************/ rc = connect(sockfd. */ /****************************************/ len = send(sockfd. (struct sockaddr *)&addr. } printf("Connect completed.\n"). int bufflen. } /****************************************/ /* Initialize the socket address structure */ /****************************************/ memset(&addr. The */ /* socket() function returns a socket */ /* descriptor that represents an endpoint.sin_family = AF_INET. }printf("%d bytes sent\n". char *argv[]) int len. addr. /****************************************/ /* Initialize buffer length field */ /****************************************/ bufflen = sizeof(buffer). 0). if sockfd < 0) { perror("socket"). char buffer[0x10000]. /****************************************/ /* Connect to the server. if (len !=bufflen) { perror("send").

&len). SIOCSENDQ.\n". if (rc < 0) { perror("ioctl(SIOCSENDQ)")./* verify data send has reached remote driver */ /****************************************/ do { /****************************************/ /* After the send. /****************************************/ /* The process sleeps for one second each */ /* iteration of the loop that does not have */ /* a len of 0. */ /****************************************/ close(sockfd). else { printf("%d bytes yet to be acknowledged. The server example and client example use the following sequence of function calls: v socket() v bind() 94 Socket programming . exit(-1). } if (len == 0) printf("All data acknowledged by remote driver. close(sockfd). */ /* close() the socket descriptor.\n"). */ /****************************************/ sleep(1). /****************************************/ /* Close down the socket. issue an ioctl(SIOCSENDQ) */ /* call to determine if the sent data has */ /* been acknowledged by the remote TCP */ /* driver. len). NOTE: In a real application. */ /* alternate processing could be performed */ /* at this time instead of a sleep. } } while (len !=0). } Examples: UDP connectionless client/server introduction The connectionless protocol server and client examples illustrate the socket APIs that are written for User Datagram Protocol (UDP). This example has the ioctl performed */ /* in a loop until all data has been acknowledged */ /****************************************/ rc=ioctl(sockfd. After the data */ /* has been acknowledged by the remote side. NOTE: In */ /* a real application. the program would */ /* probably continue on to another unit of */ /* work with this socket.

*/ /***********************************************/ /* in qcle/h file */ #include <stdio. rc. /***********************************************/ /* Header files needed to use the sockets API.The following figure illustrates the client/server relationship of the socket APIs for a connectionless protocol.h> /* Server's port number */ #define SERVPORT 3555 void main() { /***************************************/ /* Variable and structure definitions.h> #include <netinet/in.h> #include <string. */ /***************************************/ int sd. Examples: Connecting a UDP server and client The following examples show how to use UDP to connect a server to a connectionless client. and a connectless client to a server. Examples: Using sockets 95 .h> #include <sys/socket.h> #include <arpa/inet. Example: Connecting a UDP server to a client The following example shows how to use UDP to connect a connectionless socket server program to a client. */ /* File contain Macro. Chapter 7.h> /* in qsysinc library */ #include <sys/types. Data Type and Structure */ /* definitions along with Function prototypes.h> #include <stdlib.

sin_port = htons(SERVPORT). */ /************************************************/ /* Wait on client requests. close(sd). char buffer[100]. &clientaddrlen). SOCK_DGRAM. serveraddrlen)). char *bufptr = buffer. 96 Socket programming .\n". if ((rc = bind(sd. if (rc < 0) { perror("recvfrom() failed").struct sockaddr_in serveraddr. /******************************************/ /* The socket() function returns a socket */ /* descriptor representing an endpoint. 0. serveraddr. */ rc = recvfrom(sd. */ /********************************************/ /* bind to address */ memset(&serveraddr. */ /* a bind() is done to assign a unique name */ /* to the socket. exit(-1).sin_addr. exit(-1). } /********************************************/ /* After the socket descriptor is received. */ /******************************************/ /* get a socket descriptor */ if ((sd = socket(AF_INET. int buflen = sizeof(buffer). close(sd). the user */ /* set the s_addr to zero. int clientaddrlen = sizeof(clientaddr). The recvfrom() function waits */ /* indefinitely for data to arrive. (struct sockaddr *)&serveraddr. int serveraddrlen = sizeof(serveraddr). printf(" from port %d and address %s. In this example. } printf("server received the following: <%s>\n". 0)) < 0) { perror("socket() failed"). serveraddr. */ /*********************************************/ /************************************************/ /* This example does not use flags that control */ /* the reception of the data. 0x00. } /*********************************************/ / Use the recvfrom() function to receive the */ /* data.sin_family = AF_INET. exit(-1). This allows the */ /* system to connect to any client that uses */ /* port 3555. serveraddr. serveraddrlen)) < 0) { perror("bind() failed").s_addr = htonl(INADDR_ANY). (struct sockaddr *)&clientaddr. */ /* The statement also identifies that the */ /* INET (Internet Protocol) address family */ /* with the UDP transport (SOCK_DGRAM) will */ /* be used for this socket. bufptr. bufptr). clientaddr. buflen.

or */ /* set the server name in the #define */ /* SERVER. */ /* In this example. */ /* File contain Macro. clientaddrlen). char *argv[]) { /***************************************/ Chapter 7. */ void main(int argc.h> #include <stdlib.h> #include <netdb.ntohs(clientaddr. */ /************************************************/ /************************************************/ /* This example does not use flags that control */ /* the transmission of the data */ /************************************************/ /* Send a reply. } /********************************************/ /* When the data has been sent. Examples: Using sockets 97 .h> #include <netinet/in. */ /***********************************************/ /* in qcle/h file */ #include <stdio. (struct sockaddr *)&clientaddr.h> #include <sys/socket. 0. bufptr. just echo the request */ rc = sendto(sd. close(sd).h> #include <arpa/inet. } /* end of main() */ Example: Connecting a UDP client to a server The following example shows how to use UDP to connect a connectionless socket client program to a server.h> /* in qsysinc library */ #include <sys/types. /************************************************/ /* Send a reply by using the sendto() function.h> #include <string. close() the */ /* socket descriptor. */ close(sd). if (rc < 0) { perror("sendto() failed"). */ /********************************************/ /* Close() the socket descriptor. /***********************************************/ /* Header files needed to use the sockets API. inet_ntoa(clientaddr. buflen.h> /* Host name of my system */ #define SERVER "SERVERHOSTNAME" /* Server's port number */ #define SERVPORT 3555 /* Pass in 1 parameter which is either the */ /* address or host name of the server.sin_addr)). the system echoes the received */ /* data back to the client. Data Type and Structure */ /* definitions along with Function prototypes.sin_port). exit(-1). exit(0).

/* Variable and structure definitions. */ /***************************************/ int sd, rc; struct sockaddr_in serveraddr; int serveraddrlen = sizeof(serveraddr); char server[255]; char buffer[100]; char *bufptr = buffer; int buflen = sizeof(buffer); struct hostent *hostp; memset(buffer, 0x00, sizeof(buffer)); memcpy(buffer, "A CLIENT REQUEST", 16); /******************************************/ /* The socket() function returns a socket */ /* descriptor representing an endpoint. */ /* The statement also identifies that the */ /* INET (Internet Protocol) address family */ /* with the UDP transport (SOCK_DGRAM) will */ /* be used for this socket. */ /******************************************/ /* get a socket descriptor */ if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket() failed"); exit(-1); } if (argc > 1) strcpy(server, argv[1]); else strcpy(server, SERVER); memset(&serveraddr, 0x00, sizeof(struct sockaddr_in)); serveraddr.sin_family = AF_INET; serveraddr.sin_port = htons(SERVPORT); if ((serveraddr.sin_addr.s_addr = inet_addr(server)) == (unsigned long)INADDR_NONE) { /************************************************/ /* Use the gethostbyname() function to retrieve */ /* the address of the host server if the system */ /* passed the host name of the server as a parameter. */ /************************************************/ /* get server address */ hostp = gethostbyname(server); if (hostp == (struct hostent *)NULL) { printf("HOST NOT FOUND --> "); /* h_errno is usually defined */ /* in netdb.h */ printf("h_errno = %d\n",h_errno); exit(-1); } memcpy(&serveraddr.sin_addr, hostp->h_addr, sizeof(serveraddr.sin_addr)); } /**********************************************/ /* Use the sendto() function to send the data */ /* to the server. */ /*********************************************/ /************************************************/ /* This example does not use flags that control */ /* the transmission of the data. */

98

Socket programming

/************************************************/ /* send request to server */ rc = sendto(sd, bufptr, buflen, 0, (struct sockaddr *)&serveraddr, sizeof(serveraddr)); if (rc < 0) { perror("sendto() failed"); close(sd); exit(-1); } /**********************************************/ /* Use the recvfrom() function to receive the */ /* data back from the server. */ /**********************************************/ /************************************************/ /* This example does not use flags that control */ /* the reception of the data. */ /************************************************/ /* Read server reply. */ /* Note: serveraddr is reset on the */ /* recvfrom() function. */ rc = recvfrom(sd, bufptr, buflen, 0, (struct sockaddr *)&serveraddr, &serveraddrlen); if (rc < 0) { perror("recvfrom() failed"); close(sd); exit(-1); } printf("client received the following: <%s>\n", bufptr); printf(" from port %d, from address %s\n", ntohs(serveraddr.sin_port), inet_ntoa(serveraddr.sin_addr)); /********************************************/ /* When the data has been received, close() */ /* the socket descriptor. */ /********************************************/ /* close() the socket descriptor. */ close(sd); exit(0);

}

Examples: Connection-oriented server designs introduction
There are a number of ways that you can design a connection-oriented socket server on the AS/400. While additional socket server designs are possible, the designs provided in the examples below are the most common: v Iterative server In the iterative server example, a single server job handles all incoming connections and all data flows with the client jobs. When the accept() API completes, the server handles the entire transaction. This is the easiest server to develop, but it does have a few problems. While the server is handling the request from a given client, additional clients could be trying to get to the server. These requests fill the listen() backlog and some of the them will be rejected eventually.

Chapter 7. Examples: Using sockets

99

All of the remaining examples are concurrent server designs. In these designs, the system uses multiple jobs and threads to handle the incoming connection requests. With a concurrent server there are usually multiple clients that connect to the server at the same time. v spawn() server and spawn() worker The spawn() server and spawn() worker example uses the spawn() API to create a new job to handle each incoming request. After spawn() completes, the server can then wait on the accept() API for the next incoming connection to be received. The only problem with this server design is the performance overhead of creating a new job each time a connection is received. You can avoid the performance overhead of the spawn() server example by using prestarted jobs. Instead of creating a new job each time a connection is received, the incoming connection is given to a job that is already active. All of the remaining examples in this topic use prestarted jobs. v givedescriptor() server and takedescriptor() worker The givedescriptor() server and takedescriptor() worker example uses the AS/400-specific givedescriptor() and takedescriptor() APIs. These APIs pass the incoming connection to the worker (client) job. The server prestarted all of the worker jobs when the server job first started. v sendmsg() server and recvmsg() worker The sendmsg() server and recvmsg() worker example is nearly identical to the givedescriptor() server and takedescriptor() worker examples. The following are the main differences between the APIs: – The system does not create an AS/400-specific data queue in this example. – The system uses the industry standard sendmsg() and recvmsg() APIs to pass the incoming connection from the server to the worker job. – The performance of the sendmsg() and recvmsg() APIs is slightly better than the performance of the givedescriptor() and takedescriptor() APIs. v Multiple accept() servers and multiple accept() workers In the previous examples, the worker job did not get involved until after the server received the incoming connection request. The multiple accept() servers and multiple accept() workers example of the system turns each of the worker jobs into an iterative server. The server job still calls the socket(), bind(), and listen() APIs. When the listen() call completes, the server creates each of the worker jobs and gives a listening socket to each one of them. All of the worker jobs then call the accept() API. When a client tries to connect to the server, only one accept() call completes, and that worker handles the connection. This type of design removes the need to give the incoming connection to a worker job, and saves the performance overhead that is associated with that operation. As a result, this design has the best performance. A worker job or a worker thread refers to a process or subprocess (thread) that does data processing by using the socket descriptor. For example, a worker process accesses a database file to extract and format information for sending to the remote peer through the socket descriptor and its associated connection. It could then receive a response or set of data from the remote peer and update the database accordingly. Depending on the design of the server, the worker usually does not perform the connection ″bring-up″ or initiation. This is usually done by the listening or server job or thread. The listening or server job usually passes the descriptor to the worker job or thread.

100

Socket programming

Examples: Using sockets 101 . The system used the same port on all the server programs so that it could use a single client example program with all of the servers. buffer[80].h> <netinet/in. In the example server programs. The figure illustrates how the server and client jobs interact when the system used the iterative server design.h> 12345 #define SERVER_PORT main (int { int int char struct argc. len. char *argv[]) i. 2. This means that only one of the server programs can be active at any given time.h> <sys/socket. listen_sd. accept_sd. /*************************************************/ /* If an argument was specified. num. Example: Writing an iterative server program This example shows how you can write an iterative server program.Notes: 1. The default is for the server to allow only one connection. use it to */ Chapter 7. sockaddr_in addr.h> <stdlib. #include #include #include #include <stdio. rc. All of the five server example programs use the same port number (12345). the number of incoming connections that the server allows depends on the first parameter that is passed to the server.

} /*************************************************/ /* Inform the user that the server is ready */ /*************************************************/ printf("The server is ready\n"). 0). } /*************************************************/ /* Bind the socket */ /*************************************************/ memset(&addr. accept_sd = accept(listen_sd. exit(-1). exit(-1). exit(-1). (struct sockaddr *)&addr. if (listen_sd < 0) { perror("socket() failed"). addr. i+1). /*************************************************/ /* Go through the loop once for each connection */ /*************************************************/ for (i=0. SOCK_STREAM. if (accept_sd < 0) { perror("accept() failed"). /*************************************************/ /* Create an AF_INET stream socket to receive */ /* incoming connections on */ /*************************************************/ listen_sd = socket(AF_INET.s_addr = htonl(INADDR_ANY).sin_port = htons(SERVER_PORT). 0.sin_addr. NULL. i < num. addr. sizeof(addr)). close(listen_sd). close(listen_sd). } /*************************************************/ /* Set the listen backlog */ /*************************************************/ rc = listen(listen_sd. rc = bind(listen_sd. } 102 Socket programming . exit(-1). if (rc < 0) { perror("bind() failed")./* control the number of incoming connections */ /*************************************************/ if (argc >= 2) num = atoi(argv[1]).sin_family = AF_INET. else num = 1. sizeof(addr)). printf(" waiting on accept()\n"). NULL). if (rc < 0) { perror("listen() failed"). addr. close(listen_sd). i++) { /**********************************************/ /* Wait for an incoming connection */ /**********************************************/ printf("Iteration: %d\n". 5).

} /**********************************************/ /* Close the incoming connection */ /**********************************************/ close(accept_sd). sizeof(buffer). rc = recv(accept_sd. buffer). The attributes that are inherited by the child with the spawn() function include the following items: v The socket and file descriptors v The signal mask v The signal action vector v The environment variables Chapter 7. 0). close(accept_sd). buffer. } } /*************************************************/ /* Close the listen socket */ /*************************************************/ close(listen_sd). close(accept_sd). exit(-1). close(listen_sd). len = rc. len. buffer. exit(-1). rc = send(accept_sd. The server job waits for an incoming connection. if (rc <= 0) { perror("recv() failed"). /**********************************************/ /* Echo the data back to the client */ /**********************************************/ printf(" echo it back\n"). if (rc <= 0) { perror("send() failed"). and then calls spawn() to create children jobs to handle the incoming connection. } printf(" <%s>\n".printf(" accept completed successfully\n"). Examples: Using the spawn() API to create child processes The server example shows how a server program can use the spawn() API to create a child process that inherits the socket descriptor from the parent. /**********************************************/ /* Receive a message from the client */ /**********************************************/ printf(" wait for client to send us a message\n"). Examples: Using sockets 103 . close(listen_sd). 0).

The worker job receives a data buffer from the client job and echos it back. 104 Socket programming .h> <netinet/in.h> 12345 #define SERVER_PORT main (int argc. go to the spawn() function details in the Sockets APIs. pid. accept_sd. char *argv[]) { int i. #include #include #include #include #include <stdio. char *spawn_envp[1]. worker.h> <stdlib. num. and client jobs interact when the spawn() server design is used. int listen_sd. char buffer[80]. Example: Using the spawn() API to create child processes This example shows how to use the spawn() API to create a child process that inherits the socket descriptor from the parent. For more information. The worker example contains the code for the worker job that is created by spawn(). char *spawn_argv[3].h> <spawn.The following figure illustrates how the server. rc.h> <sys/socket.

sizeof(addr)). 0. else num = 1. (struct sockaddr *)&addr. 5). use it to */ /* control the number of incoming connections */ /*************************************************/ if (argc >= 2) num = atoi(argv[1]). addr. i++) { /**********************************************/ /* Wait for an incoming connection */ /**********************************************/ printf("Iteration: %d\n". /*************************************************/ /* Create an AF_INET stream socket to receive */ /* incoming connections on */ /*************************************************/ listen_sd = socket(AF_INET. exit(-1). if (rc < 0) { perror("bind() failed"). if (accept_sd < 0) Chapter 7. exit(-1). if (listen_sd < 0) { perror("socket() failed"). close(listen_sd). addr. accept_sd = accept(listen_sd. Examples: Using sockets 105 .sin_addr. /*************************************************/ /* Go through the loop once for each connection */ /*************************************************/ for (i=0. addr. sizeof(addr)). rc = bind(listen_sd. SOCK_STREAM. /*************************************************/ /* If an argument was specified. addr.s_addr = htonl(INADDR_ANY).struct inheritance struct sockaddr_in inherit. exit(-1). NULL). i < num. } /*************************************************/ /* Set the listen backlog */ /*************************************************/ rc = listen(listen_sd. i+1). if (rc < 0) { perror("listen() failed"). 0). printf(" waiting on accept()\n"). NULL.sin_family = AF_INET. } /*************************************************/ /* Inform the user that the server is ready */ /*************************************************/ printf("The server is ready\n"). } /*************************************************/ /* Bind the socket */ /*************************************************/ memset(&addr.sin_port = htons(SERVER_PORT). close(listen_sd).

buffer[80]. close(accept_sd). 0. len. */ /**********************************************/ memset(&inherit.h> #include <stdlib. accept completed successfully\n").PGM". } } /*************************************************/ /* Close the listen socket */ /*************************************************/ close(listen_sd). spawn_argv[0] = "". /**********************************************/ /* Initialize the spawn parameters */ /* */ /* Turn the socket descriptor for the new */ /* connection into a string and pass it to */ /* the child program as an argument.LIB/WRKR1. Example: Enabling the worker job to receive a data buffer This example contains the code that enables the worker job to receive a data buffer from the client job and echo it back. accept_sd + 1. accept_sd).h> main (int { int int char argc. NULL. } printf(" spawn completed successfully\n"). spawn_argv[2] = NULL.h> #include <sys/socket. sockfd. sprintf(buffer. close(listen_sd). "%d". exit(-1). spawn_envp). &inherit. exit(-1). /**********************************************/ /* Close the incoming connection since */ /* it has been given to a worker to handle */ /**********************************************/ close(accept_sd).{ } printf(" perror("accept() failed"). /**********************************************/ /* Create the worker job */ /**********************************************/ printf(" creating worker job\n"). if (pid < 0) { perror("spawn() failed"). #include <stdio. pid = spawn("/QSYS.LIB/QGPL. spawn_argv[1] = buffer. spawn_envp[0] = NULL. char *argv[]) rc. sizeof(inherit)). close(listen_sd). /*************************************************/ /* The descriptor for the incoming connection is */ 106 Socket programming . spawn_argv.

exit(-1). /*************************************************/ /* Echo the data back to the client */ /*************************************************/ printf("Echo it back\n"). close(sockfd). Examples: Using sockets 107 . buffer). /*************************************************/ /* Receive a message from the client */ /*************************************************/ printf("Wait for client to send us a message\n")./* passed to this worker job as a command line */ /* parameter */ /*************************************************/ sockfd = atoi(argv[1]). 0). exit(-1). rc = send(sockfd. When the client job connects to the server. if (rc <= 0) { perror("recv() failed"). 0). } printf("<%s>\n". buffer. len. buffer. When the server starts. } /*************************************************/ /* Close the incoming connection */ /*************************************************/ close(sockfd). the server gives the incoming connection to one of the worker jobs. it creates a pool of worker jobs. if (rc <= 0) { perror("send() failed"). len = rc. close(sockfd). These preallocated (spawned) worker jobs wait until needed. } Examples: Using givedescriptor() and takedescriptor() APIs to handle incoming connections The givedescriptor() and takedescriptor() examples show how to design a server program that uses these APIs to handle incoming connections. Chapter 7. rc = recv(sockfd. sizeof(buffer).

Note: 108 Socket programming . worker.The following figure illustrates how the server. Example: Using the givedescriptor() API to handle incoming connections This examples show how to design the givedescriptor() server API to handle incoming connections and to create a pool of worker jobs. and client jobs interact when the system uses the givedescriptor() and takedescriptor() server design.

sin_port = htons(SERVER_PORT). 0. addr. char *spawn_argv[2].h> #define ID_LEN 16 #define SERVER_PORT 12345 main (int argc. if (rc < 0) { perror("bind() failed"). exit(-1).h> <sys/socket. /*************************************************/ /* Create an AF_INET stream socket to receive */ /* incoming connections on */ /*************************************************/ listen_sd = socket(AF_INET.s_addr = htonl(INADDR_ANY). int listen_sd.h> <spawn. use it to */ /* control the number of incoming connections */ /*************************************************/ if (argc >= 2) num = atoi(argv[1]). struct inheritance inherit. char jobid[ID_LEN]. else num = 1. close(listen_sd). 5). struct sockaddr_in addr.h> <stdlib. (struct sockaddr *)&addr. if (listen_sd < 0) { perror("socket() failed").h> <qrcvdtaq.h> <qclrdtaq. pid. num. exit(-1). } /*************************************************/ /* Bind the socket */ /*************************************************/ memset(&addr.0) jobid_len = ID_LEN. /*************************************************/ /* If an argument is specified.sin_family = AF_INET. rc. close(listen_sd). addr. char *spawn_envp[1]. Examples: Using sockets 109 . SOCK_STREAM. accept_sd. char *argv[]) { int i. rc = bind(listen_sd. } /*************************************************/ /* Set the listen backlog */ /*************************************************/ rc = listen(listen_sd.#include #include #include #include #include #include #include #include <stdio.h> <netinet/in. sizeof(addr)). if (rc < 0) { perror("listen() failed"). _Decimal(5. 0). Chapter 7.sin_addr. sizeof(addr)). addr.h> <qusec.

/*************************************************/ /* Go through the loop once for each connection */ /*************************************************/ for (i=0. i++) { /**********************************************/ /* Wait for an incoming connection */ /**********************************************/ printf("Iteration: %d\n". -1.} exit(-1). QCLRDTAQ("DQ "QUSRSYS ". NULL.. accept_sd = accept(listen_sd.\n"). spawn_envp[0] = NULL. if (accept_sd < 0) { perror("accept() failed"). NULL). i < num. printf(" waiting on accept()\n"). /*************************************************/ /* Create and clear a data queue */ /*************************************************/ system("CRTDTAQ DTAQ(QUSRSYS/DQ) MAXLEN(20)"). /* dtaq name /* dtaq lib */ */ /*************************************************/ /* Initialize spawn parms prior to entering the */ /* for loop */ /*************************************************/ memset(&inherit. exit(-1). } printf(" Worker = %d\n". "). pid).PGM". } printf(" accept completed successfully\n"). i < num. i++) { pid = spawn("/QSYS. spawn_argv[0] = "". if (pid < 0) { perror("spawn() failed"). } /*************************************************/ /* Inform the user that the server is ready */ /*************************************************/ printf("The server is ready\n"). spawn_argv[1] = NULL. spawn_argv. close(listen_sd). spawn_envp). sizeof(inherit)). for (i=0.LIB/QGPL. close(listen_sd). 0. /* dtaq name */ 110 Socket programming . exit(-1).. /*************************************************/ /* Create each of the worker jobs */ /*************************************************/ printf("Creating worker jobs. /**********************************************/ /* Receive the job ID of the next available */ /* worker from the data queue */ /**********************************************/ QRCVDTAQ("DQ ". &inherit.LIB/WRKR2. i+1). NULL.

h> <qsnddtaq. } printf(" QRCVDTAQ completed successfully\n"). } } /*************************************************/ /* Close the server and listen sockets */ /*************************************************/ close(listen_sd).0) jobid_len = ID_LEN. #include #include #include #include #include #include <stdio. close(accept_sd).h> <qusec. close(listen_sd). Example: Using the takedescriptor() API to receive worker jobs This example shows how the takedescriptor() client job connects to the server and receives the worker jobs. close(accept_sd). int sockfd.h> <stdlib.h> <qusrjobi. /* place to put output */ struct Qwc_JOBI0100 jobinfo. char buffer[80]. char *argv[]) { int rc. /* dtaq lib */ &jobid_len.h> 16 #define ID_LEN main (int argc. len. /* wait time (sec) */ if (jobid_len != ID_LEN) { printf("QRCVDTAQ failed\n"). /**********************************************/ /* Close the incoming connection since */ /* it has been given to a worker to handle */ /**********************************************/ close(accept_sd). */ /**********************************************/ rc = givedescriptor(accept_sd. /* length of data */ jobid. close(listen_sd). /* data */ 10). Chapter 7.h> <sys/socket. jobid). /**********************************************/ /* Use the job ID that was dequeued from the */ /* data queue to give the descriptor for the */ /* incoming connection to the worker job that */ /* is waiting for the takedescriptor() API. char jobid[ID_LEN]. _Decimal(5. exit(-1). } printf(" givedescriptor completed successfully\n")."QUSRSYS ". Examples: Using sockets 111 . if (rc < 0) { perror("givedescriptor() failed"). exit(-1).

Bytes_Available != 0) { printf("QUSRJOBI() failed\n"). } /*************************************************/ /* Receive a message from the client */ /*************************************************/ printf("Wait for client to send us a message\n"). exit(-1). /*************************************************/ /* Enqueue the internal job ID onto the shared */ /* data queue */ /*************************************************/ QSNDDTAQ("DQ ". buffer. buffer. sizeof(buffer). 0). } /*************************************************/ /* Copy the job information into local variable */ /*************************************************/ memcpy(jobid. exit(-1). sizeof(jobinfo). if (sockfd < 0) { perror("takedescriptor() failed"). */ /*************************************************/ printf("Waiting on takedescriptor\n"). close(sockfd). sockfd = takedescriptor(NULL). /*************************************************/ /* Determine this job's internal job ID */ /*************************************************/ QUSRJOBI(&jobinfo. /* dtaq lib */ ID_LEN. exit(-1). if (rc <= 0) { perror("send() failed"). len. rc = send(sockfd. } printf("<%s>\n". /* dtaq name */ "QUSRSYS ". "JOBI0100". /* length of data */ jobid). rc = recv(sockfd. "* ". buffer). if (rc <= 0) { perror("recv() failed").Int_Job_ID. &error). 0). /* data */ /*************************************************/ /* Issue the takedescriptor() API which will */ /* block until the server job gives its */ /* descriptor to this job. if (error. len = rc. 112 Socket programming . jobinfo./* error structure */ Qus_EC_t error = { sizeof(Qus_EC_t) }. /*************************************************/ /* Echo the data back to the client */ /*************************************************/ printf("Echo it back\n"). 16). " ".

The following figure illustrates how the server. Chapter 7. When the server starts. } /*************************************************/ /* Close the descriptors */ /*************************************************/ close(sockfd). These preallocated (spawned) worker jobs wait until needed. and client jobs interact when the system uses the sendmsg() and recvmsg() server design. the server gives the incoming connection to one of the worker jobs. Examples: Using sendmsg() and recvmsg() APIs to handle incoming connections The sendmsg() and recvmsg() examples show how to design a server program that uses these APIs to handle incoming connections. worker. When the client job connects to the server. it creates a pool of worker jobs. Examples: Using sockets 113 .} close(sockfd). exit(-1).

num. if (rc < 0) { perror("listen() failed"). addr. int server_sd. char *spawn_argv[3]. worker_sd. 0. sizeof(addr)). struct sockaddr_in addr. accept_sd. int listen_sd.s_addr = htonl(INADDR_ANY). } /*************************************************/ /* Set the listen backlog */ /*************************************************/ rc = listen(listen_sd.h> <spawn. if (rc < 0) { perror("bind() failed"). 114 Socket programming . (struct sockaddr *)&addr. rc. addr. struct inheritance inherit. use it to */ /* control the number of incoming connections */ /*************************************************/ if (argc >= 2) num = atoi(argv[1]).h> <netinet/in. 5). else num = 1. rc = bind(listen_sd. exit(-1). addr. exit(-1). if (listen_sd < 0) { perror("socket() failed"). 0). #include #include #include #include #include <stdio. char *spawn_envp[1].h> 12345 #define SERVER_PORT main (int argc. /*************************************************/ /* Create an AF_INET stream socket to receive */ /* incoming connections on */ /*************************************************/ listen_sd = socket(AF_INET. close(listen_sd).sin_port = htons(SERVER_PORT). char *argv[]) { int i. struct msghdr msg.sin_family = AF_INET. } /*************************************************/ /* Bind the socket */ /*************************************************/ memset(&addr. /*************************************************/ /* If an argument is specified. pid. char buffer[80].Example: Using the sendmsg() API to create worker jobs This example shows how to use the sendmsg() API to create a pool of worker jobs.h> <stdlib. sizeof(addr)).sin_addr. pair_sd[2].h> <sys/socket. SOCK_STREAM.

/*************************************************/ /* Create a pair of UNIX datagram sockets */ /*************************************************/ rc = socketpair(AF_UNIX. close(server_sd). SOCK_DGRAM. i < num. */ /*************************************************/ memset(&inherit. spawn_envp). if (rc != 0) { perror("socketpair() failed"). worker_sd + 1. "%d". } printf(" Worker = %d\n".LIB/QGPL. close(listen_sd). } /*************************************************/ /* Close the worker side of the socketpair */ /*************************************************/ close(worker_sd). spawn_argv[2] = NULL. /*************************************************/ /* Create each of the worker jobs */ /*************************************************/ printf("Creating worker jobs. /*************************************************/ /* Go through the loop once for each connection */ /*************************************************/ for (i=0. spawn_argv. worker_sd). NULL. pid). close(worker_sd)..\n").PGM".. /*************************************************/ /* Inform the user that the server is ready */ /*************************************************/ printf("The server is ready\n"). spawn_argv[1] = buffer. pair_sd). exit(-1). i++) { Chapter 7. } server_sd = pair_sd[0]. exit(-1). 0. sprintf(buffer. for (i=0. close(listen_sd).} close(listen_sd).LIB/WRKR3. sizeof(inherit)). spawn_envp[0] = NULL. if (pid < 0) { perror("spawn() failed"). Examples: Using sockets 115 . &inherit. i++) { pid = spawn("/QSYS. spawn_argv[0] = "". i < num. exit(-1). /*************************************************/ /* Initialize parameters prior to entering */ /* command for loop */ /* */ /* Turn the worker socket descriptor into a */ /* string and pass it to the child program as */ /* an argument. 0. worker_sd = pair_sd[1].

exit(-1). /**********************************************/ /* You are not sending any data so you do not */ /* need to set either of the msg_iov fields. printf(" waiting on accept()\n"). NULL). exit(-1). close(listen_sd). 0. */ /**********************************************/ msg. NULL. /**********************************************/ /* Initialize message header structure */ /**********************************************/ memset(&msg.msg_accrightslen = sizeof(accept_sd). */ /* The memset of the message header structure */ /* will set the msg_iov pointer to NULL and */ /* it will set the msg_iovcnt field to 0. i+1). if (rc < 0) { perror("sendmsg() failed")./**********************************************/ /* Wait for an incoming connection */ /**********************************************/ printf("Iteration: %d\n". close(server_sd). */ /* */ /* NOTE: It is not known which worker job will*/ /* get this inbound connection. /**********************************************/ /* Give the incoming connection to one of the */ /* worker jobs. } printf(" sendmsg completed successfully\n"). close(accept_sd). 116 Socket programming . &msg. accept_sd = accept(listen_sd. } } /*************************************************/ /* Close the server and listen sockets */ /*************************************************/ close(server_sd).msg_accrights = (char *)&accept_sd msg. } printf(" accept completed successfully\n"). sizeof(msg)). */ /**********************************************/ rc = sendmsg(server_sd. close(server_sd). 0). /**********************************************/ /* Close the incoming connection since */ /* it has been given to a worker to handle */ /**********************************************/ close(accept_sd). close(listen_sd). if (accept_sd < 0) { perror("accept() failed"). */ /**********************************************/ /**********************************************/ /* The only fields in the message header */ /* structure that need to be filled in are */ /* the msg_accrights fields. close(listen_sd).

h> #include <sys/socket. exit(-1). /*************************************************/ /* One of the socket descriptors that is */ /* returned by socketpair() is passed to this */ /* worker job as a command line parameter */ /*************************************************/ worker_sd = atoi(argv[1]). worker_sd.msg_accrights = (char *)&pass_sd msg.msg_accrightslen = sizeof(pass_sd). char *argv[]) rc.iov_len = sizeof(buffer). 0). close(worker_sd).msg_iovlen = 1.msg_iov = iov. msghdr msg. pass_sd. #include <stdio. /*************************************************/ /* Fill in the msg_accrights fields so that you */ /* can receive the descriptor */ /*************************************************/ msg. iov[0]. /*************************************************/ /* Initialize message header structure */ /*************************************************/ memset(&msg. rc = recvmsg(worker_sd.msg_accrightslen <= 0) { printf("Descriptor was not received\n"). iovec iov[1]. close(worker_sd). sizeof(iov)). } else { printf("Received descriptor = %d\n". msg. Examples: Using sockets 117 . if (rc < 0) { perror("recvmsg() failed"). } Chapter 7. 0. msg.iov_base = buffer. } else if (msg. len. /*************************************************/ /* The recvmsg() call will not block unless a */ /* non-zero length data buffer is specified */ /*************************************************/ iov[0].h> #include <stdlib. buffer[80].Example: Using the recvmsg() API to receive worker jobs This example shows how to use the recvmsg() API client job to receive the worker jobs. &msg.h> main (int { int int char struct struct argc. memset(iov. sizeof(msg)). exit(-1). pass_sd). 0. /*************************************************/ /* Wait for the descriptor to arrive */ /*************************************************/ printf("Waiting on recvmsg\n").

close(worker_sd). buffer). if (rc <= 0) { perror("send() failed"). and listen() as normal. len = rc. close(pass_sd). } printf("<%s>\n". rc = recv(pass_sd. if (rc <= 0) { perror("recv() failed"). sizeof(buffer). it does a socket(). 0). close(worker_sd)./*************************************************/ /* Receive a message from the client */ /*************************************************/ printf("Wait for client to send us a message\n"). } Examples: Using multiple accept() APIs to handle incoming connection requests These examples show how to design a server program that uses the multiple accept() model for handling incoming connection requests. 118 Socket programming . buffer. } /*************************************************/ /* Close the descriptors */ /*************************************************/ close(worker_sd). exit(-1). len. When the multiple accept() server starts up. It then creates a pool of worker jobs and gives each worker job the listening socket. exit(-1). /*************************************************/ /* Echo the data back to the client */ /*************************************************/ printf("Echo it back\n"). Each multiple accept() worker then calls accept(). rc = send(pass_sd. buffer. 0). bind(). close(pass_sd). close(pass_sd).

accept_sd. num. Chapter 7. Examples: Using sockets 119 . /*************************************************/ /* If an argument is specified. char *argv[]) { int i.h> sys/socket. #include #include #include #include #include <stdio.h> <stdlib. pid. rc.h> <spawn. Example: Using multiple accept() APIs to create worker jobs This example shows how to use the multiple accept() model to create a pool of worker jobs. worker.The following figure illustrates how the server.h> <netinet/in. char *spawn_envp[1]. struct sockaddr_in addr. struct inheritance inherit. use it to */ /* control the number of incoming connections */ /*************************************************/ if (argc >= 2) num = atoi(argv[1]). char buffer[80]. and client jobs interact when the system uses the multiple accept() server design. char *spawn_argv[3]. int listen_sd.h> 12345 #define SERVER_PORT main (int argc.

sprintf(buffer. spawn_envp). exit(-1).LIB/QGPL. spawn_argv. } /*************************************************/ /* Set the listen backlog */ /*************************************************/ rc = listen(listen_sd. 5). 0). } /*************************************************/ /* Bind the socket */ /*************************************************/ memset(&addr. i < num. close(listen_sd). } /*************************************************/ /* Initialize parameters prior to entering the */ /* command for loop */ /* */ /* Turn the listen socket descriptor into a */ /* string and pass it to the child program as */ /* an argument. spawn_argv[2] = NULL. addr. exit(-1). spawn_envp[0] = NULL.sin_port = htons(SERVER_PORT). &inherit. /*************************************************/ /* Create an AF_INET stream socket to receive */ /* incoming connections on */ /*************************************************/ listen_sd = socket(AF_INET. */ /*************************************************/ memset(&inherit. addr. rc = bind(listen_sd.LIB/WRKR4. if (rc < 0) { perror("bind() failed"). NULL. sizeof(addr)). if (pid < 0) { 120 Socket programming . addr. 0. if (listen_sd < 0) { perror("socket() failed"). i++) { pid = spawn("/QSYS. listen_sd + 1.sin_addr. exit(-1). close(listen_sd). sizeof(addr)). listen_sd).. if (rc < 0) { perror("listen() failed").PGM". spawn_argv[1] = buffer. SOCK_STREAM. spawn_argv[0] = ""..s_addr = htonl(INADDR_ANY). for (i=0. 0. /*************************************************/ /* Create each of the worker jobs */ /*************************************************/ printf("Creating worker jobs.else num = 1. sizeof(inherit)).sin_family = AF_INET.\n"). (struct sockaddr *)&addr. "%d".

accept_sd. /*************************************************/ /* Inform the user that the server is ready */ /*************************************************/ printf("The server is ready\n"). /*************************************************/ /* Close the listening socket */ /*************************************************/ close(listen_sd). } printf("<%s>\n". close(listen_sd). buffer. #include <stdio. Worker = %d\n". close(listen_sd). close(accept_sd). buffer[80]. len. } printf("Accept completed successfully\n").h> main (int { int int char argc.h> #include <stdlib.} } printf(" perror("spawn() failed"). if (accept_sd < 0) { perror("accept() failed"). exit(-1). rc = recv(accept_sd. pid). if (rc <= 0) { perror("recv() failed"). close(listen_sd). accept_sd = accept(listen_sd. /*************************************************/ Chapter 7. listen_sd. NULL. buffer). Examples: Using sockets 121 . sizeof(buffer). NULL). /*************************************************/ /* Wait for an incoming connection */ /*************************************************/ printf("Waiting on accept()\n").h> #include <sys/socket. } Example: Using multiple accept() APIs to receive worker jobs This example shows how multiple accept() APIs receive the worker jobs and call the accept() server. 0). char *argv[]) rc. /*************************************************/ /* The listen socket descriptor is passed to */ /* this worker job as a command line parameter */ /*************************************************/ listen_sd = atoi(argv[1]). exit(-1). exit(-1). /*************************************************/ /* Receive a message from the client */ /*************************************************/ printf("Wait for client to send us a message\n").

if (rc <= 0) { perror("send() failed"). sockaddr_in addr. char *argv[]) len. SOCK_STREAM./* Echo the data back to the client */ /*************************************************/ printf("Echo it back\n"). } /*************************************************/ /* Initialize the socket address structure */ /*************************************************/ memset(&addr. 122 Socket programming . /*************************************************/ /* Connect to the server */ /*************************************************/ rc = connect(sockfd. addr. The client job does a socket().h> <sys/socket. /*************************************************/ /* Create an AF_INET stream socket */ /*************************************************/ sockfd = socket(AF_INET. exit(-1). addr. 0). send_buf[80]. exit(-1). len.h> <stdlib.s_addr = htonl(INADDR_ANY). buffer. This client job works with all five types of servers that are listed in the connection-oriented server designs examples. The client job is not aware that the data buffer it sent and received is going to a worker job rather than to the server. 0). sizeof(addr)).sin_port = htons(SERVER_PORT). if (sockfd < 0) { perror("socket"). 0. addr. send(). close(listen_sd). #include #include #include #include <stdio. rc = send(accept_sd. and close(). } Example: Code for the connection-oriented common client This example provides the code for the client job. close(accept_sd).h> 12345 #define SERVER_PORT main (int { int int char char struct argc. } /*************************************************/ /* Close the descriptors */ /*************************************************/ close(listen_sd).sin_family = AF_INET.sin_addr. recv(). rc. close(accept_sd). len = rc. recv_buf[80].h> <netinet/in. connect(). sockfd.

exit(-1). exit(-1).h> #define HEX00 '\x00' #define NUMPARMS 2 Chapter 7. gets(send_buf). recv_buf. if (len != strlen(send_buf) + 1) { perror("recv").h> #include <sys/socket. Examples: Using sockets 123 . } Example: Threadsafe network routines for using gethostbyaddr_r() Following is an example of a program that uses gethostbyaddr_r(). sizeof(struct sockaddr_in)).h> #include <netinet/in.\n"). sizeof(recv_buf). 0). } printf("Connect completed.h> #include <stdio. (struct sockaddr *)&addr. /*************************************************/ /* Enter data buffer that is to be sent */ /*************************************************/ printf("Enter message to be sent:\n").h> #include <stdlib. This example program takes an IP address in the dotted-decimal notation and prints the host name. /*************************************************/ /* Send data buffer to the worker job */ /*************************************************/ len = send(sockfd. if (len != strlen(send_buf) + 1) { perror("send"). /*************************************************/ /* Close the socket */ /*************************************************/ close(sockfd). /*************************************************/ /* Receive data buffer from the worker job */ /*************************************************/ len = recv(sockfd.if (rc < 0) { perror("connect").h> #include <sys/param. close(sockfd). All other routines with names that end in ″_r″ have similar semantics and are also threadsafe. } printf("%d bytes received\n". send_buf. 0). /********************************************************/ /* Header files */ /********************************************************/ #include </netdb. len). exit(-1). len). close(sockfd). strlen(send_buf) + 1. close(sockfd).h> #include <arpa/inet. } printf("%d bytes sent\n".

otherwise. If you require compatibility */ /* with other platforms. &hst_ent_data)) == -1) { printf("Host name not found\n"). &hst_ent. */ /********************************************************/ int main(int argc.host_control_blk with hexadecimal zeros */ /* before its initial use. argv[1]). char dotted_decimal_address [16]. struct in_addr internet_address. exit(-1). /**********************************************************/ /* Translate an Internet address from dotted decimal */ /* notation to 32-bit IP address format. */ /* The following are possible values: */ /* -1 (unsuccessful call) */ /* 0 (successful call) */ /**********************************************************/ if ((rc=gethostbyaddr_r((char *) &internet_address. sizeof(struct in_addr). } /**********************************************************/ /* Obtain addressability to parameters passed */ /**********************************************************/ strcpy(dotted_decimal_address. then you must initialize the */ /* entire hostent_data structure with hexadecimal zeros. The host name will be */ /* displayed if found. AF_INET. char host_name[MAXHOSTNAMELEN]. */ /**********************************************************/ /* Initialize to hex 00 hostent_data structure */ /**********************************************************/ memset(&hst_ent_data. a message states */ /* host not found. /**********************************************************/ /* Verify correct number of arguments have been passed */ /**********************************************************/ if (argc != NUMPARMS) { printf("Wrong number of parms passed\n")./********************************************************/ /* Pass one parameter that is the IP address in */ /* dotted decimal notation. char *argv[]) { int rc. 124 Socket programming . exit(-1). /**********************************************************/ /* Initialize the structure-field */ /* hostent_data.sizeof(struct hostent_data)).HEX00. /**********************************************************/ /* Obtain host name */ /**********************************************************/ /**********************************************************/ /* NOTE: The gethostbyaddr_r() returns an integer. */ /**********************************************************/ internet_address. } else { /*****************************************************/ /* Copy the host name to an output buffer */ /*****************************************************/ (void) memcpy((void *) host_name. struct hostent hst_ent.s_addr=inet_addr(dotted_decimal_address). struct hostent_data hst_ent_data.

/****************************************************/ /* You must address all the results through the */ /* hostent structure hst_ent. You cannot use connection-oriented sockets of type SOCK_STREAM for multicasting. an application can use the setsockopt() function to control the multicast characteristics associated with that socket. A class D Internet address in the range 224.255.255. The steps needed to send a multicast datagram differ from the steps needed to receive a multicast datagram. An application program can send or receive multicast datagrams by using the socket() API and connectionless SOCK_DGRAM type sockets. MAXHOSTNAMELEN). Hosts may join and leave groups at any time. } Examples: Sending and receiving a multicast datagram IP multicasting provides the capability for an application to send a single IP datagram that a group of hosts in a network can receive.1 to 239. There are no restrictions on the location or number of members in a host group. Chapter 7. The hosts that are in the group may reside on a single subnet or may be on different subnets that connect multicast-capable routers.0. Example: Sending a multicast datagram The following example enables a socket to perform the steps listed below and to send multicast datagrams: 1. The following examples enable a socket to send and receive multicast datagrams. Examples: Using sockets 125 .255 identifies a host group. When a socket of type SOCK_DGRAM is created. Applications should consider */ /* hostent_data a storage area to put host level data */ /* that the application does not need to access. v IP_MULTICAST_LOOP: Specifies whether or not a copy of an outgoing multicast datagram is delivered to the sending host as long as it is a member of the multicast group. SOCK_DGRAM type socket.0.h_name. v IP_MULTICAST_TTL: Sets the Time To Live (TTL) in the IP header for outgoing multicast datagrams. Create an AF_INET. /*****************************************************/ /* Print the host name */ /*****************************************************/ printf("The host name is %s\n". The setsockopt() function accepts the following IPPROTO_IP level flags: v IP_ADD_MEMBERSHIP: Joins the multicast group specified. v IP_DROP_MEMBERSHIP: Leaves the multicast group specified. 2. */ /* NOTE: Hostent_data structure hst_ent_data is just */ /* a data repository that is used to support the */ /* hostent structure. } exit(0). */ /****************************************************/ (void *) hst_ent. host_name). Multicasting is a one-to-many transmission method. v IP_MULTICAST_IF: Sets the interface over which outgoing multicast datagrams are sent. Initialize a sockaddr_in structure with the destination group IP address and port number.

h> <stdio. groupSock. close(sd). * The IP address specified must be associated with a local. databuf[1024]. datalen. groupSock.1 and port 5555.s_addr = inet_addr("225. struct in_addr struct sockaddr_in int int char int main (int argc.1.sin_addr. /* * Disable loopback so you do not receive your own datagrams.h> <stdlib.1. exit(1). groupSock. IP_MULTICAST_LOOP. Send the datagram.sin_family = AF_INET.1. */ sd = socket(AF_INET. 0). sizeof(groupSock)). */ /* */ /* ------------------------------------------------------------*/ /* * Create a datagram socket on which to send. } } /* * Set local interface for outbound multicast datagrams. 4. 0. #include #include #include #include #include #include <sys/types. SOCK_DGRAM.h> <sys/socket.3. Set the IP_MULTICAST_IF socket option to define the local interface over which you want to send the multicast datagrams. * multicast-capable interface. IPPROTO_IP.1. */ { char loopch=0. (char *)&loopch. sd. char *argv[]) { /* ------------------------------------------------------------*/ /* */ /* Send Multicast Datagram code example. } /* * Initialize the group sockaddr structure with a * group address of 225.h> <arpa/inet. exit(1). */ 126 Socket programming . */ memset((char *) &groupSock.1").h> localInterface. sizeof(loopch)) < 0) { perror("setting IP_MULTICAST_LOOP:"). 5. groupSock.sin_port = htons(5555). if (setsockopt(sd.h> <netinet/in. Set the IP_MULTICAST_LOOP socket option according to whether the sending system should receive a copy of the multicast datagrams that are transmitted. if (sd < 0) { perror("opening datagram socket").

SOCK_DGRAM type socket. */ /* */ /* ------------------------------------------------------------*/ Chapter 7.s_addr = inet_addr("9. int main (int argc. When joining a group.h> <stdlib. databuf[1024].5. char *argv[]) { /* ------------------------------------------------------------*/ /* */ /* Receive Multicast Datagram code example. sd.h> <stdio.h> <sys/socket. Create an AF_INET. Use the IP_ADD_MEMBERSHIP socket option to join the multicast group that receive the datagrams. } } Example: Receiving a multicast datagram The following example enables a socket to perform the steps listed below and to receive multicast datagrams: 1. if (setsockopt(sd.h> <netinet/in. Use the bind() verb to specify the local port number. databuf.h> <arpa/inet. 4. 0. datalen. The system must call the IP_ADD_MEMBERSHIP socket option for each local interface receiving the multicast datagrams. (struct sockaddr*)&groupSock. group. specify the class D group address along with the IP address of a local interface. Specify the IP address as INADDR_ANY in order to receive datagrams that are addressed to a multicast group. 2. if (sendto(sd.h> struct sockaddr_in struct ip_mreq int int char localSock. } /* * Send a message to the multicast group specified by the * groupSock sockaddr structure. */ datalen = 10. sizeof(groupSock)) < 0) { perror("sending datagram message"). exit(1). 3. (char *)&localInterface. IP_MULTICAST_IF. Examples: Using sockets 127 . #include #include #include #include #include #include <sys/types.1. 5. IPPROTO_IP.localInterface. Set the SO_REUSEADDR option to allow multiple applications to receive datagrams that are destined to the same local port number.1"). Receive the datagram. sizeof(localInterface)) < 0) { perror("setting local interface"). datalen.

1. close(sd).sin_port = htons(5555).5. close(sd). localSock. exit(1). IPPROTO_IP./* * Create a datagram socket on which to receive. } } /* * Bind to the proper port number with the IP address * specified as INADDR_ANY. if (sd < 0) { perror("opening datagram socket"). SOL_SOCKET. exit(1).s_addr = INADDR_ANY. databuf. if (read(sd. close(sd).. SO_REUSEADDR.5.imr_interface.sin_addr.1. */ memset((char *) &localSock.1. */ sd = socket(AF_INET. SOCK_DGRAM. } } 128 Socket programming . exit(1). (struct sockaddr*)&localSock. } /* * Read from the socket. } /* * Join the multicast group 225.s_addr = inet_addr("225. group.1 * interface. localSock. exit(1). */ datalen = sizeof(databuf). exit(1). if (bind(sd. (char *)&group. */ group. IP_ADD_MEMBERSHIP. datalen) < 0) { perror("reading datagram message").1.1"). sizeof(localSock))) { perror("binding datagram socket"). sizeof(group)) < 0) { perror("adding multicast group"). */ { int reuse=1. sizeof(localSock)).1.1. 0).s_addr = inet_addr("9. if (setsockopt(sd. 0. sizeof(reuse)) < 0) { perror("setting SO_REUSEADDR"). localSock. (char *)&reuse. close(sd). Note that this IP_ADD_MEMBERSHIP option must be * called for each local interface over which the multicast * datagrams are to be received.1"). if (setsockopt(sd. } /* * Enable SO_REUSEADDR to allow multiple instances of this * application to receive copies of the multicast datagrams.sin_family = AF_INET.imr_multiaddr.1 on the local 9.

cipherSuiteList = &cipher[0].keyringPassword = NULL. sizeof(sslinit)). An SSL_Init() call must succeed at least once in a job. The server calls bind(). 8. listen(). SSL_RSA_EXPORT_WITH_RC4_40_MD5 }.h> <ssl. SSLInit sslinit. /*************************************************/ /* memset sslinit structure to hex zeros and */ /* fill in values for the sslinit structure */ /*************************************************/ memset((char *)&SSL_Init. The server calls socket() to obtain a socket descriptor. 2.kyr". 7.h> <errno. sslinit. SSL_RSA_WITH_RC4_128_SHA.Example: Establishing SSL server and client communications The following examples enable a Secure Sockets Layer (SSL) server to communicate with an SSL client. #include #include #include #include #include #include #include <stdio. /*************************************************/ /* Initialize SSL security call SSL_Init */ Chapter 7. sd2. 0x00. The server calls SSL_Init() to set up the application certificate if it is needed.h> <sys/socket. sd. Examples: Using sockets 129 . and accept() to activate a connection for a server program. 4. SSLHandle* sslh. addrlen = 0. The steps that are needed for an SSL server differ from the steps that are needed for an SSL client.keyringFileName = "/keyringfile.h> /* bufferLen is 250 bytes */ #define bufferLen 250 void main() { int bufferLen. Example: Enabling the SSL server to communicate with the SSL client The following example enables an SSL server to perform the steps listed below and to communicate with an SSL client: 1. rc = 0. The server calls SSL_Read() and SSL_Write() to receive and send data. The server calls SSL_Handshake() to initiate the SSL handshake negotiation of the cryptographic parameters. struct sockaddr_in addr. The server calls close() to destroy the connected sockets. The server calls SSL_Create() to enable SSL support for the connected socket. sslinit. sslinit. char buffer[bufferLen]. 3. The server calls SSL_Destroy() to disable SSL support for the socket.h> <arpa/inet. on = 1.h> <netinet/in.h> <sys/types. 6.cipherSuiteListLen = 3. unsigned short int cipher[3] = { SSL_RSA_WITH_RC4_128_MD5. 5. sslinit.

s_addr = htonl(INADDR_ANY).sin_family = AF_INET. } /*************************************************/ /* Allow the socket descriptor to be reusable */ /*************************************************/ rc = setsockopt(sd. addr./*************************************************/ rc = SSL_Init(&sslinit). if (rc < 0) { perror("bind() failed"). sizeof(on)). 0). (struct sockaddr *) &addr. SOL_SOCKET. return.sin_port = 12345. close(sd). } /*************************************************/ /* memset the sockaddr structure to hex zeros */ /* and bind the local server address */ /*************************************************/ memset((char *) &addr.\n". (struct sockaddr *) &addr. addr. rc = bind(sd. &addrlen). sizeof(addr)). sd2 = accept(sd. SOCK_STREAM. if (rc < 0) { perror("listen() failed"). if (rc < 0) { perror("setsockopt() failed").errno). if (sd2 < 0) 130 Socket programming . (char *)&on. if (sd < 0) { perror("socket() failed"). SO_REUSEADDR. } /*************************************************/ /* Accept a client connection */ /*************************************************/ addrlen = sizeof(addr). return.rc. addr. } /*************************************************/ /* Initialize a socket */ /*************************************************/ sd = socket(AF_INET. 5). return. if (rc != 0) { printf("SSL_Init() failed with rc = %d " "and errno = %d. 0x00.sin_addr. sizeof(addr)). return. } /*************************************************/ /* Enable client connections */ /*************************************************/ listen(sd. return. close(sd).

\n".rc). return. SSL_Destroy(sslh). } /*************************************************/ /* Set the input fields of the SSLHandle */ /* structure */ /*************************************************/ sslh -> protocol = 3. close(sd). buffer. bufferLen). buffer. sslh -> cipherSuiteList = &cipher[0] sslh -> cipherSuiteListLen = 3. } /*************************************************/ /* Send the message to the client using the */ /* secure session */ /*************************************************/ bufferLen = strlen(buffer). rc = SSL_Write(sslh. close(sd). rc. close(sd).\n". Examples: Using sockets 131 . /*************************************************/ /* Enable SSL support for the connection */ /*************************************************/ sslh = SSL_Create(sd. close(sd2). SSL_HANDSHAKE_AS_SERVER_WITH_CLIENT_AUTH). if (sslh == NULL) { printf("SSL_Create() failed with errno = %d. Chapter 7. errno). errno).\n". close(sd2). /*************************************************/ /* Receive a message from the client using the */ /* secure session */ /*************************************************/ rc = SSL_Read(sslh. 0x00. if (rc < 0) { printf("SSL_Read() failed with rc = %d. bufferLen). } /*************************************************/ /* memset buffer to hex zeros */ /*************************************************/ memset((char *) buffer. SSL_ENCRYPT). if (rc != 0) { printf("SSL_Handshake() failed with rc = %d " "and errno = %d. bufferLen). close(sd2). return.{ } perror("accept() failed"). sslh -> timeout = 0. return. /*************************************************/ /* Initiate the SSL handshake */ /*************************************************/ rc = SSL_Handshake(sslh. return. close(sd).

8.h> <netinet/in. The client calls SSL_Read() and SSL_Write() to receive and send data. return.h> <ssl. The client calls close() to destroy the connected sockets.h> <sys/socket. 7.h> <errno. 5. close(sd).h> <sys/types. The client calls SSL_Init() to set up the application certificate if the certificate does not exist. 3. The client calls SSL_Handshake() to initiate the SSL handshake negotiation of the cryptographic parameters. } else { printf("SSL_Write() did not write all data. The client calls SSL_Destroy() to disable SSL support for the socket. close(sd2). The client calls connect() to activate a connection for a client program. 2. /*************************************************/ /* Close the connection */ /*************************************************/ close(sd2). 6. The client calls socket() to obtain a socket descriptor.\n".\n").h> <ctype.rc). 4.h> 132 Socket programming . The client calls SSL_Create() to enable SSL support for the connected socket.h> <arpa/inet. } return. close(sd2). An SSL_Init() call must succeed at least once in a job. close(sd). #include #include #include #include #include #include #include #include #include <stdio. /*************************************************/ /* Close the listener */ /*************************************************/ close(sd). return. SSL_Destroy(sslh). SSL_Destroy(sslh).if (rc != bufferLen) { if (rc < 0) { printf("SSL_Write() failed with rc = %d.h> <netdb. Example: Enabling the SSL client to communicate with the server The following example enables an SSL client to perform the steps listed below and to communicate with an SSL server: 1. } } /*************************************************/ /* Disable SSL support for the connection */ /*************************************************/ SSL_Destroy(sslh).

unsigned short int cipher[2] = { SSL_RSA_WITH_NULL_MD5. struct hostent *host_ent.keyringFileName = "/keyringfile. if (sd < 0) { perror("socket() failed"). sslinit. SSLInit sslinit. SSLHandle *sslh. */ /***************************************************/ void main(int argc./* bufferLen is 250 bytes */ #define bufferLen 250 /***************************************************/ /* This program can be called by passing a host */ /* name or passing an IP address or with no */ /* parameters. sslinit. sslinit. char readBuff[bufferLen].keyringPassword = "secret". char writeBuff[bufferLen]. /*************************************************/ /*Initialize SSL security call SSL_Init */ /*************************************************/ rc = SSL_Init(&sslinit). 0).cipherSuiteListLen = sizeof(cipher) / sizeof(short). sslinit.\n". sizeof(sslinit)).kyr". /*************************************************/ /* memset sslinit structure to hex zeros and */ /* fill in values for the sslinit structure */ /*************************************************/ memset((char *)&sslinit. SOCK_STREAM. struct sockaddr_in addr. 0x00. sd.cipherSuiteList = &cipher[0]. if (rc != 0) /* did SSL_Init fail? */ { printf("SSL_Init() failed with rc = %d" " and errno = %d.errno). return. } /*************************************************/ /* Initialize a socket */ /*************************************************/ sd = socket(AF_INET. } /*************************************************/ /* Determine the host name and IP address of the */ /* machine the server is running on */ /*************************************************/ if (argc < 2) { /***********************************************/ /* Use INADDR_ANY if no parameters passed */ Chapter 7. Examples: Using sockets 133 .rc. SSL_RSA_EXPORT_WITH_RC4_40_MD5 }. return. char * argv[]) { int rc = 0.

host_ent->h_addr_list[0]. close(sd). /*************************************************/ /* Initiate the SSL handshake */ /*************************************************/ rc = SSL_Handshake(sslh.s_addr.s_addr = inet_addr(argv[1]). errno). if (rc < 0) { perror("connect() failed"). rc = connect(sd. return. return. if (sslh == NULL) { printf("SSL_Create() failed with errno = %d. (struct sockaddr *) &addr. } /*************************************************/ /* Set the input fields of the SSLHandle */ /* structure */ /*************************************************/ sslh -> protocol = 3. host_ent->h_length). /***********************************************/ addr.\n". } memcpy((char *)&addr. sizeof(addr)).sin_family = AF_INET.sin_addr. close(sd).} else if (isdigit(*argv[1])) { /***********************************************/ /* Use the IP address that is passed */ /***********************************************/ addr. sslh -> cipherSuiteListLen = 0.sin_addr.s_addr = htonl(INADDR_ANY). SSL_ENCRYPT). sslh -> timeout = 0. addr. return. addr. } /*************************************************/ /* Enable SSL support for the connection */ /*************************************************/ sslh = SSL_Create(sd. SSL_HANDSHAKE_AS_CLIENT). } else { /***********************************************/ /* Get the IP address of the host name that */ /* is passed in */ /***********************************************/ host_ent = gethostbyname(argv[1]). sizeof(addr)). if (host_ent == NULL) { printf("Host not found!\n").sin_port = 12345. 134 Socket programming . sslh -> cipherSuiteList = NULL. 0x00.sin_addr. } /*************************************************/ /* Connect to the server */ /*************************************************/ memset((char *) &addr.

} return. Chapter 7. /*************************************************/ /* Close the connection */ /*************************************************/ close(sd). errno). bufferLen). SSL_Destroy(sslh). rc. if (rc != bufferLen) { if (rc < 0) { printf("SSL_Write() failed with rc = %d " "and errno = %d. Examples: Using sockets 135 . /*************************************************/ /* Receive the message from the server using the */ /* secure session */ /*************************************************/ rc = SSL_Read(sslh. return. writeBuff. } /*************************************************/ /* Send a message to the server using the secure */ /* session */ /*************************************************/ strcpy(writeBuff. bufferLen = strlen(writeBuff). } /*************************************************/ /* Disable SSL support for the connection */ /*************************************************/ SSL_Destroy(sslh). return.\n".\n". return. readBuff. close(sd).rc). if (rc < 0) { printf("SSL_Read() failed with rc = %d.\n"). SSL_Destroy(sslh). bufferLen).rc. return. bufferLen). close(sd). close(sd). 0x00.if (rc != 0) { printf("SSL_Handshake() failed with rc = %d " "and errno = %d. } } /*************************************************/ /* memset readBuff to hex zeros */ /*************************************************/ memset((char *) readBuff. SSL_Destroy(sslh). close(sd).\n". errno)."Test of SSL_Write \n\n"). } else { printf("SSL_Write() did not write all data. rc = SSL_Write(sslh.

bind().h> <fcntl. so you do not need to assign the file offset field. and listen() to create a listening socket. parms. This call is a combination of the accept(). The server calls open() to open the file whose name was obtained as data on the accept_and_recv() from the client application. 7. 136 Socket programming . rc. num.Examples: Establishing communications using the send_file() and accept_and_recv() APIs The following examples enable a server to communicate with a client by using the send_file() and accept_and_recv() APIs. The SF_CLOSE flag informs the send_file() API that it should automatically close the socket connection when the last byte of the file and the trailer buffer (if specified) have been sent successfully. The server calls accept_and_recv() to wait for an incoming connection and to wait for the first data buffer to arrive over this connection. This call returns the number of bytes that is received and the local and remote addresses that are associated with this connection. Example: Connecting a server using the send_file() API The following example enables a server to perform the steps listed below to communicate with a client by using the send_file() and accept_and_recv() APIs: 1. size_t remote_addr_length. The system is not sending a header buffer and trailer buffer.h> #define SERVER_PORT 12345 main (int argc. 4. listen_sd. and recv() APIs. The application does not need to call close() if the SF_CLOSE flag is specified. char *argv[]) { int i. The steps that are needed for the server example differ from the steps that are needed for the client example. int fd. 2. 3. The server specifies the SF_CLOSE flag on the send_file() API. The server sets the file descriptor field to the value that open() returned. 5. The server calls send_file() to transmit the contents of the file. accept_sd = -1.h> <sys/socket. The server then sets the file bytes field to -1 to indicate that the server should send the entire file.h> <errno. size_t total_sent. flag = 1. memset() is used to set all of the fields of the sf_parms structure to an initial value of 0. The server initializes the local and remote address structures. send_file() is more efficient because the application does not have to go into a read() and send() loop until the file finishes. remote_addr. The server calls socket(). send_file() does not complete until the entire file has been sent or an interrupt occurs.h> <stdlib. The system is sending the entire file. 6. getsockname(). local_addr.h> <netinet/in. so these fields do not fill. #include #include #include #include #include #include <stdio. size_t local_addr_length. struct struct struct struct sockaddr_in sockaddr_in sockaddr_in sf_parms addr.

s_addr = htonl(INADDR_ANY).sin_port = htons(SERVER_PORT). rc = bind(listen_sd. addr. SOCK_STREAM.sin_family = AF_INET. close(listen_sd). Examples: Using sockets 137 . exit(-1). addr. 5). sizeof(addr)). if (listen_sd < 0) { perror("socket() failed"). sizeof(addr)). sizeof(flag)). (char *)&flag. addr. if (rc < 0) { perror("listen() failed"). close(listen_sd).sin_addr. } /*************************************************/ /* Set the listen backlog */ /*************************************************/ rc = listen(listen_sd. } /*************************************************/ /* Bind the socket */ /*************************************************/ memset(&address. if (rc < 0) { perror("bind() failed"). if (rc < 0) { perror("setsockop() failed"). SO_REUSEADDR. SOL_SOCKET. close(listen_sd). use it to */ /* control the number of incoming connections */ /*************************************************/ if (argc >= 2) num = atoi(argv[1]). exit(-1).char buffer[255]. exit(-1). /*************************************************/ /* Create an AF_INET stream socket to receive */ /* incoming connections on */ /*************************************************/ listen_sd = socket(AF_INET. /*************************************************/ /* If an argument is specified. } /*************************************************/ /* Set the SO_REUSEADDR bit so that you do not */ /* have to wait 2 minutes before restarting */ /* the server */ /*************************************************/ rc = setsockopt(listen_sd. 0. else num = 1. 0). exit(-1). } Chapter 7. (struct sockaddr *)&addr.

&accept_sd. rc = accept_and_recv(listen_sd. close(listen_sd). O_RDONLY). remote_addr_length = sizeof(remote_addr). sizeof(parms)). /**********************************************/ /* Loop until the entire file has been sent */ /**********************************************/ 138 Socket programming . buffer). (struct sockaddr *)&remote_addr. i+1). /**********************************************/ /* Initialize the counter of the total number */ /* of bytes sent */ /**********************************************/ total_sent = 0./*************************************************/ /* Initialize the local and remote addr lengths */ /*************************************************/ local_addr_length = sizeof(local_addr). parms. close(listen_sd). /*************************************************/ /* Go through the loop once for each connection */ /*************************************************/ for (i=0. 0. } /**********************************************/ /* Initialize the sf_parms structure */ /**********************************************/ memset(&parms. /*************************************************/ /* Inform the user that the server is ready */ /*************************************************/ printf("The server is ready\n"). if (fd < 0) { perror("open() failed"). exit(-1).file_bytes = -1. sizeof(buffer)). &remote_addr_length. i < num. close(accept_sd).file_descriptor = fd. parms. &local_addr_length. /**********************************************/ /* Open the file to retrieve */ /**********************************************/ fd = open(buffer. } printf(" Request for file: %s\n". exit(-1). if (rc < 0) { perror("accept_and_recv() failed"). (struct sockaddr *)&local_addr. printf(" waiting on accept_and_recv()\n"). &buffer. i++) { /**********************************************/ /* Wait for an incoming connection */ /**********************************************/ printf("Iteration: %d\n". close(accept_sd).

SF_CLOSE). the program prompts the user to enter a file name.h> <stdio. close(accept_sd). /*************************************************/ /* Close the accept socket */ /*************************************************/ if (accept_sd != -1) close(accept_sd). A server application sends the contents of the specified file to the client. /*************************************************/ /* Close the listen socket */ /*************************************************/ close(listen_sd). if (rc < 0) { perror("send_file() failed"). #include #include #include #include <ctype. The first parameter (if specified) is the dotted-decimal IP address or the host name where the server application is located. } total_sent += parms. total_sent). 4. If the user does not specify a second parameter. Examples: Using sockets 139 . then the client uses INADDR_ANY for the server’s IP address. If the user does not specify any parameters. The client calls connect() to establish a connection to the server. close(fd). exit(-1). } while (rc == 1). printf(" Total number of bytes sent: %d\n".h> <netdb. } /**********************************************/ /* Close the file that is sent out */ /**********************************************/ close(fd). 5.bytes_sent. 2. This client program takes from zero to two parameters. } Example: Connecting a client using the accept_and_recv() API The following example enables a client to perform the steps listed below and to communicate with a server by using the accept_and_recv() API: 1.h> <stdlib. The second parameter (if specified) is the name of the file that the client attempts to obtain from the server. The client calls close() to close the socket. The client calls send() to inform the server what file name it wants to obtain. Step one obtained the IP address of the server. The client calls socket() to create a socket descriptor. close(listen_sd). Step one obtained the name of the file. 3.do { rc = send_file(&accept_sd.h> Chapter 7. The client goes into a ″do″ loop calling recv() until the end of the file is reached. &parms. 6. A return code of 0 on the recv() means that the server closed the connection.

#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define SERVER_PORT 12345 main (int argc, char *argv[]) { int rc, sockfd; char char filename[256]; buffer[32 * 1024];

struct sockaddr_in addr; struct hostent *host_ent; /*************************************************/ /* Initialize the socket address structure */ /*************************************************/ memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(SERVER_PORT); /*************************************************/ /* Determine the host name and IP address of the */ /* machine the server is running on */ /*************************************************/ if (argc < 2) { addr.sin_addr.s_addr = htonl(INADDR_ANY); } else if (isdigit(*argv[1])) { addr.sin_addr.s_addr = inet_addr(argv[1]); } else { host_ent = gethostbyname(argv[1]); if (host_ent == NULL) { printf("Host not found!\n"); exit(-1); } memcpy((char *)&addr.sin_addr.s_addr, host_ent->h_addr_list[0], host_ent->h_length); } /**************************************************/ /* Check to see if the user specified a file name */ /* on the command line */ /**************************************************/ if (argc == 3) { strcpy(filename, argv[2]); } else { printf("Enter the name of the file:\n"); gets(filename); } /*************************************************/ /* Create an AF_INET stream socket */ /*************************************************/ sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0)

140

Socket programming

{

} printf("Socket completed.\n"); /*************************************************/ /* Connect to the server */ /*************************************************/ rc = connect(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); if (rc < 0) { perror("connect() failed"); close(sockfd); exit(-1); } printf("Connect completed.\n"); /*************************************************/ /* Send the request over to the server */ /*************************************************/ rc = send(sockfd, filename, strlen(filename) + 1, 0); if (rc < 0) { perror("send() failed"); close(sockfd); exit(-1); } printf("Request for %s sent\n", filename); /*************************************************/ /* Receive the file from the server */ /*************************************************/ do { rc = recv(sockfd, buffer, sizeof(buffer), 0); if (rc < 0) { perror("recv() failed"); close(sockfd); exit(-1); } else if (rc == 0) { printf("End of file\n"); break; } printf("%d bytes received\n", rc); } while (rc > 0); /*************************************************/ /* Close the socket */ /*************************************************/ close(sockfd);

perror("socket() failed"); exit(-1);

}

Chapter 7. Examples: Using sockets

141

142

Socket programming

.

A.Printed in U. .S.

Sign up to vote on this title
UsefulNot useful