SocketClient.cpp 4.92 KB
Newer Older
unknown's avatar
unknown committed
1 2 3 4
/* Copyright (C) 2003 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
unknown's avatar
unknown committed
5
   the Free Software Foundation; version 2 of the License.
unknown's avatar
unknown committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */


#include <ndb_global.h>
#include <NdbOut.hpp>

#include <SocketClient.hpp>
#include <SocketAuthenticator.hpp>

SocketClient::SocketClient(const char *server_name, unsigned short port, SocketAuthenticator *sa)
{
  m_auth= sa;
  m_port= port;
unknown's avatar
unknown committed
27
  m_server_name= server_name ? strdup(server_name) : 0;
unknown's avatar
unknown committed
28
  m_sockfd= NDB_INVALID_SOCKET;
29
  m_connect_timeout_sec= 0;
unknown's avatar
unknown committed
30 31 32 33 34 35
}

SocketClient::~SocketClient()
{
  if (m_server_name)
    free(m_server_name);
unknown's avatar
unknown committed
36
  if (m_sockfd != NDB_INVALID_SOCKET)
unknown's avatar
unknown committed
37 38 39 40 41 42 43 44
    NDB_CLOSE_SOCKET(m_sockfd);
  if (m_auth)
    delete m_auth;
}

bool
SocketClient::init()
{
unknown's avatar
unknown committed
45
  if (m_sockfd != NDB_INVALID_SOCKET)
unknown's avatar
unknown committed
46 47
    NDB_CLOSE_SOCKET(m_sockfd);

unknown's avatar
unknown committed
48 49 50 51 52 53 54 55 56 57
  if (m_server_name)
  {
    memset(&m_servaddr, 0, sizeof(m_servaddr));
    m_servaddr.sin_family = AF_INET;
    m_servaddr.sin_port = htons(m_port);
    // Convert ip address presentation format to numeric format
    if (Ndb_getInAddr(&m_servaddr.sin_addr, m_server_name))
      return false;
  }
  
unknown's avatar
unknown committed
58 59 60 61
  m_sockfd= socket(AF_INET, SOCK_STREAM, 0);
  if (m_sockfd == NDB_INVALID_SOCKET) {
    return false;
  }
62

unknown's avatar
unknown committed
63 64
  DBUG_PRINT("info",("NDB_SOCKET: %d", m_sockfd));

unknown's avatar
unknown committed
65 66 67
  return true;
}

unknown's avatar
unknown committed
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
int
SocketClient::bind(const char* bindaddress, unsigned short localport)
{
  if (m_sockfd == NDB_INVALID_SOCKET)
    return -1;

  struct sockaddr_in local;
  memset(&local, 0, sizeof(local));
  local.sin_family = AF_INET;
  local.sin_port = htons(localport);
  // Convert ip address presentation format to numeric format
  if (Ndb_getInAddr(&local.sin_addr, bindaddress))
  {
    return errno ? errno : EINVAL;
  }
  
  const int on = 1;
  if (setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, 
		 (const char*)&on, sizeof(on)) == -1) {

    int ret = errno;
    NDB_CLOSE_SOCKET(m_sockfd);
    m_sockfd= NDB_INVALID_SOCKET;
    return errno;
  }
  
  if (::bind(m_sockfd, (struct sockaddr*)&local, sizeof(local)) == -1) 
  {
    int ret = errno;
    NDB_CLOSE_SOCKET(m_sockfd);
    m_sockfd= NDB_INVALID_SOCKET;
    return ret;
  }
  
  return 0;
}

unknown's avatar
unknown committed
105
NDB_SOCKET_TYPE
unknown's avatar
unknown committed
106
SocketClient::connect(const char *toaddress, unsigned short toport)
unknown's avatar
unknown committed
107
{
108 109 110 111
  fd_set rset, wset;
  struct timeval tval;
  int r;
  bool use_timeout;
112
  SOCKOPT_OPTLEN_TYPE len;
113 114
  int flags;

unknown's avatar
unknown committed
115
  if (m_sockfd == NDB_INVALID_SOCKET)
unknown's avatar
unknown committed
116 117
  {
    if (!init()) {
118
#ifdef VM_TRACE
unknown's avatar
unknown committed
119
      ndbout << "SocketClient::connect() failed " << m_server_name << " " << m_port << endl;
120
#endif
unknown's avatar
unknown committed
121
      return NDB_INVALID_SOCKET;
unknown's avatar
unknown committed
122 123
    }
  }
unknown's avatar
unknown committed
124 125 126 127 128 129 130 131 132 133 134 135 136 137

  if (toaddress)
  {
    if (m_server_name)
      free(m_server_name);
    m_server_name = strdup(toaddress);
    m_port = toport;
    memset(&m_servaddr, 0, sizeof(m_servaddr));
    m_servaddr.sin_family = AF_INET;
    m_servaddr.sin_port = htons(toport);
    // Convert ip address presentation format to numeric format
    if (Ndb_getInAddr(&m_servaddr.sin_addr, m_server_name))
      return NDB_INVALID_SOCKET;
  }
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162

  flags= fcntl(m_sockfd, F_GETFL, 0);
  fcntl(m_sockfd, F_SETFL, flags | O_NONBLOCK);

  r= ::connect(m_sockfd, (struct sockaddr*) &m_servaddr, sizeof(m_servaddr));

  if (r == 0)
    goto done; // connected immediately.

  if (r < 0 && (errno != EINPROGRESS)) {
    NDB_CLOSE_SOCKET(m_sockfd);
    m_sockfd= NDB_INVALID_SOCKET;
    return NDB_INVALID_SOCKET;
  }

  FD_ZERO(&rset);
  FD_SET(m_sockfd, &rset);
  wset= rset;
  tval.tv_sec= m_connect_timeout_sec;
  tval.tv_usec= 0;
  use_timeout= m_connect_timeout_sec;

  if ((r= select(m_sockfd+1, &rset, &wset, NULL,
                 use_timeout? &tval : NULL)) == 0)
  {
unknown's avatar
unknown committed
163
    NDB_CLOSE_SOCKET(m_sockfd);
unknown's avatar
unknown committed
164 165
    m_sockfd= NDB_INVALID_SOCKET;
    return NDB_INVALID_SOCKET;
unknown's avatar
unknown committed
166
  }
unknown's avatar
unknown committed
167

168 169 170
  if (FD_ISSET(m_sockfd, &rset) || FD_ISSET(m_sockfd, &wset))
  {
    len= sizeof(r);
171
    if (getsockopt(m_sockfd, SOL_SOCKET, SO_ERROR, &r, &len) < 0 || r)
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
    {
      // Solaris got an error... different than others
      NDB_CLOSE_SOCKET(m_sockfd);
      m_sockfd= NDB_INVALID_SOCKET;
      return NDB_INVALID_SOCKET;
    }
  }
  else
  {
    // select error, probably m_sockfd not set.
    NDB_CLOSE_SOCKET(m_sockfd);
    m_sockfd= NDB_INVALID_SOCKET;
    return NDB_INVALID_SOCKET;
  }

done:
  fcntl(m_sockfd, F_SETFL, flags);

unknown's avatar
unknown committed
190
  if (m_auth) {
unknown's avatar
unknown committed
191 192 193
    if (!m_auth->client_authenticate(m_sockfd))
    {
      NDB_CLOSE_SOCKET(m_sockfd);
unknown's avatar
unknown committed
194 195
      m_sockfd= NDB_INVALID_SOCKET;
      return NDB_INVALID_SOCKET;
unknown's avatar
unknown committed
196
    }
unknown's avatar
unknown committed
197
  }
unknown's avatar
unknown committed
198
  NDB_SOCKET_TYPE sockfd= m_sockfd;
unknown's avatar
unknown committed
199
  m_sockfd= NDB_INVALID_SOCKET;
unknown's avatar
unknown committed
200 201 202

  return sockfd;
}