Solved

FD_ISSET macro fails...

Posted on 2003-11-04
18
994 Views
Last Modified: 2012-06-21
Hi all,

I have a client server program. I am using both tcp and udp. The udp part is to basically tell a client that a server is running on that machine.The problem is that the third call to FD_ISSET fails(I have marked this with a comment //problem here). I would like to know why this is happening.Due to this reason none of the clients are able to contact the server. Can anybody help me out...The main loop of the server code is pasted below.

regards
balaji

int MainLoop(void)
{
      int client_len=0,       
                new_sock_des=0,
                sock_des=0,
      child_pid=0,
                retval=0,
                sock_opt;
         
        int   sockfdu; /*UDP socket*/
   
       char localhost[MAXHOSTNAME+1],
       display[50];
       struct hostent *hp;
       struct sockaddr_in   server_addr,
                client_addr;
        fd_set stReadFDs;
        fd_set stXcptFDs;
 

      if(InitSocket(localhost)!=TRUE)
          exit(1);

/* Get the host name and other info on which this server is run */
     if((hp = gethostbyname(localhost)) == NULL)
         err_sys("Socket Error:Cant get localhost info");

 /*Create a tcp socket */
    if((sock_des=socket(AF_INET,SOCK_STREAM,0))<0)
       err_sys("Socket Error:Cant create TCP Socket");

   /*Create a udp socket */
   if( (sockfdu = socket (AF_INET, SOCK_DGRAM,IPPROTO_UDP)) <0)
      err_sys("Socket Error:Cant create UDP Socket\n");  

     memset((char *) &server_addr,0,sizeof(server_addr));
     server_addr.sin_family=AF_INET;
     server_addr.sin_port= htons((unsigned short)Port_number);
     server_addr.sin_addr.s_addr = htonl (INADDR_ANY);
      
/* Tell the system to allow local addresses to be reused. */
     sock_opt = 1;
if (setsockopt(sock_des, SOL_SOCKET, SO_REUSEADDR, (void *)&sock_opt,sizeof (sock_opt)) == -1) {
         (void) close(sock_des);
         //return (-1);
 }


  /* Bind to the address and listen on tcp socket */
   if(bind(sock_des,(struct sockaddr *)&server_addr, sizeof(server_addr))<0)
       err_sys("Socket Error:TCP bind not successful,port no %d used by some other application",Port_number);

     
   listen(sock_des,Q_LEN);

   /* Bind to the address and listen on udp socket */
   if (bind(sockfdu, (struct sockaddr *) &server_addr, sizeof(server_addr)))
       err_sys("Socket Error:UDP bind not successful,port no %d used by some other application",Port_number);

      
   client_len=sizeof(client_addr);
      
   FD_ZERO(&stReadFDs);
   FD_ZERO(&stXcptFDs);
   FD_SET(sockfdu,&stReadFDs);
   FD_SET(sockfdu,&stXcptFDs);
   FD_SET(sock_des,&stReadFDs);
   FD_SET(sock_des,&stXcptFDs);
   

while(1)
{

     errno=0;
     retval=select(FD_SETSIZE,  &stReadFDs, NULL, &stXcptFDs, NULL);
         
      if(errno == EINTR)
      {
         FD_ZERO(&stReadFDs);
         FD_ZERO(&stXcptFDs);
         FD_SET(sockfdu,&stReadFDs);
         FD_SET(sockfdu,&stXcptFDs);
         FD_SET(sock_des,&stReadFDs);
         FD_SET(sock_des,&stXcptFDs);
         continue;
      }
   if(retval == -1)
   {
           perror("problem with select");
               exit(0);
   }
   else if (retval!=0)
   {
        if(FD_ISSET(sockfdu,&stXcptFDs))
         {
             err_ret("some exception occured \n");
             exit(0);
         }
        if(FD_ISSET(sock_des,&stXcptFDs))
        {
           err_ret("some other exception occured \n");
           exit(0);
         }
}

if(FD_ISSET(sock_des,&stReadFDs))//problem here....
{
 new_sock_des=accept(sock_des,(struct sockaddr *)&client_addr,(unsigned int*)&client_len);
  if(new_sock_des<0)
   {
      err_ret("Spotsd :accept not successful");
      continue;
   }
         
   CallProcessRequest(sock_des,new_sock_des,client_addr);
      
          
}
 else if(FD_ISSET(sockfdu,&stReadFDs))
         AutoDetectSendMessage(sockfdu);

  }  /* End of while */
}
0
Comment
Question by:balajis79
  • 8
  • 5
  • 2
  • +1
18 Comments
 
LVL 45

Expert Comment

by:sunnycoder
ID: 9677726
you call select and then you call FD_SET ?

it is the other way round ... you need FD_SET before select and also keep in mind that you need to set the FDs again before you call select()
0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 9677765
oops sorry ... I did not read carefully

anyway... you need to move the FD_SET staements inside the loop

from the man page
  On  success,  select  and  pselect  return  the number of descriptors contained in the descriptor sets, which may be zero if the timeout expires

so else if (retval != 0) would represent success and == 0 would represent time out ... so you need a bit of reorganization there
0
 
LVL 6

Expert Comment

by:Ajar
ID: 9677813
Hey you need to  do  "FD_ZERO " before calling select each time in the loop ....

0
 
LVL 45

Accepted Solution

by:
sunnycoder earned 100 total points
ID: 9677818
reorganize to something like this ....
while(1)
{

 FD_ZERO(&stReadFDs);
  FD_ZERO(&stXcptFDs);
  FD_SET(sockfdu,&stReadFDs);
  FD_SET(sockfdu,&stXcptFDs);
  FD_SET(sock_des,&stReadFDs);
  FD_SET(sock_des,&stXcptFDs);

    errno=0;
    retval=select(FD_SETSIZE,  &stReadFDs, NULL, &stXcptFDs, NULL);
       
      if(errno == EINTR)
     {
/*        FD_ZERO(&stReadFDs);
        FD_ZERO(&stXcptFDs);
        FD_SET(sockfdu,&stReadFDs);
        FD_SET(sockfdu,&stXcptFDs);
        FD_SET(sock_des,&stReadFDs);
        FD_SET(sock_des,&stXcptFDs);  */
        continue;
     }
  if(retval == -1)
  {
         perror("problem with select");
             exit(0);
  }
  else if (retval == 0)
  {
      /* time out will never happen since you gave NULL*/
 }
else
  {
       if(FD_ISSET(sockfdu,&stXcptFDs))
        {
            err_ret("some exception occured \n");
            exit(0);
        }
       if(FD_ISSET(sock_des,&stXcptFDs))
       {
          err_ret("some other exception occured \n");
          exit(0);
       
      if(FD_ISSET(sock_des,&stReadFDs))//problem here....
      {
       new_sock_des=accept(sock_des,(struct sockaddr *)&client_addr,(unsigned int*)&client_len);
        if(new_sock_des<0)
         {
                  err_ret("Spotsd :accept not successful");
                 continue;
         }
       
       CallProcessRequest(sock_des,new_sock_des,client_addr);              
     }

     else if(FD_ISSET(sockfdu,&stReadFDs))
        AutoDetectSendMessage(sockfdu);
 } /*end of else*/
  }  /* End of while */
}
0
 

Author Comment

by:balajis79
ID: 9677873
Dear Sunnycoder,

I tried out your solution but it did not solve the problem. Actually i forgot to mention something important last time. I am porting this code to run on netware 6.5 as an nlm (akin exe). When i run this piece of code on the netware server the problem occurs...

Balaji
0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 9677896
Ok, keep the FD_SETs inside the loop anyway...
FD_ISSET ia a macro... how did you deduce that this was the call that was failing ? may be the FD was really not set
0
 

Author Comment

by:balajis79
ID: 9677933
I put printf's after each statement to trace the flow(Unfortunately this is the only way to debug on a netware server). I found that it was never printing the one inside " if(FD_ISSET(sock_des, &stReadFDs))". Hence i deduced that this might be the problematic statement. (Actually i am new to socket programming...so please tell me if i have made any other error also). The FD_SETs part is duly noted.

Balaji
0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 9677994
>I found that it was never printing the one inside " if(FD_ISSET(sock_des, &stReadFDs))
how about the else part ... place a print in the else part ... may be the fd is not set !!
0
IT, Stop Being Called Into Every Meeting

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!

 

Author Comment

by:balajis79
ID: 9678028
The else part is always successful.(the one which checks for udp). I found that it always goes into the function AutoDetectSendMessage...
Balaji
0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 9678063
that would mean that sock_des is not set while sockfdu is set ... does not look like select() or FD_ISSET error...
 if that is not the correct behaviour for your application, look for logical errors (big pain)
0
 

Author Comment

by:balajis79
ID: 9678134
but when i print the sock_des value i get 6. Does is not mean that the sock_des is correct. In that case should it not get set?
0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 9678157
sock_des holds the int value by which system identifies this socket
FD_ISSET will show it set if and only if there was some activity at that socket (send/recv)
0
 
LVL 5

Expert Comment

by:mtmike
ID: 9678178
Your socket descriptors might be out of range. Netware has a FD_SETSIZE=16.

Make sure that
sock_des < FD_SETSIZE && sockfdu < FD_SETSIZE
0
 

Author Comment

by:balajis79
ID: 9678222
Dear mtmike,

I saw that FD_SETSIZE is set to 64 in select.h. Even other wise i get the values 6 & 7 for sock_des(tcp) and sockfdu(udp) respectively. So it is less than 16.

balaji

0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 9678264
sock_des and sockfdu are nothing but descriptors and have nothing to do with SETSIZE

from the man page
   The functions select and pselect wait for a number of file descriptors to change status.

so FD_ISSET will evaluate to true if there was a change in status... e.g. on a readfd, some data arrived.... it has nothing to do with actual value of the fd !!!
0
 
LVL 5

Assisted Solution

by:mtmike
mtmike earned 100 total points
ID: 9680110
On unix, socket/file descriptors are small integers and the fd_set structure is implemented as a bit set of some fixed size. The first argument to select is the highest numbered file descriptor in any of the three sets, plus one.

On netware, this function seems to be different:
http://developer.novell.com/ndk/doc/libc/index.html?page=/ndk/doc/libc/libc_enu/data/sdk86.html

I would try changing the first argument to select to 3 (2+1).

Also, check the return value of listen().

And, do make the changes sunnycoder suggested.
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

Have you thought about creating an iPhone application (app), but didn't even know where to get started? Here's how: ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Important pre-programming comments: I’ve never tri…
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 how to use strings and some functions related to them in the C programming language.
The goal of this video is to provide viewers with basic examples to understand opening and reading files in the C programming language.

758 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

19 Experts available now in Live!

Get 1:1 Help Now