Solved

Unix Socket Programming - Get Host information and send file contents to the server client.

Posted on 2003-11-13
20
348 Views
Last Modified: 2007-12-19
Hi All,

I'm very new to programming and especially socket programming, I'm trying to write a client which does the following over TCP:

- Gets the fqdn of the server
- Gets any other names that the server may be known by
- Gets the IP address of the server
- Reads the contents of a file in the current directory and sends the contents to the server client. The file will contain about 36characters max.
- Waits to get an ACK from the on successfull receipt of the full message and displays that the message has been received by the server.

The server piece is deployed on the same machine and is listening on port 54203.

I have no idea where to begin and what to do here, can somebody please help.  

Thanks!!

This is what I have been able to piece together so far, what include files should I include??

return_value = gethostname(name_buffer,sizeof(name_buffer));
 
  if (return_value == 0) {           //got address
   
    s_hostent = gethostbyname(name_buffer);

     if (s_hostent != NULL) {    //got name of server
        for ( i = 0; s_hostent->h_addr_list[i] != 0; i++) {
        in_server_address.s_addr = *s_hostent->h_addr_list[i];
        printf("Server is running on %s...\n",inet_ntoa(in_server_address));
      }
     
    }

}



int name=strlen(filename);
send(name,4)
send(nameof(filename));
while(eof)
{
readfromfile
sendto socket;
}
close;

0
Comment
Question by:r5ur5
  • 6
  • 6
  • 4
  • +1
20 Comments
 
LVL 6

Expert Comment

by:GloomyFriar
ID: 9741525
windows? unix? ...?
0
 
LVL 45

Accepted Solution

by:
Kdo earned 250 total points
ID: 9741543

Hi r5ur5,

Here are the 5 steps that you described.  Let me address each of them:

- Gets the fqdn of the server

From where?  The address will need to come from a configuration file, variable, or typed by a user.

- Gets any other names that the server may be known by

If you've got access to linux source, look over the code for dig() and nslookup().  You will have to query a DNS for the other names and both of these routines display all of the names known to the DNS.

- Gets the IP address of the server

The same code that gets all of the registered names from the DNS will also get the IP address.

- Reads the contents of a file in the current directory and sends the contents to the server client. The file will contain about 36characters max.

"to the server client"?  I assume that you mean "to the server socket".  Very easy.  The server is in a listen() state on the socket and when something arrives it does a read on the socket.  The client program attempts to open a socket connection on the port, and once complete writes the message to the socket.

- Waits to get an ACK from the on successfull receipt of the full message and displays that the message has been received by the server.

If you're using TCP, you can safely assume that the message arrived at the server.  If you really do want to receive a return message, the server needs to send a message back to the client.


Kent
0
 

Author Comment

by:r5ur5
ID: 9741597
The client is what I will need to write up and the server piece is already written and deployed on the same machine. The environment is UNIX. The client code needs to determine what the ip address of the host is (on which the client  & the server code both are deployed), what the fully qualified domain name of the host is and also if there are any aliases. I don't know if my implementation of the gethostname is correct or not.

Hope this helps.

Thanks.
0
 
LVL 45

Expert Comment

by:Kdo
ID: 9741760


Let's start from the middle and work out.  :)

Since the client and the server are running on the same machine, you can start by testing the connect/send/receive logic.

Connect to the socket on IP address 127.0.0.1 (localhost).  The system will connect your client to the server running on the same machine that is listening to the specified port.  You can then send and receive data and make sure that your "protocols" are correct.

Then we can work backwards, and build in the communications necessary to move the client to another machine.

Kent
0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 9745618
I think Kents questions are important before you can get appropriate help...
>From where?  The address will need to come from a configuration file, variable, or typed by a user.
to add, you may need to query a DNS ....

so address his questions one by one just like he addressed your issues in his post
0
 

Author Comment

by:r5ur5
ID: 9748357
Kent,

I'm not sure how the address and alias information will be taken, that is why I was thinking of using gethostbyname() function and gethostaddr(). The server code and the client code are both to reside on the same physical box, but the requirement here is still to get the actual IP address of that machine and any aliases associated with it. I can try to use the functions above and see if there is any reverse lookup function also.

As for sending the conetnets of the file, I assume I would first need to initiate the socket (in client code) to connect to the server side socket and then do read, write functions. The only problem is I have no idean on how to write syntax I will still try. Your help is greatly appreciated.

Thanks a ton.  :-)

0
 
LVL 45

Expert Comment

by:Kdo
ID: 9748574

You gethostname() and gethostbyname() calls look good so you should have a valid host_ent pointer.

However, your setting of in_server_addr.s_addr is suspect.  It appears that you are trying to move the IP address one octet (byte) at a time, but the result seems to be that each octet is copied into the same cell.  You need to index the receiving field as well.


Kent
0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 9753446
>I'm very new to programming and especially socket programming
http://www.ecst.csuchico.edu/~beej/guide/net/html/
read this tutorial ... It is simple and easy to follow ... you will feel lot more confident after reading this.
here is a section from that tutorial which guides you how to use gethostbyname and related functions

4.10. gethostname()--Who am I?
Even easier than getpeername() is the function gethostname(). It returns the name of the computer that your program is running on. The name can then be used by gethostbyname(), below, to determine the IP address of your local machine.

What could be more fun? I could think of a few things, but they don't pertain to socket programming. Anyway, here's the breakdown:

    #include <unistd.h>

    int gethostname(char *hostname, size_t size);

 

The arguments are simple: hostname is a pointer to an array of chars that will contain the hostname upon the function's return, and size is the length in bytes of the hostname array.

The function returns 0 on successful completion, and -1 on error, setting errno as usual.

4.11. DNS--You say "whitehouse.gov", I say "198.137.240.92"
In case you don't know what DNS is, it stands for "Domain Name Service". In a nutshell, you tell it what the human-readable address is for a site, and it'll give you the IP address (so you can use it with bind(), connect(), sendto(), or whatever you need it for.) This way, when someone enters:

    $ telnet whitehouse.gov

 

telnet can find out that it needs to connect() to "198.137.240.92".

But how does it work? You'll be using the function gethostbyname():

    #include <netdb.h>
   
    struct hostent *gethostbyname(const char *name);

 

As you see, it returns a pointer to a struct hostent, the layout of which is as follows:

    struct hostent {
        char    *h_name;
        char    **h_aliases;
        int     h_addrtype;
        int     h_length;
        char    **h_addr_list;
    };
    #define h_addr h_addr_list[0]

 

And here are the descriptions of the fields in the struct hostent:


h_name -- Official name of the host.

h_aliases -- A NULL-terminated array of alternate names for the host.

h_addrtype -- The type of address being returned; usually AF_INET.

h_length -- The length of the address in bytes.

h_addr_list -- A zero-terminated array of network addresses for the host. Host addresses are in Network Byte Order.

h_addr -- The first address in h_addr_list.

gethostbyname() returns a pointer to the filled struct hostent, or NULL on error. (But errno is not set--h_errno is set instead. See herror(), below.)

But how is it used? Sometimes (as we find from reading computer manuals), just spewing the information at the reader is not enough. This function is certainly easier to use than it looks.

Here's an example program:

    /*
    ** getip.c -- a hostname lookup demo
    */

    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <netdb.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>

    int main(int argc, char *argv[])
    {
        struct hostent *h;

        if (argc != 2) {  // error check the command line
            fprintf(stderr,"usage: getip address\n");
            exit(1);
        }

        if ((h=gethostbyname(argv[1])) == NULL) {  // get the host info
            herror("gethostbyname");
            exit(1);
        }

        printf("Host name  : %s\n", h->h_name);
        printf("IP Address : %s\n", inet_ntoa(*((struct in_addr *)h->h_addr)));
       
       return 0;
    }

 

With gethostbyname(), you can't use perror() to print error message (since errno is not used). Instead, call herror().

It's pretty straightforward. You simply pass the string that contains the machine name ("whitehouse.gov") to gethostbyname(), and then grab the information out of the returned struct hostent.

The only possible weirdness might be in the printing of the IP address, above. h->h_addr is a char*, but inet_ntoa() wants a struct in_addr passed to it. So I cast h->h_addr to a struct in_addr*, then dereference it to get at the data.


I would strongly advise reading the guide thorougly... As a matter of fact, it covers almost everything you will need to code your application (except file opening and reading ;o))

Cheers!
Sunny:o)
0
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 

Author Comment

by:r5ur5
ID: 9767726
Sunny,

Thanks so much for directing me to the site, this is what I have been able to put together. I still need to know how to get a list of all the aliases for a host, and also need to figure out how to wait for an ack from the server and display that on screen. Can you please help me with that? PLease please please.

******CODE*************

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define SERVER_PORT 54203
#define BUF_SIZE 512
//#define h_addr h_addr_list[0]



int main(int argc, char *argv[])
    {
        int sd, rc, i;
        struct sockaddr_in localAddr, servAddr;
        struct hostent *h;
        FILE *f;
        char s[64];
        char send_to_buf[BUF_SIZE];
        char file_name[64];

        if (argc != 2) {  // error check the command line
            fprintf(stderr,"usage: ./client [hostname]\n");
            exit(1);
        }

        if ((h=gethostbyname(argv[1])) == NULL) {  // get the host info
            herror("gethostbyname");
            exit(1);
        }

        printf("Host name  : %s\n", h->h_name);
        printf("IP Address : %s\n", inet_ntoa(*((struct in_addr *)h->h_addr)));
        printf("Alias Name : %s\n", h->h_aliases);   *****THIS GIVE A BLANK LINE RIGHT NOW**
        //return 0;

        servAddr.sin_family = h->h_addrtype;
        memcpy((char *) &servAddr.sin_addr.s_addr, h->h_addr_list[0], h->h_length);
        servAddr.sin_port = htons(SERVER_PORT);

        /* create socket */
        sd = socket(AF_INET, SOCK_STREAM, 0);
        if(sd<0) {
        perror("cannot open socket ");
exit(1);
        }

        /* bind any port number */
        localAddr.sin_family = AF_INET;
        localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
        localAddr.sin_port = htons(0);

        rc = bind(sd, (struct sockaddr *) &localAddr, sizeof(localAddr));
        printf("%s: bind port TCP %u\n",argv[0],SERVER_PORT);
        if(rc<0) {
        printf("%s: cannot bind port TCP %u\n",argv[0],SERVER_PORT);
        perror("error ");
        exit(1);
        }

        /* connect to server */
        rc = connect(sd, (struct sockaddr *) &servAddr, sizeof(servAddr));
        if(rc<0) {
        perror("cannot connect ");
        exit(1);
        }

        for(i=2;i<argc;i++) {

        rc = send(sd, argv[i], strlen(argv[i]) + 1, 0);

        if(rc<0) {
        perror("cannot send data ");
        close(sd);
        exit(1);

    }

    printf("%s: data%u sent (%s)\n",argv[0],i-1,argv[i]); ***DON't know what this means****


  }
        //f=fopen("input.txt","r");   ****I would like to use this function, where the name of the file
        //if (!f)                              ****is static but don't know how to pass that to the buffer.
        //      return 1;
        //while (fgets(s,64,f) !=NULL)
        //fgets(send_to_buf, BUF_SIZE, f);
        //printf("\ndata: %s\n", send_to_buf);

        //fclose(f);
        printf("\nPlease enter the name of the file to transmit: ");
        fgets(file_name, 64, stdin);
      file_name[strlen(file_name)-1] = '\0';

        if((f = fopen(file_name, "rt")) == NULL)
        {
                herror("fopen");
                return -1;
        }
        fgets(send_to_buf, BUF_SIZE, f);
        printf("\ndata: %d\n", send_to_buf);
        fclose(f);

return 0;
  *****HOW DO I WAIT FOR AN ACK FROM THE SERVER THAT DATA IS RECEIVED??*********
}

**********END CODE************


Thanks a ton!!

r5ur5
0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 9769006
> still need to know how to get a list of all the aliases for a host, and
look at the following section very carefully and you would know
But how does it work? You'll be using the function gethostbyname():

   #include <netdb.h>
   
   struct hostent *gethostbyname(const char *name);

 

As you see, it returns a pointer to a struct hostent, the layout of which is as follows:

   struct hostent {
       char    *h_name;
       char    **h_aliases;
       int     h_addrtype;
       int     h_length;
       char    **h_addr_list;
   };
   #define h_addr h_addr_list[0]

 

And here are the descriptions of the fields in the struct hostent:


h_name -- Official name of the host.

*** h_aliases -- A NULL-terminated array of alternate names for the host. ****

h_addrtype -- The type of address being returned; usually AF_INET.

h_length -- The length of the address in bytes.

h_addr_list -- A zero-terminated array of network addresses for the host. Host addresses are in Network Byte Order.

h_addr -- The first address in h_addr_list.


>also need to figure out how to wait for an ack from the server and display that on screen.
If you are using connected sockets/TCP sockets/SOCK_STREAM (which as I see you are), then you do not need a separate ACk .. the ACK is received and processed by the underlying protocol before it shows you success.
0
 

Author Comment

by:r5ur5
ID: 9778238
Sunny,

Thanks for the description, I guess I had overlooked this while reading the guide it makes sense now. My only doubt at this point is the code about opening the file and sending the data in the file to the server. How can I make the commented code work?

 //f=fopen("input.txt","r");   ****I would like to use this function, where the name of the file
        //if (!f)                              ****is static but don't know how to pass that to the buffer.
        //      return 1;
        //while (fgets(s,64,f) !=NULL)
        //fgets(send_to_buf, BUF_SIZE, f);
        //printf("\ndata: %s\n", send_to_buf);

        //fclose(f);

This does not ask the user to input a file but instead picks the file directly from the working path, how would I make sure that the file is being read and the data is being sent.  With the following code :

printf("\nPlease enter the name of the file to transmit: ");
        fgets(file_name, 64, stdin);
     file_name[strlen(file_name)-1] = '\0';

        if((f = fopen(file_name, "rt")) == NULL)
        {
                herror("fopen");
                return -1;
        }
        fgets(send_to_buf, BUF_SIZE, f);
        printf("\ndata: %d\n", send_to_buf);
        fclose(f);

return 0;

I am able to get some indication that data was sent, I get back something like  -4245921 (this is not the exact number but) this is what I get back. Is there any way to put a check somewhere to see whether the data is actually being sent or not?

Thanks,
r5ur5



0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 9778309
      f=fopen("input.txt","r");

       if ( f == NULL )        
             return 1;

       while (fgets(s,64,f) !=NULL)      
             printf("\ndata: %s\n", s);

       fclose(f);

to send, add a send() in the while loop ...

> Is there any way to put a check somewhere to see whether the data is actually being sent or not?
check return value of send() .. also check the contents received at the server side
0
 

Author Comment

by:r5ur5
ID: 9779009
I added the following:

f=fopen("input.txt","r");

       if ( f == NULL )        
             return 1;

       while (fgets(s,64,f) !=NULL)
             rc = send(sd, argv[i], strlen(argv[i]) + 1, 0)
             printf("\ndata: %s\n", s);

       fclose(f);

The program complies but I get a message when running, "Segmentation Fault".  No idea what this means...


0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 9779059
segmentation fault means that you are trying to access memory which does not belong to your process
 
while (fgets(s,64,f) !=NULL)  .... what is the declaration for s .. does it have 64 bytes ?
{
             rc = send(sd, argv[i], strlen(argv[i]) + 1, 0);     .... you read from file in buffer s but you are sending argv[i] ????
             printf("\ndata: %s\n", s);
}
0
 

Author Comment

by:r5ur5
ID: 9779125
s is defined as:

char s[64];

what should I be sending instead of argv?

changed the send to following:

f=fopen("input.txt","rt");
        if (f == NULL)
                return 1;
        while (fgets(s,64,f) !=NULL)
        {
              rc = send(sd, s, strlen(s) + 1, 0);
              printf("\ndata: %s\n", send_to_buf);
        }
        fclose(f);

Program complies and runs but I see the value of Data: being output to screen as blank, does this mean that data has been sent.
Unfortunately I don't have access to the server code to verify the receipt of data. I am really really greatful for your help!

Thank you so much!


0
 
LVL 45

Assisted Solution

by:sunnycoder
sunnycoder earned 250 total points
ID: 9785862
f=fopen("input.txt","rt");
       if (f == NULL)
               return 1;
       while (fgets(s,64,f) !=NULL)
       {
             rc = send(sd, s, strlen(s) +1 , 0);
             printf("\ndata: %s\n", s);
       }
       fclose(f);

are you sure your file will never have a line containing more than 64 chars ? If it has, this code will crash...

Also there is no error checking built into the program ... it is a good practice ....

right now,  what happens if fopen() fails .... you proceed with fgets() on an unopened file and program will crash ... such events are avoided by adding error checks and allowing application handle errors or at very minimum exit gracefully instead of crashing
0
 
LVL 45

Expert Comment

by:Kdo
ID: 10391969

Split 'em.
0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Summary: This tutorial covers some basics of pointer, pointer arithmetic and function pointer. What is a pointer: A pointer is a variable which holds an address. This address might be address of another variable/address of devices/address of fu…
This is a short and sweet, but (hopefully) to the point article. There seems to be some fundamental misunderstanding about the function prototype for the "main" function in C and C++, more specifically what type this function should return. I see so…
The goal of this video is to provide viewers with basic examples to understand recursion in the C programming language.
The goal of this video is to provide viewers with basic examples to understand and use conditional statements in the C programming language.

706 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now