Sunday, August 7, 2011

Obtaining the Socket Address


If a C library function that you wrote receives a socket as an input argument, then you will not know what the socket address of that socket is. This is because your function did not create the socket;
and, unless the socket address is also passed to your function as input, you will not know what the address is. The function getsockname(2) permits your function to obtain it. The function synopsis for getsockname(2) is as follows:

#include <sys/socket.h>
int getsockname(int s, struct sockaddr *name, socklen_t *namelen)

This function takes the following three input arguments:
  1. The socket s to query for the socket address.
  2. The pointer to the receiving buffer (argument name).
  3. Pointer to the maximum length variable. This variable provides the maximum length in bytes that can be received in the buffer (argument namelen). This value is updated with the actual number of bytes written to the receiving buffer.

Note that like the bind(2) function, getsockname(2) uses the generic address structure sockaddr because it can be used for any type of socket address. This will mean that you will likely need to apply the C language casting operator on the pointer supplied in this argument.

The length argument namelen specifies the maximum number of bytes that can be received into argument two (name). Prior to returning to the caller, however, the value of namelen is overwritten to indicate how many bytes were actually returned in the receiving buffer. This will be less than or equal to the original value supplied.

CAUTION
Never supply the address of a constant for the socket address length in a call to getsockname(2). This should not be done because the length variable is updated with the actual number of bytes placed into the receiving address structure.
If you do supply the address of a constant, the value of the constant will be overwritten. This will cause havoc in your program. On some CPU platforms, you might experience a program fault instead.

The function returns zero if it is successful. If an error occurs, the return value -1 is returned, and the reason for the error is posted to the variable errno.

Writing a sock_addr() Function

To illustrate the use of getsockaddr(2), a small function has been presented in Listing below which accepts as input a socket descriptor. The function obtains the socket's address by calling
getsockaddr(2), and then formats a string to be returned to the caller which can be used in a printf(3) call.


/* sckname.c:
 * Demonstrate getsockname(2):
 */
 #include <stdio.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>

/*
 * This saves lines of code later:
 */
 static void displayError(const char *on_what) {
    perror(on_what); /* Report error */
    exit(1);         /* Exit Program */
 }

/*
 * This function accepts as input a socket
 * for which a socket address must be
 * determined for it. Then the address
 * is converted into a string and returned.
 *
 * If an error occurs, NULL is returned.
 */
    char * sock_addr(int s,char *buf,size_t bufsiz) {
    int z;         /* Status return code */
    struct sockaddr_in adr_inet;/* AF_INET */
    int len_inet;  /* length */

/*
 * Obtain the address of the socket:
 */
    len_inet = sizeof adr_inet;

    z = getsockname(s, (struct sockaddr *)&adr_inet, &len_inet);

    if ( z == -1 ) {
       return NULL; /* Failed */
    }

/*
 * Convert address into a string
 * form that can be displayed:
 */
    snprintf(buf,bufsiz, "%s:%u",
    inet_ntoa(adr_inet.sin_addr),
    (unsigned)ntohs(adr_inet.sin_port));

    return buf;
 }

 /*
 * Main Program:
 */
 int  main(int argc,char **argv,char **envp) {
    int z; /* Status return code */
    int sck_inet; /* Socket */
    struct sockaddr_in adr_inet;/* AF_INET */
    int len_inet; /* length */
    char buf[64]; /* Work buffer */

/*
 * Create an IPv4 Internet Socket:
 */
    sck_inet = socket(AF_INET,SOCK_STREAM,0);

    if ( sck_inet == -1 ) {
       displayError("socket()");
    }
/*
 * Create an AF_INET address:
 */
    memset(&adr_inet,0,sizeof adr_inet);
    adr_inet.sin_family = AF_INET;
    adr_inet.sin_port = htons(9000);
    inet_aton ("127.0.0.24",&adr_inet.sin_addr);
    len_inet = sizeof adr_inet;

/*
 * Now bind the address to the socket:
 */
    z = bind(sck_inet,
    (struct sockaddr *)&adr_inet,
    len_inet);
    if ( z == -1 ) {
       displayError("bind()");
    }
/*
 * Now test our sock_addr() function:
 */
    if ( !sock_addr(sck_inet,buf,sizeof buf)) {
       displayError("sock_addr()");
}

    printf("Address is'%s'\n" ,buf);

    close(sck_inet);
    return 0;
 }
//OUTPUT:

/*
[sgupta@rhel55x86 Linux-Socket-Programming]$ gcc sckname.c -o sckname
[sgupta@rhel55x86 Linux-Socket-Programming]$ ./sckname
Address is'127.0.0.24:9000'
[sgupta@rhel55x86 Linux-Socket-Programming]$

 */

No comments:

Post a Comment