Feedback Search Top Backward Forward
EDM/2

Plugging Into OS/2 Socket Programming - Part 2/3

Written by Edward Boykin

Linkbar

 
Part1 Part2 Part3

Introduction

Hello 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 Address

As 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 Structures

There 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 APIs

There 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's

The 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.4
Figure 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.

Wrap Up and Next Time

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...

 

Linkbar