![]() |
Plugging Into OS/2 Socket Programming - Part 2/3Written by Edward Boykin |
IntroductionHello again folks. I'm sorry there was a delay between this article and my previous one. I am wrapping up my undergraduate studies at Georgia Tech and things have been a bit hectic. Last time I gave a quick introduction into what goes into making a very simple client/server program using OS/2's TCP/IP socket interface. This month I am not going to expand that client/server program but instead I will talk some more about the socket interface API functions. In particular, I will be discussing the socket utility functions. The socket utility functions perform a wide range of function from hostname, domain name, network and services information to internet address manipulation commands. I will be covering the most commonly used functions in this article and leaving infrequently used ones out. Let's get started!The Internet AddressAs I mentioned last time an internet address is a 32 bit number, usually represented by four 1-3 digit numbers separated by periods, e.g. 198.69.176.242. This number must be unique for each TCP/IP interface card within an administered AF_INET domain. Each TCP/IP machine on these networks is a host and it may have as many addresses as it has interfaces. For example, at home I have two network interfaces. One is my PPP connection to the internet and the other is for my ethernet card to my apartment's LAN. For a socket to be set, it must have the internet address and the port to connect to. The port is the entry point to an application on another host and is a 16 bit integer number. Some of the more common ports used are 110 for POP mail, 21 for FTP, and 23 for Telnet services. A complete list of the standard port numbers used is contained the SERVICES file in either the TCPIP/ETC or MPTN/ETC directories. Some Socket Data StructuresThere are two data structures I want to go over before start talking about the API functions. They are the hostent and _res structures. The hostent structure is returned by functions used for host name resolution and the _res structure is returned by the service name resolution commands. netdb.h defines the hostent structure like this: struct hostent { char *h_name; /* official name of host */ char **h_aliases; /* alias list */ int h_addrtype; /* host address type */ int h_length; /* length of address */ char **h_addr_list; /* list of addresses from name server */ };Figure 1: hostent structure The hostent structure will contain some or all of these fields depending on the function call you make. h_name is the host name of the machine. h_aliases is a list of aliases set up for that host name. h_addrtype is going to be AF_INET always for OS/2 since it currently only supports the TCP/IP addressing scheme for sockets. h_length will contain the length of the addresses in the h_addr_list and h_addr_list is a list of addresses to which that hostname belong. Remember, that I said a particular machine could have as many addresses as it has interfaces! The next structure is the _res structure. It is actually defined as the state structure but then _res is declared as an external instance of the state struct. struct state { int retrans; /* retransmission time interval */ int retry; /* number of times to retransmit */ long options; /* option flags */ int nscount; /* number of name servers */ struct sockaddr_in nsaddr_list[MAXNS]; /* address of name server */ unsigned short id; /* current packet id */ char defdname[MAXDNAME]; /* default domain */ char * dnsrch[MAXDNSRCH+1]; /* components of domain to search */ }; extern struct state _res;Figure 2: state structure You can see there are a lot of things contained in this structure. The parts we are most concerned with are the nsassr_list[MAXNS], and defdname[MAXDNAME]. These variables will hold the default domain name and the addresses of the host running the nameserver. The other components are used in ways I will not be covering in this article. Hostname Information APIsThere are five functions which comprise the hostname information API functions. I will only be discussing the two I feel are most commonly used by programmers. These are gethostbyname() and gethostbyaddr(). The functions are declared in the netdb.h header file. The first function is gethostbyname(). netdb.h declares the API function like this: struct hostent * _System gethostbyname( char * );Figure 3: gethostbyname() declaration The purpose of gethostbyname() is return the address of a hostname. The call will get this information from the nameserver or, if the nameserver isn't available, it will search your local hosts file. The only information this function needs is the string containing the hostname of the computer in question. The function returns this information in the hostent struct I talked about in the previous section. The address or addresses will be contained the h_addr_list section of the hostent structure. gethostbyaddr() is defined like this: struct hostent * _System gethostbyaddr( char *, int, int );Figure 4: gethostbyaddr() declaration gethostbyaddr() is used to obtain the symbolic hostname for a particular address. The information is obtained from the nameserver or the hosts files and stored in a hostent struct. The three parameters for this function are the address of the host, the length of the address in bytes, and the address type. The address must be the 32 bit network address in network byte order. I talked about converting to and from network and host byte orders in my last article. The length of the address is 4 bytes and the address is always AF_INET. The hostname will be in the h_name section of the structure. For a quick and dirty example I will use my own internet address and hostname. My hostname is aviator and my internet address is 168.121.51.106. If I wanted to get that hostname and I only knew the address I would call gethostbyaddr() or vice versa if I wanted the address but only knew the name. The functions simple and useful for just about any network program. Domain Name Resolution API'sThe domain name resolution API's are used to make queries to the nameserver about domain names and addresses. The two functions I will talk about are res_init() and res_mkquery(). res_init() is defined in resolv.h like this: void res_init();Figure 5: res_init() declaration It's a toughie, eh? The res_init() function is used to obtain the default domain name and the internet addresses of the initial hosts running the nameserver. It will read first from the RESOLV file then the HOSTS file on the local computer. One of these file should exist. An example of the RESOLV file is shown below. A RESOLV example is shown below: domain mindspring.com nameserver 204.180.128.4Figure 6: Sample RESOLV file res_mkquery() is a bit more difficult than res_init() is. It is defined in resolv.h as well and looks like this: int res_mkquery( int op, char* dname, int class, int type, char* data, int datalen, struct rrec* newrr, char* buf, int buflen );Figure 7: res_mkquery() declaration The parameters for this function are as follows: op - The is the type of query to be made. It is usually QUERY. This and
other types of queries are found in dname - This is a pointer to the domain name as found in the RESOLV file.
class - This will be set to C_IN for ARPA Internet.
type - This is the gusto part. Here you tell the nameserver what resource
or query you want. You can get all kinds of useful information like mail
routing information, user information, user or group ids, etc. The
complete list of types is in the nameser.h header file.
data - This is a pointer to the data you want to send to the nameserver as
part of a search key for the information you want.
datalen - This is the size of the data parameter in bytes.
newrr - This is reserved for future updates and is unused.
buf - This will be set to point to the data returned by the query.
buflen - This is the length of the buffer in bytes pointed to by buf.
Well that's about it for now. You now have all the information you should
need to manipulate internet addresses, hostnames and domain names. There a
slew of other functions which perform related operations but I feel these
are rarely going to be used except by advanced network programmers and,
therefore, they're beyond the scope of my introduction.
With the school quarter coming to a close I am very busy. I hope to be
able to finish writing the sample code for my next article during the
winter break. This will be a server which will accept multiple connections
simultaneously and be able to relay the data sent by each connection to
every other connection in a very basic client/server manner.
I included the sample code from my last article just in case some of you
didn't get it last time. There are no changes to it; however, I recommend
you try to add the use of the functions I talked about today into them and
see what results you get from them.
Thanks for reading. I hope you stay tuned for more...
|