home *** CD-ROM | disk | FTP | other *** search
/ ftp.ncftp.com / ftp.ncftp.com.zip / ftp.ncftp.com / libncftp / libncftp-3.2.5-src.zip / libncftp-3.2.5 / sio / SConnect.c < prev    next >
C/C++ Source or Header  |  2009-12-17  |  6KB  |  258 lines

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