home *** CD-ROM | disk | FTP | other *** search
/ ftp.ncftp.com / ftp.ncftp.com.zip / ftp.ncftp.com / libncftp / older_versions / libncftp-3.1.5-src.tar.gz / libncftp-3.1.5-src.tar / libncftp-3.1.5 / sio / SConnect.c < prev    next >
C/C++ Source or Header  |  2002-07-02  |  6KB  |  270 lines

  1. #include "syshdrs.h"
  2. #ifdef PRAGMA_HDRSTOP
  3. #    pragma hdrstop
  4. #endif
  5.  
  6. #ifndef NO_SIGNALS
  7. extern Sjmp_buf gNetTimeoutJmp;
  8. extern Sjmp_buf gPipeJmp;
  9. #endif
  10.  
  11. int _SConnect(const int sfd, const struct sockaddr_in *const addr, const size_t saddrsiz, const int tlen);
  12.  
  13. int
  14. SConnect(int sfd, const struct sockaddr_in *const addr, int tlen)
  15. {
  16.     int result;
  17.     
  18.     result = _SConnect(sfd, addr, (size_t) sizeof(struct sockaddr_in), tlen);
  19.     return (result);
  20. }    /* SConnect */
  21.  
  22.  
  23.  
  24. #ifdef FIONBIO
  25. /*
  26.  * All this crud just to get various compilers to shut up about non-problems.
  27.  * Just ioctl() already!
  28.  */
  29. static int
  30. SSetFIONBIO(
  31.     int sfd,
  32. #if (defined(WIN32) || defined(_WINDOWS)) && !defined(__CYGWIN__)
  33.     unsigned long onoff
  34. #else
  35.     int onoff
  36. #endif
  37. )
  38. {
  39.     int rc;
  40. #if (defined(HPUX))
  41. #    undef FIONBIO 
  42. #    define FIONBIO 0x8004667e
  43. #endif
  44. #if ((defined(TRU64UNIX)) || (defined(DIGITAL_UNIX)) || (defined(HPUX)))
  45.     unsigned int ui_fionbio = FIONBIO;
  46. #endif
  47.  
  48. #if ((defined(TRU64UNIX)) || (defined(DIGITAL_UNIX)) || (defined(HPUX)))
  49.     rc = ioctlsocket(sfd, ui_fionbio, &onoff);
  50. #else
  51.     rc = ioctlsocket(sfd, FIONBIO, &onoff);
  52. #endif
  53.  
  54.     return (rc);
  55. }    /* SSetFIONBIO */
  56. #endif    /* FIONBIO */
  57.  
  58.  
  59.  
  60.  
  61. int
  62. _SConnect(const int sfd, const struct sockaddr_in *const addr, const size_t saddrsiz, const int tlen)
  63. {
  64. #ifndef NO_SIGNALS
  65.     int result;
  66.     vsio_sigproc_t sigalrm;
  67.  
  68.     if (SSetjmp(gNetTimeoutJmp) != 0) {
  69.         alarm(0);
  70.         (void) SSignal(SIGALRM, (sio_sigproc_t) sigalrm);
  71.         errno = ETIMEDOUT;
  72.         return (kTimeoutErr);
  73.     }
  74.  
  75.     sigalrm = (vsio_sigproc_t) SSignal(SIGALRM, SIOHandler);
  76.     alarm((alarm_time_t) tlen);
  77.  
  78.     errno = 0;
  79.     do {
  80.         result = connect(sfd, (const struct sockaddr *) addr,
  81.             (sockaddr_size_t) saddrsiz);
  82.     } while ((result < 0) && (errno == EINTR));
  83.  
  84.     alarm(0);
  85.     (void) SSignal(SIGALRM, (sio_sigproc_t) sigalrm);
  86.     return (result);
  87. #else    /* NO_SIGNALS */
  88.     fd_set ss, xx;
  89.     struct timeval tv;
  90.     int result;
  91.     int cErrno;
  92. #if (defined(WIN32) || defined(_WINDOWS)) && !defined(__CYGWIN__)
  93.     int wsaErrno;
  94.     int soerr;
  95.     sockopt_size_t soerrsize;
  96. #else
  97. #ifndef FIONBIO
  98.     int fcntl_opt;
  99. #endif
  100.     int optval;
  101.     sockopt_size_t optlen;
  102. #endif
  103.  
  104.     errno = 0;
  105.     if (tlen <= 0) {
  106.         do {
  107.             result = connect(sfd, (const struct sockaddr *) addr,
  108.                 (sockaddr_size_t) saddrsiz);
  109.             SETERRNO
  110.         } while ((result < 0) && (errno == EINTR));
  111.         return (result);
  112.     }
  113.  
  114. #ifdef FIONBIO
  115.     if (SSetFIONBIO(sfd, 1) < 0) {
  116.         SETERRNO
  117.         return (-1);
  118.     }
  119. #else
  120.     if ((fcntl_opt = fcntl(sfd, F_GETFL, 0)) < 0) {
  121.         SETERRNO
  122.         return (-1);
  123.     } else if (fcntl(sfd, F_SETFL, fcntl_opt | O_NONBLOCK) < 0) {
  124.         SETERRNO
  125.         return (-1);
  126.     }
  127. #endif
  128.  
  129.     errno = 0;
  130.     result = connect(sfd, (const struct sockaddr *) addr,
  131.             (sockaddr_size_t) saddrsiz);
  132.     if (result == 0) 
  133.         goto connected;    /* Already?!? */
  134.  
  135.     if ((result < 0) 
  136. #if (defined(WIN32) || defined(_WINDOWS)) && !defined(__CYGWIN__)
  137.         && ((wsaErrno = WSAGetLastError()) != WSAEWOULDBLOCK)
  138.         && (wsaErrno != WSAEINPROGRESS)
  139. #else
  140.         && (errno != EWOULDBLOCK) && (errno != EINPROGRESS)
  141. #endif
  142.         ) {
  143.         cErrno = errno;
  144.         SETERRNO
  145.         shutdown(sfd, 2);
  146.         errno = cErrno;
  147.         return (-1);
  148.     }
  149.     cErrno = errno;
  150.  
  151.     forever {
  152. #if (defined(WIN32) || defined(_WINDOWS)) && !defined(__CYGWIN__)
  153.         WSASetLastError(0);
  154. #endif
  155.         MY_FD_ZERO(&ss);
  156. #if defined(__DECC) || defined(__DECCXX)
  157. #    pragma message save
  158. #    pragma message disable trunclongint
  159. #endif
  160.         MY_FD_SET(sfd, &ss);
  161. #if defined(__DECC) || defined(__DECCXX)
  162. #    pragma message restore
  163. #endif
  164.         xx = ss;
  165.         tv.tv_sec = (tv_sec_t) tlen;
  166.         tv.tv_usec = 0;
  167.         result = select(sfd + 1, NULL, SELECT_TYPE_ARG234 &ss, SELECT_TYPE_ARG234 &xx, SELECT_TYPE_ARG5 &tv);
  168.         if (result == 1) {
  169.             /* ready */
  170.             break;
  171.         } else if (result == 0) {
  172.             /* timeout */        
  173.             errno = ETIMEDOUT;
  174.             SETWSATIMEOUTERR
  175.             /* Don't bother turning off FIONBIO */
  176.             return (kTimeoutErr);
  177.         } else if (errno != EINTR) {
  178.             /* Don't bother turning off FIONBIO */
  179.             SETERRNO
  180.             return (-1);
  181.         }
  182.     }
  183.  
  184.     /* Supposedly once the select() returns with a writable
  185.      * descriptor, it is connected and we don't need to
  186.      * recall connect().  When select() returns an exception,
  187.      * the connection failed -- we can get the connect error
  188.      * doing a write on the socket which will err out.
  189.      */
  190.  
  191. #if defined(__DECC) || defined(__DECCXX)
  192. #    pragma message save
  193. #    pragma message disable trunclongint
  194. #endif
  195.     if (MY_FD_ISSET(sfd, &xx)) {
  196. #if defined(__DECC) || defined(__DECCXX)
  197. #    pragma message restore
  198. #endif
  199. #if (defined(WIN32) || defined(_WINDOWS)) && !defined(__CYGWIN__)
  200.         errno = 0;
  201.         soerr = 0;
  202.         soerrsize = (sockopt_size_t) sizeof(soerr);
  203.         result = getsockopt(sfd, SOL_SOCKET, SO_ERROR, (char *) &soerr, &soerrsize);
  204.         if ((result >= 0) && (soerr != 0)) {
  205.             errno = soerr;
  206.         } else {
  207.             errno = 0;
  208.             (void) send(sfd, "\0", 1, 0);
  209.             SETERRNO
  210.         }
  211. #else
  212.         errno = 0;
  213.         (void) send(sfd, "\0", 1, 0);
  214. #endif
  215.         result = errno;
  216.         shutdown(sfd, 2);
  217.         errno = result;
  218.         return (-1);
  219.     }
  220.  
  221. #if (defined(WIN32) || defined(_WINDOWS)) && !defined(__CYGWIN__)
  222. #else
  223.     if (cErrno == EINPROGRESS) {
  224.         /*
  225.          * [from Linux connect(2) page]
  226.          *
  227.          * EINPROGRESS
  228.          *
  229.          * The socket is non-blocking and the connection can¡
  230.          * not  be  completed immediately.  It is possible to
  231.          * select(2) or poll(2) for completion  by  selecting
  232.          * the  socket  for  writing.  After select indicates
  233.          * writability,  use  getsockopt(2)   to   read   the
  234.          * SO_ERROR  option  at level SOL_SOCKET to determine
  235.          * whether connect completed  successfully  (SO_ERROR
  236.          * is zero) or unsuccessfully (SO_ERROR is one of the
  237.          * usual error codes  listed  above,  explaining  the
  238.          * reason for the failure).
  239.              */
  240.         optval = 0;
  241.         optlen = (sockopt_size_t) sizeof(optval);
  242.         if (getsockopt(sfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == 0) {
  243.             errno = optval;
  244.             if (errno != 0)
  245.                 return (-1);
  246.         }
  247.     }
  248. #endif
  249.  
  250.  
  251. connected:
  252.  
  253. #ifdef FIONBIO
  254.     if (SSetFIONBIO(sfd, 0) < 0) {
  255.         SETERRNO
  256.         shutdown(sfd, 2);
  257.         return (-1);
  258.     }
  259. #else
  260.     if (fcntl(sfd, F_SETFL, fcntl_opt) < 0) {
  261.         SETERRNO
  262.         shutdown(sfd, 2);
  263.         return (-1);
  264.     }
  265. #endif
  266.  
  267.     return (0);
  268. #endif    /* NO_SIGNALS */
  269. }    /* _SConnect */
  270.