× The internal search function is temporarily non-functional. The current search engine is no longer viable and we are researching alternatives.
As a stop gap measure, we are using Google's custom search engine service.
If you know of an easy to use, open source, search engine ... please contact support@midrange.com.



Scott,

Thanks for the info.  This should give me what I need.  I'm looking forward
to getting past CLIENTEX1 and through the rest of your tutorial.  And I'm
planning on using hostnames instead of IP addresses, but the Redbook
examples don't so I wasn't either at that point.

Mike E.





                    Scott Klement
                    <klemscot@klement       To:     rpg400-l@midrange.com
                    s.com>                  cc:
                    Sent by:                Subject:     Re: sockets connect() 
behaving strangely on local network
                    rpg400-l-admin@mi
                    drange.com


                    08/26/2002 04:12
                    AM
                    Please respond to
                    rpg400-l








On Sun, 25 Aug 2002 meovino@estes-express.com wrote:
>
> This sounds logical as well, but I'm really doing most of my testing with
> the SCLIENT4 and SSERVER4 programs in the redbook, and they take dotted
> IP addresses, not hostnames.
>

So it's not DNS that's causing the delays (I thought that was unlikely
anyway).   Tho, you really should have your clients use hostnames instead
of addresses.  The idea behind that is that when the hosts get moved to a
different area of the network or internet, and their IP addresses are
forced to change, you should only have to change the address in one
place... the DNS server.

> I used CLIENTEX1 to see if I got the same results, and I did.
>

No big surprise there.  They're both running the same connect() API on
the same network interfaces connected to the same networks.  They should
behave the same.

>
> > My question to you is:  Why does it matter?  What are you trying to
> > accomplish?
>
> We are attempting to write a sockets client and server to allow us to
> communicate with our sister companies that are all on a VPN into our
> LAN.  We're the most IT savvy of the group, so we're writing all of
> this.  This is going to be used  on the fly to get data to use in CGI
> programs, so two minutes is too long for a timeout.  I'd like to know
> that the connection has failed immediately.

As I said before...  you can't know "immediately".  Either something has
to send back an ICMP indicating failure (which could be very quick, or
could take a few seconds to send back) or you have to wait for a
timeout...    That's the nature of network programming.

What you CAN do is use a smaller timeout value if 2 minutes is too
extreme.  You do this by using non-blocking sockets and the select() API.

>
> > Maybe I've got a solution for you...
>
> I have a feeling you do.  I've seen you write about non-blocking sockets
> elsewhere on this lilst.  SCLIENT4 uses them, but it does not set the
> socket to non-blocking until *after* the connect.  I copied the code
> that sets the socket to non-blocking before the connect, and the
> connect() gives me the return code of -1 immediately when I have
> disabled the interface.  Unfortunately, it also gives me a return code
> of -1 when the interface is up.
>

Correct.  That's exactly what it SHOULD do.  Did you even bother to read
about non-blocking and understand what it does?

Here's a quick explanation:   Non-blocking tells the API that you never
want to wait for a socket operation.   In other words, when you call
connect(), accept(), recv(), send() APIs they always return immediately.

The connect() API can only return two possible results.   A 0 which means
the connection has been established, or a -1 which means that it hasn't.

Making a connection takes time.  It has to send setup datagrams to the
remote host, and the remote host has to send back datagrams.  They have to
negotiate some parameters, and then the connection can be started.

So, on a non-blocking socket, when you call connect() it nearly always
returns a -1 indicating that the connection has not been made... it's
theoretically possible that the connection could be established so fast
that it succeeds without blocking, but I've never seen it happen.

So, what you need to do in non-blocking mode is:   Check errno to see
why the socket failed.   Chapter 4 of my socket tutorial will explain
how to use errno to get the error message.

If the connect() API gives you an error message of EINPROGESS it means
that the socket is in non-blocking mode, and the connect() is happening
asynchronusly.   When that happens, you can call the select() API and
wait for your socket to become writable.    You can give select() any
time-out value that you like.

So, if you wanted your timeout to be 30 seconds instead of 2 mins, you'd
tell select() to wait until either the socket is writable, or until 30
seconds has gone by.   When select finishes, you could check to see if
the socket ended up writable...  if so, you know the connection was made.
If not, a timeout occurred, and you should call close() for that socket
to cancel the connect() operation.

>
> Does your tutorial have an example of a non-blocking connect() that will
> handle this situation.  I've only gotten to CLIENTEX1 so far.  But I
> didn't want to go too much farther without finding out if what's
> happening with the two different timeouts was a symptom of a problem
> with our network that would keep *anything* from working properly.
> Sounds like that's not the case.
>

Not in so many words.   But it does explain what non-blocking means.  And
it does show you how to retrieve error numbers in chapter 4.  And it does
explain how to call select() in chapter 6.

It doesn't put them together to specifically show you how to do a time-out
on a connect(), however.   I am currently writing a training manual that
WILL explain this (as well as other places you might want to do timeouts)
but that's not finished yet.

For the time being, I can give you a code sample.   This code uses the
/copy members from my sockets tutorial, as well as the sockutilr4 service
program which is also in my tutorial.   You'll want to get those from my
web site to use this code:

      *
      * Example of calling the connect() API with a timeout
      *
     H DFTACTGRP(*NO) ACTGRP(*NEW)
     H BNDDIR('QC2LE') BNDDIR('SOCKTUT/SOCKUTIL')

     D/copy socktut/qrpglesrc,socket_h
     D/copy socktut/qrpglesrc,errno_h
     D/copy socktut/qrpglesrc,sockutil_h

      *********************************************************
      * end of IFS API call definitions
      *********************************************************

     D die             PR
     D   peMsg                      256A   const

     D cmd             PR                  ExtPgm('QCMDEXC')
     D   command                    200A   const
     D   length                      15P 5 const

     D sock            S             10I 0
     D port            S              5U 0
     D flags           S             10I 0
     D host            s             32A
     D addr            s             10U 0
     D connto          S                   like(sockaddr_in)
     D err             S             10I 0
     D connfds         S                   like(fdset)
     D timeout         S                   like(timeval)

     C*************************************************
     C* The user will supply a hostname and file
     C*  name as parameters to our program...
     C*************************************************
     c     *entry        plist
     c                   parm                    host

     c                   eval      *inlr = *on

     C*************************************************
     C* For this example, we'll look up the port
     C* number of the HTTP service:
     C*************************************************
     c                   eval      p_servent = getservbyname('http':'tcp')
     c                   if        p_servent = *NULL
     c                   callp     die('Can''t find the HTTP service!')
     c                   return
     c                   endif

     c                   eval      port = s_port

     C*************************************************
     C* Get the 32-bit network IP address for the host
     C*  that was supplied by the user:
     C*************************************************
     c                   eval      addr = inet_addr(%trim(host))
     c                   if        addr = INADDR_NONE
     c                   eval      p_hostent = gethostbyname(%trim(host))
     c                   if        p_hostent = *NULL
     c                   callp     die('Unable to find that host!')
     c                   return
     c                   endif
     c                   eval      addr = h_addr
     c                   endif

     C*************************************************
     C* Create a socket
     C*************************************************
     c                   eval      sock = socket(AF_INET: SOCK_STREAM:
     c                                           IPPROTO_IP)
     c                   if        sock < 0
     c                   callp     die('socket(): ' +
%str(strerror(errno)))
     c                   return
     c                   endif

     c*************************************************
     C* Put the socket in non-blocking mode:
     c*************************************************
     c                   eval      flags = fcntl(sock: F_GETFL)
     c                   eval      flags = flags + O_NONBLOCK
     c                   if        fcntl(sock: F_SETFL: flags) < 0
     c                   callp     die('fcntl(): ' + %str(strerror(errno)))
     c                   return
     c                   endif

     c*************************************************
     C* Create a socket address structure that
     C*   describes the host & port we wanted to
     C*   connect to
     C*************************************************
     c                   eval      p_sockaddr = %addr(connto)

     c                   eval      sin_family = AF_INET
     c                   eval      sin_addr = addr
     c                   eval      sin_port = port
     c                   eval      sin_zero = *ALLx'00'

     C*************************************************
     C* Start the connection process.
     C*************************************************
     c                   if        connect(sock: %addr(connto):
     c                                           %size(connto) ) < 0
     c                   eval      err = errno
     c                   if        err <> EINPROGRESS
     c                   callp     close(sock)
     c                   callp     die('connect(): '+%str(strerror(err)))
     c                   return
     c                   endif
     c                   endif

     C*************************************************
     C* wait up to 30 sec for connection to be made
     C*************************************************
     c                   callp     FD_ZERO(connfds)
     c                   callp     FD_SET(sock: connfds)

     c                   eval      p_timeval = %addr(timeout)
     c                   eval      tv_sec = 30
     c                   eval      tv_usec = 0

     c                   if        select(sock+1: *NULL:
     c                                            %addr(connfds):
     c                                            *NULL:
     c                                            %addr(timeout)) < 0
     c                   eval      err = errno
     c                   callp     close(sock)
     c                   callp     die('select(): '+%str(strerror(err)))
     c                   return
     c                   endif

     c                   if        FD_ISSET(sock: connfds) = *OFF
     c                   callp     close(sock)
     c                   callp     die('connect(): time out value reached')
     c                   return
     c                   endif

     C* Here we are connected.   We can use send() & recv() to
     C* send data here...

     c                   callp     close(sock)
     c                   return


      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      *  This ends this program abnormally, and sends back an escape.
      *   message explaining the failure.
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     P die             B
     D die             PI
     D   peMsg                      256A   const

     D SndPgmMsg       PR                  ExtPgm('QMHSNDPM')
     D   MessageID                    7A   Const
     D   QualMsgF                    20A   Const
     D   MsgData                    256A   Const
     D   MsgDtaLen                   10I 0 Const
     D   MsgType                     10A   Const
     D   CallStkEnt                  10A   Const
     D   CallStkCnt                  10I 0 Const
     D   MessageKey                   4A
     D   ErrorCode                32766A   options(*varsize)

     D dsEC            DS
     D  dsECBytesP             1      4I 0 INZ(256)
     D  dsECBytesA             5      8I 0 INZ(0)
     D  dsECMsgID              9     15
     D  dsECReserv            16     16
     D  dsECMsgDta            17    256

     D wwMsgLen        S             10I 0
     D wwTheKey        S              4A

     c                   eval      wwMsgLen = %len(%trimr(peMsg))
     c                   if        wwMsgLen<1
     c                   return
     c                   endif

     c                   callp     SndPgmMsg('CPF9897': 'QCPFMSG   *LIBL':
     c                               peMsg: wwMsgLen: '*ESCAPE':
     c                               '*PGMBDY': 1: wwTheKey: dsEC)

     c                   return
     P                 E

      /define ERRNO_LOAD_PROCEDURE
      /copy socktut/qrpglesrc,errno_h

_______________________________________________
This is the RPG programming on the AS400 / iSeries (RPG400-L) mailing list
To post a message email: RPG400-L@midrange.com
To subscribe, unsubscribe, or change list options,
visit: http://lists.midrange.com/cgi-bin/listinfo/rpg400-l
or email: RPG400-L-request@midrange.com
Before posting, please take a moment to review the archives
at http://archive.midrange.com/rpg400-l.







As an Amazon Associate we earn from qualifying purchases.

This thread ...


Follow On AppleNews
Return to Archive home page | Return to MIDRANGE.COM home page

This mailing list archive is Copyright 1997-2024 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact [javascript protected email address].

Operating expenses for this site are earned using the Amazon Associate program and Google Adsense.