func newConnection(node, keyspace string, timeout int, authentication map[string]string) (*connection, error) { addr, err := net.ResolveTCPAddr("tcp", node) if err != nil { return nil, err } c := &connection{node: node} c.socket, err = thrift.NewTNonblockingSocketAddr(addr) if err != nil { return nil, err } // socket not open yet, so no error expected. it expects nanos, we have milis, so it's 1e6 c.socket.SetTimeout(int64(timeout) * 1e6) c.transport = thrift.NewTFramedTransport(c.socket) protocolFactory := thrift.NewTBinaryProtocolFactoryDefault() c.client = cassandra.NewCassandraClientFactory(c.transport, protocolFactory) // simulate timeout support for the underlying Dial() in .Open(). needless to say this sucks // restore sanity to this for Go v1 with the new DialTimeout() func ch := make(chan bool, 1) go func() { err = c.transport.Open() ch <- true }() timedOut := false select { case <-time.After(time.Duration(timeout) * time.Millisecond): timedOut = true case <-ch: } if timedOut { return nil, ErrorConnectionTimeout } if err != nil { return nil, err } version, err := c.client.DescribeVersion() if err != nil { c.close() return nil, err } versionComponents := strings.Split(version, ".") if len(versionComponents) < 1 { return nil, ErrorInvalidThriftVersion } majorVersion, err := strconv.Atoi(versionComponents[0]) if err != nil { return nil, ErrorInvalidThriftVersion } if majorVersion < LOWEST_COMPATIBLE_VERSION { return nil, ErrorWrongThriftVersion } if len(authentication) > 0 { ar := cassandra.NewAuthenticationRequest() ar.Credentials = thrift.NewTMap(thrift.STRING, thrift.STRING, 1) for k, v := range authentication { ar.Credentials.Set(k, v) } autE, auzE, err := c.client.Login(ar) if autE != nil { return nil, ErrorAuthenticationFailed } if auzE != nil { return nil, ErrorAuthorizationFailed } if err != nil { return nil, err } } ire, err := c.client.SetKeyspace(keyspace) if err != nil { c.close() return nil, err } if ire != nil { c.close() return nil, ErrorSetKeyspace } c.keyspace = keyspace return c, nil }
func newConnection(n *node, keyspace string, timeout time.Duration, authentication map[string]string, tlsConfig *tls.Config) (*connection, error) { addr, err := net.ResolveTCPAddr("tcp", n.node) if err != nil { return nil, err } c := &connection{node: n} if tlsConfig == nil { socket := thrift.NewTSocketFromAddrTimeout(addr, timeout) c.transport = thrift.NewTFramedTransport(socket) } else { sslSocket := thrift.NewTSSLSocketFromAddrTimeout(addr, tlsConfig, timeout) c.transport = thrift.NewTFramedTransport(sslSocket) } protocol := thrift.NewTBinaryProtocolTransport(c.transport) c.client = cassandra.NewCassandraClientProtocol(c.transport, protocol, protocol) if err = c.transport.Open(); err != nil { return nil, err } version, err := c.client.DescribeVersion() if err != nil { c.close() return nil, err } versionComponents := strings.Split(version, ".") if len(versionComponents) < 1 { return nil, errors.New(fmt.Sprint("Cannot parse the Thrift API version number: ", version)) } majorVersion, err := strconv.Atoi(versionComponents[0]) if err != nil { return nil, errors.New(fmt.Sprint("Cannot parse the Thrift API version number: ", version)) } if majorVersion < LOWEST_COMPATIBLE_VERSION { return nil, errors.New(fmt.Sprint("Unsupported Thrift API version, lowest supported is ", LOWEST_COMPATIBLE_VERSION, ", server reports ", majorVersion)) } if len(authentication) > 0 { ar := cassandra.NewAuthenticationRequest() ar.Credentials = authentication err := c.client.Login(ar) if err != nil { c.close() switch err.(type) { case *cassandra.AuthenticationException: return nil, errors.New("Login error: cannot authenticate with the given credentials") case *cassandra.AuthorizationException: return nil, errors.New("Login error: the given credentials are not authorized to access the server") default: return nil, err } } } err = c.client.SetKeyspace(keyspace) if err != nil { c.close() switch err.(type) { case *cassandra.InvalidRequestException: err = errors.New("Cannot set the keyspace " + keyspace) } return nil, err } return c, nil }