connect.cc 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. // $Id: connect.cc,v 1.1 1999/05/29 03:25:03 jgg Exp $
  4. /* ######################################################################
  5. Connect - Replacement connect call
  6. ##################################################################### */
  7. /*}}}*/
  8. // Include Files /*{{{*/
  9. #include "connect.h"
  10. #include <apt-pkg/error.h>
  11. #include <apt-pkg/fileutl.h>
  12. #include <stdio.h>
  13. #include <errno.h>
  14. #include <unistd.h>
  15. // Internet stuff
  16. #include <netinet/in.h>
  17. #include <sys/socket.h>
  18. #include <arpa/inet.h>
  19. #include <netdb.h>
  20. #include "rfc2553emu.h"
  21. /*}}}*/
  22. static string LastHost;
  23. static int LastPort = 0;
  24. static struct addrinfo *LastHostAddr = 0;
  25. static struct addrinfo *LastUsed = 0;
  26. // DoConnect - Attempt a connect operation /*{{{*/
  27. // ---------------------------------------------------------------------
  28. /* This helper function attempts a connection to a single address. */
  29. static bool DoConnect(struct addrinfo *Addr,string Host,
  30. unsigned long TimeOut,int &Fd,pkgAcqMethod *Owner)
  31. {
  32. // Show a status indicator
  33. char Name[NI_MAXHOST];
  34. Name[0] = 0;
  35. getnameinfo(Addr->ai_addr,Addr->ai_addrlen,
  36. Name,sizeof(Name),0,0,NI_NUMERICHOST);
  37. Owner->Status("Connecting to %s (%s)",Host.c_str(),Name);
  38. // Get a socket
  39. if ((Fd = socket(Addr->ai_family,Addr->ai_socktype,
  40. Addr->ai_protocol)) < 0)
  41. return _error->Errno("socket","Could not create a socket");
  42. SetNonBlock(Fd,true);
  43. if (connect(Fd,Addr->ai_addr,Addr->ai_addrlen) < 0 &&
  44. errno != EINPROGRESS)
  45. return _error->Errno("connect","Cannot initiate the connection "
  46. "to %s (%s).",Host.c_str(),Name);
  47. /* This implements a timeout for connect by opening the connection
  48. nonblocking */
  49. if (WaitFd(Fd,true,TimeOut) == false)
  50. return _error->Error("Could not connect to %s (%s), "
  51. "connection timed out",Host.c_str(),Name);
  52. // Check the socket for an error condition
  53. unsigned int Err;
  54. unsigned int Len = sizeof(Err);
  55. if (getsockopt(Fd,SOL_SOCKET,SO_ERROR,&Err,&Len) != 0)
  56. return _error->Errno("getsockopt","Failed");
  57. if (Err != 0)
  58. return _error->Error("Could not connect to %s (%s).",Host.c_str(),Name);
  59. return true;
  60. }
  61. /*}}}*/
  62. // Connect - Connect to a server /*{{{*/
  63. // ---------------------------------------------------------------------
  64. /* Performs a connection to the server */
  65. bool Connect(string Host,int Port,const char *Service,int &Fd,
  66. unsigned long TimeOut,pkgAcqMethod *Owner)
  67. {
  68. if (_error->PendingError() == true)
  69. return false;
  70. /* We used a cached address record.. Yes this is against the spec but
  71. the way we have setup our rotating dns suggests that this is more
  72. sensible */
  73. if (LastHost != Host || LastPort != Port)
  74. {
  75. Owner->Status("Connecting to %s",Host.c_str());
  76. // Lookup the host
  77. char S[300];
  78. if (Port != 0)
  79. snprintf(S,sizeof(S),"%u",Port);
  80. else
  81. snprintf(S,sizeof(S),"%s",Service);
  82. // Free the old address structure
  83. if (LastHostAddr != 0)
  84. {
  85. freeaddrinfo(LastHostAddr);
  86. LastHostAddr = 0;
  87. }
  88. // We only understand SOCK_STREAM sockets.
  89. struct addrinfo Hints;
  90. memset(&Hints,0,sizeof(Hints));
  91. Hints.ai_socktype = SOCK_STREAM;
  92. // Resolve both the host and service simultaneously
  93. if (getaddrinfo(Host.c_str(),S,&Hints,&LastHostAddr) != 0 ||
  94. LastHostAddr == 0)
  95. return _error->Error("Could not resolve '%s'",Host.c_str());
  96. LastHost = Host;
  97. LastPort = Port;
  98. LastUsed = 0;
  99. }
  100. // Get the printable IP address
  101. struct addrinfo *CurHost = LastHostAddr;
  102. if (LastUsed != 0)
  103. CurHost = LastUsed;
  104. while (CurHost != 0)
  105. {
  106. if (DoConnect(CurHost,Host,TimeOut,Fd,Owner) == true)
  107. {
  108. LastUsed = CurHost;
  109. return true;
  110. }
  111. close(Fd);
  112. Fd = -1;
  113. CurHost = CurHost->ai_next;
  114. LastUsed = 0;
  115. if (CurHost != 0)
  116. _error->Discard();
  117. }
  118. return false;
  119. }
  120. /*}}}*/