🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: borland.public.cppbuilder.internet.socket
4 messages
4 total messages Started by jer Wed, 27 Sep 2006 21:24
select returns 10022 invalid argument error
#1906
Author: jer
Date: Wed, 27 Sep 2006 21:24
32 lines
2837 bytes
Hello, I'm a sockets newb looking for some advice from a vet. I'm using
Borland BCB6, Windows XP SP2, to write a program to communicate with
another computer on a network. I have a thread that sends data out of a
UDP socket periodically to the other computer. Before the sendto
function I always use select to determine if the socket is writable. I
have gotten the software to the point where I am able to send and
receive data correctly most of the time. However, intermittently, the
select statement times out (I set it to a 3 sec timeout). When this
happens I skip the sendto function and try the select again. At this
point, select returns SOCKET_ERROR and I get a 10022 error (invalid
argument) when I call WSAGetLastError(). From this point on, I use
select to check if the socket is writable and each time I get
SOCKET_ERROR with 10022.

After this happens, I have tried to diagnose what is going on in the
PC. I have tried pinging the other computer on the network, and I
always get "destination unreachable". Then I tried pinging localhost
and I get destination unreachable. If I ping any of the network cards
on the PC, even ones unrelated to the socket I'm using, I get
destination unreachable. I also cannot disable or enable any of the
network cards on the PC. The only way to remedy the situation at this
point is to power cycle the PC. Here are my questions:

1. Why would select suddenly timeout after working properly for 10
minutes?
2. Why would I get an invalid argument error after successfully using
the same select code many times before?
3. What could I be doing to break ping? Why can't I ping localhost?

Any hints or help searching for clues would be hugely appreciated.
Thanks,
Jer
Re: select returns 10022 invalid argument error
#1907
Author: Remy Lebeau (TeamB)
Date: Wed, 27 Sep 2006 23:28
60 lines
2850 bytes
"jer" <jer_bred_guy@yahoo.com> wrote in message
news:1159392295.406227.295400@e3g2000cwe.googlegroups.com...

> Before the sendto function I always use select to determine if the socket
is writable.

That is generally not a good idea.  You should just call sendto() by itself,
and let it report an error if it cannot send.

> However, intermittently, the select statement times out (I set it to
> a 3 sec timeout).  When this happens I skip the sendto function and try
> the select again. At this point, select returns SOCKET_ERROR and
> I get a 10022 error (invalid argument) when I call WSAGetLastError().

From the select() documentation:

    WSAEINVAL
    The timeout value is not valid, or all three descriptor parameters were
NULL.

Please show your actual socket code.

> From this point on, I use select to check if the socket is writable and
> each time I get SOCKET_ERROR with 10022.

My guess would be that your socket is no longer valid.

> After this happens, I have tried to diagnose what is going on in
> the PC. I have tried pinging the other computer on the network,
> and I always get "destination unreachable".

You lost your network connection.  Try rebooting the machine, and
double-check the network wires.

> Then I tried pinging localhost and I get destination unreachable.

You probably blew up the TCP/IP stack altogether.  Pinging the localhost
should never fail when TCP/IP is working properly.

> Why would select suddenly timeout after working properly for 10
> minutes?

Hard to say without seeing your actual code.

> Why would I get an invalid argument error after successfully
> using the same select code many times before?

Because the socket is no longer valid.

> What could I be doing to break ping?

Hard to say without seeing your actual code.

> Why can't I ping localhost?

Because TCP/IP is not working properly anymore.


Gambit
Re: select returns 10022 invalid argument error
#1908
Author: jer
Date: Thu, 28 Sep 2006 17:11
209 lines
7629 bytes
>> Before the sendto function I always use select to determine if the socket
>>is writable.
>That is generally not a good idea.  You should just call sendto() by itself,
>and let it report an error if it cannot send.

I'll give this a shot.

>> However, intermittently, the select statement times out (I set it to
>> a 3 sec timeout).  When this happens I skip the sendto function and try
>> the select again. At this point, select returns SOCKET_ERROR and
>> I get a 10022 error (invalid argument) when I call WSAGetLastError().
>From the select() documentation:
>WSAEINVAL
>The timeout value is not valid, or all three descriptor parameters were
>NULL.

>Please show your actual socket code.

See below.

>> Then I tried pinging localhost and I get destination unreachable.
>You probably blew up the TCP/IP stack altogether.  Pinging the localhost
>should never fail when TCP/IP is working properly.

Yeah, somehow I've managed to hang TCP/IP. I wonder if there's a way to
restart or reset TCP/IP without rebooting windows?

Here's some of my code.

//This is the code I use to set up the socket for sending data
//The parameters that are passed into the function are global,
//and are used in the send thread, see below.
int Start_UDP_Sock_Send(int* sockfd,
                     struct sockaddr_in* their_addr,
                     char* ip_addr,
                     int send_port)
{
   struct hostent *he;
   WSADATA wsaData;
   int error_status = 0;
   struct sockaddr_in my_addr;

   char host_name[80];

   //Begin setting up network socket
   if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
   {
      return error_status = -1;
   }

   //Set the address of the computer you want to send data to
   he = gethostbyname(ip_addr);

   //SOCK_DGRAM is used to set up a UDP socket
   if ((*sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
   {
      return error_status = -2;
   }

   //Next four lines set up network parameters
   (*their_addr).sin_family = AF_INET;     // host byte order
   (*their_addr).sin_port = htons(send_port); // short, network byte
order
   (*their_addr).sin_addr = *((struct in_addr *)he->h_addr);
   memset(&((*their_addr).sin_zero), '\0', 8); // zero the rest of the
struct

   //used to bind to a specific network interface on local pc
   my_addr.sin_family = AF_INET;         // host byte order
   my_addr.sin_port = 0;                 // short, network byte order
   if (strcmp(ip_addr, "10.100.4.200") == 0)
   {
      my_addr.sin_addr.s_addr = inet_addr("10.100.4.201");
   }
   else if (strcmp(ip_addr, "10.100.4.201") == 0)
   {
      my_addr.sin_addr.s_addr = inet_addr("10.100.4.200");
   }
   else if (strcmp(ip_addr, "localhost") == 0)
   {
      my_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
   }
   memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct

   if((bind(*sockfd, (struct sockaddr *)&my_addr, sizeof(struct
sockaddr)))==SOCKET_ERROR)
   {
      return error_status = -3;
   }

   return error_status;
}

//This function runs in a separate thread. It sends data on
//the socket set up above.
int __fastcall send_thread_function(LPVOID lpParam)
{
   int error_value = 0;

   char loc_send_buf[1024];
   memset(loc_send_buf, 0, 1024);

   //Variables for sleep timer resolution
   TIMECAPS tc;
   timeGetDevCaps(&tc, sizeof(TIMECAPS));
   //Set the resolution of the timer
   timeBeginPeriod(tc.wPeriodMin);

   int send_cnt = 0;

   //used for storing the pc time
   struct time pc_time;

   fd_set writefds;
   struct timeval tv;
   int sel_value = 0;
   // wait until either socket is ready to send or time out in 3
seconds
   tv.tv_sec = 3;
   tv.tv_usec = 0;

   FD_ZERO(&writefds);
   FD_SET(sockfd_send, &writefds);

   FILE* test_fptr;
   //write debug data to a text file
   test_fptr = fopen("C:\\send_log.log", "a+t");

   int error_code = 0;

   gettime(&pc_time);
   if (test_fptr != NULL)
   {
      //write data
      fprintf(test_fptr, "Started Send Thread ***** at: ");
      fprintf(test_fptr, "%02d:%02d:%02d:%d\n", pc_time.ti_hour,
pc_time.ti_min, pc_time.ti_sec, pc_time.ti_hund);
      fclose(test_fptr);
   }

   //This function runs in a separate thread. It's used to send data
   for(;;)
   {
      memset(loc_send_buf, 0, 1024);
      //memcpy send data out of the global buffer
      memcpy(loc_send_buf, glob_send_buf, 1024);

      //Use select to time out if data is not ready to be sent
      sel_value = select(2, NULL, &writefds, NULL, &tv);
      if (sel_value == 0)
      {
         gettime(&pc_time);
         //write debug data to a text file
         test_fptr = fopen("C:\\send_log.log", "a+t");
         if (test_fptr != NULL)
         {
            //write data
            fprintf(test_fptr, "send select time out at: ");
            fprintf(test_fptr, "%02d:%02d:%02d:%d\n", pc_time.ti_hour,
pc_time.ti_min, pc_time.ti_sec, pc_time.ti_hund);
            fclose(test_fptr);
         }
         Sleep(3000);
      }
      else if (sel_value == SOCKET_ERROR)
      {
         error_code = WSAGetLastError();

         gettime(&pc_time);
         //write debug data to a text file
         test_fptr = fopen("C:\\send_log.log", "a+t");
         if (test_fptr != NULL)
         {
            //write data
            fprintf(test_fptr, "select error: %d at: ", error_code);
            fprintf(test_fptr, "%02d:%02d:%02d:%d\n", pc_time.ti_hour,
pc_time.ti_min, pc_time.ti_sec, pc_time.ti_hund);
            fclose(test_fptr);
         }
         Sleep(3000);
      }
      else
      {
         error_value = sendto(sockfd_send,
                              loc_send_buf,
                              616,
                              0,
                              (SOCKADDR *)&their_addr_send,
                              sizeof(their_addr_send));

         if (error_value > 0)
         {
            send_cnt++;
            Sleep(5);
         }
         else
         {
            Sleep(5000);
         }
      }
   }
   return 0;
}

I have code that I use to receive data as well. I can put this code up
if you think it would help. Your first reply has me thinking of a few
things to try out in the mean time. Thanks so much for your help!
Jer
Re: select returns 10022 invalid argument error
#1910
Author: Remy Lebeau (TeamB)
Date: Thu, 28 Sep 2006 18:34
72 lines
3688 bytes
"jer" <jer_bred_guy@yahoo.com> wrote in message
news:1159444802.345644.119460@m7g2000cwm.googlegroups.com...

> Yeah, somehow I've managed to hang TCP/IP. I wonder if there's a
> way to restart or reset TCP/IP without rebooting windows?

Nope.

> This is the code I use to set up the socket for sending data
> The parameters that are passed into the function are global,
> and are used in the send thread, see below.

Are you protecting your globals from multi-threaded access properly?

>    if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)

Why are you calling WSAStartup() for each new socket?  You do not even need
to call it for each individual thread.  You should only be calling it once
at program startup.

>    //Set the address of the computer you want to send data to
>    he = gethostbyname(ip_addr);

You are not checking for errors in resolving the remote computer.
gethostbyname() will return a NULL pointer if it fails.

>    (*their_addr).sin_family = AF_INET;     // host byte order
>    (*their_addr).sin_port = htons(send_port); // short, network byte
> order
>    (*their_addr).sin_addr = *((struct in_addr *)he->h_addr);
>    memset(&((*their_addr).sin_zero), '\0', 8); // zero the rest of the
> struct

Use the '->' operator instead of the '*' operator:

    their_addr->sin_family = AF_INET;     // host byte order
    their_addr->sin_port = htons(send_port); // short, network byte order
    their_addr->sin_addr = *((struct in_addr *)he->h_addr);
    memset(their_addr->sin_zero, '\0', 8); // zero the rest of the struct


>    if (strcmp(ip_addr, "10.100.4.200") == 0)
>    {
>       my_addr.sin_addr.s_addr = inet_addr("10.100.4.201");
>    }
>    else if (strcmp(ip_addr, "10.100.4.201") == 0)
>    {
>       my_addr.sin_addr.s_addr = inet_addr("10.100.4.200");
>    }

That is not a very generic way to handle IPs.  Since the calling code
already knows which IP it wants to send to, it should pass in another
parameter to the function to specify the local IP to bind to.  Then the
socket code doesn't need these special case operations anymore.

>    if((bind(*sockfd, (struct sockaddr *)&my_addr, sizeof(struct
> sockaddr)))==SOCKET_ERROR)
>    {
>       return error_status = -3;
>    }

You are not closing the socket before exiting when an error occurs.

>       sel_value = select(2, NULL, &writefds, NULL, &tv);

The first parameter is never used and should be set to 0:

    sel_value = select(0, NULL, &writefds, NULL, &tv);


Gambit
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads