Exemple #1
0
void HTTPSession::PrintPair(const ReadBuffer& key, const ReadBuffer& value)
{
    if (!conn)
        return;

    if (!headerSent)
    {
        if (type == JSON)
            json.Start();
        else
            conn->WriteHeader(HTTP_STATUS_CODE_OK);

        headerSent = true;
    }

    if (type == JSON)
        json.PrintPair(key.GetBuffer(), key.GetLength(), value.GetBuffer(), value.GetLength());
    else
    {
        conn->Write(key.GetBuffer(), key.GetLength());
        conn->Print(": ");
        conn->Write(value.GetBuffer(), value.GetLength());
        conn->Print("\n");
    }
}
void StorageMemoKeyValue::Set(ReadBuffer key_, ReadBuffer value_)
{
    if (buffer != NULL)
        free(buffer);
    
    keyLength = key_.GetLength();
    valueLength = value_.GetLength();

    buffer = (char*) malloc(GetLength());
    
    memcpy(buffer, key_.GetBuffer(), keyLength);
    memcpy(buffer + keyLength, value_.GetBuffer(), valueLength);
}
Exemple #3
0
bool HTTPSession::ParseRequest(HTTPRequest& request, ReadBuffer& cmd, UrlParam& params)
{
    char*       qmark;
    ReadBuffer  rb;
    ReadBuffer  jsonCallback;
    ReadBuffer  mimeType;
    ReadBuffer  origin;
    
    // TODO: when adding keep-alive HTTP sessions, move this to an Init() function
    isFlushed = false;
    
    uri = request.line.uri;
    rb = request.line.uri;
    if (rb.GetCharAt(0) == '/')
        rb.Advance(1);
    
    mimeType.Reset();
    ParseType(rb);
    cmd = rb;

    qmark = NULL;
    if (rb.GetLength() > 0)
        qmark = FindInBuffer(rb.GetBuffer(), rb.GetLength() - 1, '?');

    if (qmark)
    {
        rb.Advance((unsigned) (qmark - rb.GetBuffer() + 1));
        params.Init(rb.GetBuffer(), rb.GetLength(), '&');
        cmd.SetLength((unsigned) (qmark - cmd.GetBuffer()));
        
        if (type == JSON)
        {
            HTTP_GET_OPT_PARAM(params, "callback", jsonCallback);
            json.SetCallbackPrefix(jsonCallback);
        }
        
        // mime type is overridable
        HTTP_GET_OPT_PARAM(params, "mimetype", mimeType);
        if (mimeType.GetLength() != 0)
            conn->SetContentType(mimeType);
            
        // CORS support
        // http://www.w3.org/TR/cors/
        HTTP_GET_OPT_PARAM(params, "origin", origin);
    }
    
    return true;
}
Exemple #4
0
void HTTPSession::Print(const ReadBuffer& line)
{
    Buffer      header;
    ReadBuffer  tmp;
    
    if (!conn)
        return;

    if (!headerSent)
    {
        if (type == JSON)
            json.Start();
        else
            conn->WriteHeader(HTTP_STATUS_CODE_OK);

        headerSent = true;
    }
    
    if (type == JSON)
    {
        tmp = "response";
        json.PrintString(tmp);
        json.PrintColon();
        json.PrintString(line);
    }
    else
    {
        conn->Write(line.GetBuffer(), line.GetLength());
        conn->Print("\n");
    }
}
void ConfigQuorumContext::OnMessage(ReadBuffer buffer)
{
    char proto;
    
    Log_Trace("%R", &buffer);

    if (buffer.GetLength() < 2)
        ASSERT_FAIL();

    proto = buffer.GetCharAt(0);
    ASSERT(buffer.GetCharAt(1) == ':');
    
    switch(proto)
    {
        case PAXOSLEASE_PROTOCOL_ID:        // 'L':
            OnPaxosLeaseMessage(buffer);
            break;
        case PAXOS_PROTOCOL_ID:             // 'P':
            OnPaxosMessage(buffer);
            break;
        case CATCHUP_PROTOCOL_ID:           // 'C'
            OnCatchupMessage(buffer);
            break;
        default:
            ASSERT_FAIL();
            break;
    }
}
void ContextTransport::OnMessage(uint64_t nodeID, ReadBuffer msg)
{
    int         nread;
    char        proto;
    
    Log_Trace("%R", &msg);
    
    if (msg.GetLength() < 2)
        ASSERT_FAIL();

    nread = msg.Readf("%c:", &proto);
    if (nread < 2)
        ASSERT_FAIL();

    msg.Advance(2);
    
    switch (proto)
    {
        case PROTOCOL_CLUSTER:
            OnClusterMessage(nodeID, msg);
            break;
        case PROTOCOL_QUORUM:
            OnQuorumMessage(nodeID, msg);
            break;
        default:
            ASSERT_FAIL();
            break;
    }
}
Exemple #7
0
void HTTPSession::SetType(Type type_)
{
    const char* mime;
    ReadBuffer  mimeType;
    
    type = type_;

    switch (type)
    {
    case PLAIN:
        mime = MIME_TYPE_TEXT_PLAIN;
        break;
    case HTML:
        mime = MIME_TYPE_TEXT_HTML;
        break;
    case JSON:
        mime = MIME_TYPE_APPLICATION_JSON;
        break;
    default:
        mime = MIME_TYPE_TEXT_PLAIN;
        break;
    }

    if (mimeType.GetLength() == 0)
        mimeType.Wrap(mime);
    
    conn->SetContentType(mimeType);
}
Exemple #8
0
bool StorageShard::IsSplitable()
{
    StorageChunk**  itChunk;
    ReadBuffer      firstKey;
    ReadBuffer      lastKey;

    FOREACH (itChunk, GetChunks())
    {
        firstKey = (*itChunk)->GetFirstKey();
        lastKey = (*itChunk)->GetLastKey();
        
        if (firstKey.GetLength() > 0 && !RangeContains(firstKey))
            return false;

        if (lastKey.GetLength() > 0 && !RangeContains(lastKey))
            return false;
    }
void StorageMemoKeyValue::Delete(ReadBuffer key_)
{
    if (buffer != NULL)
        free(buffer);
    
    keyLength = key_.GetLength();
    valueLength = DELETE_LENGTH_VALUE;

    buffer = (char*) malloc(GetLength());
    
    memcpy(buffer, key_.GetBuffer(), keyLength);
}
Exemple #10
0
void QuorumDatabase::SetAcceptedValue(uint64_t paxosID, ReadBuffer value)
{
    Buffer      key;
    ReadBuffer  rbKey;

    ASSERT(value.GetLength() > 0);

    key.Writef("accepted:%021U", paxosID);
    rbKey.Wrap(key);

    logShard->Set(rbKey, value);
}
Exemple #11
0
bool Endpoint::Set(ReadBuffer ip_port, bool resolv)
{
    const char*     p;
    const char*     start;
    int             port;
    bool            ret;
    Buffer          ipbuf;
    Buffer          portbuf;

    if (!IsValidEndpoint(ReadBuffer(ip_port)))
        return false;
    
    start = p = ip_port.GetBuffer();
    
    p = RevFindInBuffer(ip_port.GetBuffer(), ip_port.GetLength(), ':');
    if (p == NULL)
    {
        Log_Trace("No ':' in host specification");
        return false;
    }

    ipbuf.Append(start, p - start);
    ipbuf.NullTerminate();
    
    p++;
    portbuf.Append(p, ip_port.GetLength() - (p - start));
    portbuf.NullTerminate();
    
    port = -1;
    port = atoi(portbuf.GetBuffer());
    if (port < 1 || port > 65535)
    {
        Log_Trace("atoi() failed to produce a sensible value");
        return false;
    }

    ret = Set(ipbuf.GetBuffer(), port, resolv);
    
    return ret;
}
Exemple #12
0
uint64_t QuorumDatabase::GetUint64(const char* name)
{
    ReadBuffer  key(name);
    ReadBuffer  value;
    uint64_t    u64;
    unsigned    nread;
    int         ret;

    ret = paxosShard->Get(key, value);
    if (!ret)
        return false;

    nread = 0;
    u64 = BufferToUInt64(value.GetBuffer(), value.GetLength(), &nread);
    if (nread != value.GetLength())
    {
        Log_Trace();
        u64 = 0;
    }

    return u64;
}
Exemple #13
0
void QuorumDatabase::GetAcceptedValue(uint64_t paxosID, Buffer& value)
{
    Buffer      key;
    ReadBuffer  rbKey;
    ReadBuffer  rbValue;
    bool        ret;

    key.Writef("accepted:%021U", paxosID);
    rbKey.Wrap(key);
    
    ret = logShard->Get(rbKey, rbValue);
    if (!ret)
        return;

    ASSERT(rbValue.GetLength() > 0);
    
    value.Write(rbValue);
}
Exemple #14
0
bool QuorumDatabase::GetAccepted()
{
    Buffer      key;
    ReadBuffer  rbKey;
    ReadBuffer  rbValue;
    bool        ret;

    key.Write("accepted");
    rbKey.Wrap(key);

    ret = paxosShard->Get(rbKey, rbValue);
    if (!ret)
      return false;   // not found, return default

    if (rbValue.GetLength() != 1)
      return false;   // incorrect value, return default
      
    if (rbValue.GetCharAt(0) == '1')
      return true;

    return false;
}
Exemple #15
0
bool HTTPSession::RedirectLocalhost(HTTPConnection *conn, HTTPRequest &request)
{
    ReadBuffer  host;

    // fix Windows 7 IPv6 localhost name resolution issue
    host = request.header.GetField(HTTP_HEADER_HOST);
    if (host.BeginsWith("localhost"))
    {
        ReadBuffer  userAgent;
        Buffer      newHost;
        Buffer      ha;
        unsigned    i;
        int         pos;
        
        userAgent = request.header.GetField(HTTP_HEADER_USER_AGENT);
        pos = userAgent.Find(WINDOWS_NT_USER_AGENT);
        if (pos < 0)
            return false;

        newHost.Write("127.0.0.1");
        for (i = 0; i < host.GetLength(); i++)
        {
            if (host.GetCharAt(i) == ':')
            {
                host.Advance(i);
                newHost.Append(host);
                break;
            }
        }
        ha.Writef(HTTP_HEADER_LOCATION ": http://%B%R" HTTP_CS_CRLF, &newHost, &request.line.uri);
	    ha.NullTerminate();
		conn->ResponseHeader(HTTP_STATUS_CODE_TEMPORARY_REDIRECT, true, ha.GetBuffer());
        conn->Flush(true);
		return true;
    }

    return false;
}
Exemple #16
0
bool PaxosMessage::Read(ReadBuffer& buffer)
{
    int     read;
    char    proto;
    
    if (buffer.GetLength() < 3)
        return false;

    switch (buffer.GetCharAt(2))
    {
        case PAXOS_PREPARE_REQUEST:
            read = buffer.Readf("%c:%c:%U:%U:%U", 
             &proto, &type, &paxosID, &nodeID, &proposalID);
            break;
        case PAXOS_PREPARE_REJECTED:
            read = buffer.Readf("%c:%c:%U:%U:%U:%U",
             &proto, &type, &paxosID, &nodeID, &proposalID, &promisedProposalID);
            break;
        case PAXOS_PREPARE_PREVIOUSLY_ACCEPTED:
            read = buffer.Readf("%c:%c:%U:%U:%U:%U:%U:%#R",
             &proto, &type, &paxosID, &nodeID, &proposalID, &acceptedProposalID, &runID, &value);
            break;
        case PAXOS_PREPARE_CURRENTLY_OPEN:
            read = buffer.Readf("%c:%c:%U:%U:%U",
             &proto, &type, &paxosID, &nodeID, &proposalID);
            break;
        case PAXOS_PROPOSE_REQUEST:
            read = buffer.Readf("%c:%c:%U:%U:%U:%U:%#R",
             &proto, &type, &paxosID, &nodeID, &proposalID, &runID, &value);
            break;
        case PAXOS_PROPOSE_REJECTED:
            read = buffer.Readf("%c:%c:%U:%U:%U",
             &proto, &type, &paxosID, &nodeID, &proposalID);
            break;
        case PAXOS_PROPOSE_ACCEPTED:
            read = buffer.Readf("%c:%c:%U:%U:%U",
             &proto, &type, &paxosID, &nodeID, &proposalID);
            break;
        case PAXOS_LEARN_PROPOSAL:
            read = buffer.Readf("%c:%c:%U:%U:%U",
             &proto, &type, &paxosID, &nodeID, &proposalID);
            break;
        case PAXOS_LEARN_VALUE:
            read = buffer.Readf("%c:%c:%U:%U:%U:%#R",
             &proto, &type, &paxosID, &nodeID, &runID, &value);
            break;
        case PAXOS_REQUEST_CHOSEN:
            read = buffer.Readf("%c:%c:%U:%U",
             &proto, &type, &paxosID, &nodeID);
            break;
        case PAXOS_START_CATCHUP:
            read = buffer.Readf("%c:%c:%U:%U",
             &proto, &type, &paxosID, &nodeID);
            break;
        default:
            return false;
    }
    
    ASSERT(proto == PAXOS_PROTOCOL_ID);
    
    return (read == (signed)buffer.GetLength());

}
Exemple #17
0
void Buffer::Append(ReadBuffer other)
{
    Append(other.GetBuffer(), other.GetLength());
}
Exemple #18
0
void Buffer::Write(const ReadBuffer other)
{
    Write(other.GetBuffer(), other.GetLength());
}
// copy key-values from file chunk to a temporary data page, that will be used for listing
void StorageUnwrittenChunkLister::Init(StorageFileChunk& fileChunk, ReadBuffer& firstKey, 
 ReadBuffer& prefix, unsigned count, bool forwardDirection_)
{
    StorageFileKeyValue*    kv;
    int                     cmpres;
    unsigned                num;
    uint32_t                index;
    uint64_t                offset;
    int                     ret;

    Log_Debug("Listing unwritten chunk");

    num = 0;
    index = 0;
    forwardDirection = forwardDirection_;
    
    if (forwardDirection && ReadBuffer::Cmp(firstKey, fileChunk.indexPage->GetFirstKey()) < 0)
    {
        index = 0;
        offset = fileChunk.indexPage->GetFirstDatapageOffset();
    }
    else if (!forwardDirection && firstKey.GetLength() > 0 && ReadBuffer::Cmp(firstKey, fileChunk.indexPage->GetFirstKey()) < 0)
    {
        // firstKey is set and smaller that the first key in this chunk
        dataPage.Finalize();
        return;
    }
    else if (!forwardDirection && firstKey.GetLength() > 0 && ReadBuffer::Cmp(firstKey, fileChunk.indexPage->GetLastKey()) > 0)
    {
        index = fileChunk.numDataPages - 1;
        offset = fileChunk.indexPage->GetLastDatapageOffset();
    }
    else if (!forwardDirection && firstKey.GetLength() == 0)
    {
        index = fileChunk.numDataPages - 1;
        offset = fileChunk.indexPage->GetLastDatapageOffset();
    }
    else
    {
        ret = fileChunk.indexPage->Locate(firstKey, index, offset);
        ASSERT(ret);
    }

    kv = fileChunk.dataPages[index]->LocateKeyValue(firstKey, cmpres);
    if (kv != NULL)
    {
        if (forwardDirection && cmpres > 0)
            kv = NextChunkKeyValue(fileChunk, index, kv);
        else if (!forwardDirection && cmpres < 0)
            kv = PrevChunkKeyValue(fileChunk, index, kv);
    }

    while (kv != NULL)
    {
        if (prefix.GetLength() > 0 && !kv->GetKey().BeginsWith(prefix))
            break;

        dataPage.Append(kv);
        if (kv->GetType() == STORAGE_KEYVALUE_TYPE_SET)
        {
            num++;
            if (count != 0 && num == count)
                break;
        }
        if (forwardDirection)
            kv = NextChunkKeyValue(fileChunk, index, kv);
        else
            kv = PrevChunkKeyValue(fileChunk, index, kv);
    }
    
    dataPage.Finalize();
}
Exemple #20
0
bool ConfigMessage::Read(ReadBuffer& buffer)
{
    int         read;
    unsigned    numNodes, i;
    uint64_t    nodeID_;
    ReadBuffer  rb;
        
    if (buffer.GetLength() < 1)
        return false;
    
    switch (buffer.GetCharAt(0))
    {
        // Cluster management
        case CONFIGMESSAGE_SET_CLUSTER_ID:
            read = buffer.Readf("%c:%U",
             &type, &clusterID);
             break;
        case CONFIGMESSAGE_REGISTER_SHARDSERVER:
            read = buffer.Readf("%c:%U:%#R",
             &type, &nodeID, &rb);
            endpoint.Set(rb);
            break;
        case CONFIGMESSAGE_UNREGISTER_SHARDSERVER:
            read = buffer.Readf("%c:%U",
             &type, &nodeID);
            break;
        case CONFIGMESSAGE_CREATE_QUORUM:
            read = buffer.Readf("%c:%#R:%u",
             &type, &name, &numNodes);
             if (read < 0 || read == (signed)buffer.GetLength())
                return false;
            buffer.Advance(read);
            for (i = 0; i < numNodes; i++)
            {
                read = buffer.Readf(":%U", &nodeID_);
                if (read < 0)
                    return false;
                buffer.Advance(read);
                nodes.Append(nodeID_);
            }
            if (buffer.GetLength() == 0)
                return true;
            else
                return false;
            break;
        case CONFIGMESSAGE_RENAME_QUORUM:
            read = buffer.Readf("%c:%U:%#R",
             &type, &quorumID, &name);
            break;
        case CONFIGMESSAGE_DELETE_QUORUM:
            read = buffer.Readf("%c:%U",
             &type, &quorumID);
            break;
        case CONFIGMESSAGE_ADD_SHARDSERVER_TO_QUORUM:
            read = buffer.Readf("%c:%U:%U",
             &type, &quorumID, &nodeID);
            break;
        case CONFIGMESSAGE_REMOVE_SHARDSERVER_FROM_QUORUM:
            read = buffer.Readf("%c:%U:%U",
             &type, &quorumID, &nodeID);
            break;
        case CONFIGMESSAGE_ACTIVATE_SHARDSERVER:
            read = buffer.Readf("%c:%U:%U",
             &type, &quorumID, &nodeID);
            break;
        case CONFIGMESSAGE_DEACTIVATE_SHARDSERVER:
            read = buffer.Readf("%c:%U:%U",
             &type, &quorumID, &nodeID);
            break;

        // Database management
        case CONFIGMESSAGE_CREATE_DATABASE:
            read = buffer.Readf("%c:%#R",
             &type, &name);
            break;
        case CONFIGMESSAGE_RENAME_DATABASE:
            read = buffer.Readf("%c:%U:%#R",
             &type, &databaseID, &name);
            break;
        case CONFIGMESSAGE_DELETE_DATABASE:
            read = buffer.Readf("%c:%U", 
            &type, &databaseID);
            break;

        // Table management
        case CONFIGMESSAGE_CREATE_TABLE:
            read = buffer.Readf("%c:%U:%U:%#R",
             &type, &databaseID, &quorumID, &name);
            break;
        case CONFIGMESSAGE_RENAME_TABLE:
            read = buffer.Readf("%c:%U:%#R",
             &type, &tableID, &name);
            break;
        case CONFIGMESSAGE_DELETE_TABLE:
            read = buffer.Readf("%c:%U",
             &type, &tableID);
            break;
        case CONFIGMESSAGE_TRUNCATE_TABLE_BEGIN:
            read = buffer.Readf("%c:%U",
             &type, &tableID);
            break;
        case CONFIGMESSAGE_TRUNCATE_TABLE_COMPLETE:
            read = buffer.Readf("%c:%U",
             &type, &tableID);
            break;
        case CONFIGMESSAGE_FREEZE_TABLE:
            read = buffer.Readf("%c:%U",
             &type, &tableID);
            break;
        case CONFIGMESSAGE_UNFREEZE_TABLE:
            read = buffer.Readf("%c:%U",
             &type, &tableID);
            break;

        // Shard management
        case CONFIGMESSAGE_SPLIT_SHARD_BEGIN:
            read = buffer.Readf("%c:%U:%#B",
             &type, &shardID, &splitKey);
            break;
        case CONFIGMESSAGE_SPLIT_SHARD_COMPLETE:
            read = buffer.Readf("%c:%U",
             &type, &shardID);
            break;
        case CONFIGMESSAGE_SHARD_MIGRATION_BEGIN:
            read = buffer.Readf("%c:%U:%U",
             &type, &quorumID, &shardID);
            break;
        case CONFIGMESSAGE_SHARD_MIGRATION_COMPLETE:
            read = buffer.Readf("%c:%U:%U:%U",
             &type, &quorumID, &srcShardID, &dstShardID);
            break;

        default:
            return false;
    }
    
    return (read == (signed)buffer.GetLength() ? true : false);
}
bool SDBPRequestMessage::Read(ReadBuffer& buffer)
{
    int         read;
    unsigned    i, numNodes;
    uint64_t    nodeID;
    ReadBuffer  optional;

    if (buffer.GetLength() < 1)
        return false;

    switch (buffer.GetCharAt(0))
    {
    /* Master query */
    case CLIENTREQUEST_GET_MASTER:
        read = buffer.Readf("%c:%U",
                            &request->type, &request->commandID);
        break;

    /* Get config state: databases, tables, shards, quora */
    case CLIENTREQUEST_GET_CONFIG_STATE:
        read = buffer.Readf("%c:%U",
                            &request->type, &request->commandID);
        break;

    /* Quorum management */
    case CLIENTREQUEST_CREATE_QUORUM:
        read = buffer.Readf("%c:%U:%u",
                            &request->type, &request->commandID, &numNodes);
        if (read < 0 || read == (signed)buffer.GetLength())
            return false;
        buffer.Advance(read);
        for (i = 0; i < numNodes; i++)
        {
            read = buffer.Readf(":%U", &nodeID);
            if (read < 0)
                return false;
            buffer.Advance(read);
            request->nodes.Append(nodeID);
        }
        if (buffer.GetLength() == 0)
            return true;
        else
            return false;
        break;
    case CLIENTREQUEST_DELETE_QUORUM:
        read = buffer.Readf("%c:%U:%U",
                            &request->type, &request->commandID, &request->quorumID);
        break;
    case CLIENTREQUEST_ADD_NODE:
        read = buffer.Readf("%c:%U:%U:%U",
                            &request->type, &request->commandID, &request->quorumID, &request->nodeID);
        break;
    case CLIENTREQUEST_REMOVE_NODE:
        read = buffer.Readf("%c:%U:%U:%U",
                            &request->type, &request->commandID, &request->quorumID, &request->nodeID);
        break;
    case CLIENTREQUEST_ACTIVATE_NODE:
        read = buffer.Readf("%c:%U:%U",
                            &request->type, &request->commandID, &request->nodeID);
        break;

    /* Database management */
    case CLIENTREQUEST_CREATE_DATABASE:
        read = buffer.Readf("%c:%U:%#B",
                            &request->type, &request->commandID, &request->name);
        break;
    case CLIENTREQUEST_RENAME_DATABASE:
        read = buffer.Readf("%c:%U:%U:%#B",
                            &request->type, &request->commandID, &request->databaseID,
                            &request->name);
        break;
    case CLIENTREQUEST_DELETE_DATABASE:
        read = buffer.Readf("%c:%U:%U",
                            &request->type, &request->commandID, &request->databaseID);
        break;
    case CLIENTREQUEST_SPLIT_SHARD:
        read = buffer.Readf("%c:%U:%U:%#B",
                            &request->type, &request->commandID,
                            &request->shardID, &request->key);
        break;
    case CLIENTREQUEST_MIGRATE_SHARD:
        read = buffer.Readf("%c:%U:%U:%U",
                            &request->type, &request->commandID, &request->shardID, &request->quorumID);
        return true;

    /* Table management */
    case CLIENTREQUEST_CREATE_TABLE:
        read = buffer.Readf("%c:%U:%U:%U:%#B",
                            &request->type, &request->commandID, &request->databaseID,
                            &request->quorumID, &request->name);
        break;
    case CLIENTREQUEST_RENAME_TABLE:
        read = buffer.Readf("%c:%U:%U:%#B",
                            &request->type, &request->commandID,
                            &request->tableID, &request->name);
        break;
    case CLIENTREQUEST_DELETE_TABLE:
        read = buffer.Readf("%c:%U:%U",
                            &request->type, &request->commandID,
                            &request->tableID);
        break;
    case CLIENTREQUEST_TRUNCATE_TABLE:
        read = buffer.Readf("%c:%U:%U",
                            &request->type, &request->commandID,
                            &request->tableID);
        break;

    /* Data operations */
    case CLIENTREQUEST_GET:
        read = buffer.Readf("%c:%U:%U:%U:%#B",
                            &request->type, &request->commandID,
                            &request->tableID, &request->paxosID,
                            &request->key);
        break;
    case CLIENTREQUEST_SET:
    case CLIENTREQUEST_SET_IF_NOT_EXISTS:
    case CLIENTREQUEST_GET_AND_SET:
        read = buffer.Readf("%c:%U:%U:%#B:%#B",
                            &request->type, &request->commandID,
                            &request->tableID, &request->key, &request->value);
        break;
    case CLIENTREQUEST_TEST_AND_SET:
        read = buffer.Readf("%c:%U:%U:%#B:%#B:%#B",
                            &request->type, &request->commandID,
                            &request->tableID, &request->key, &request->test, &request->value);
        break;
    case CLIENTREQUEST_TEST_AND_DELETE:
        read = buffer.Readf("%c:%U:%U:%#B:%#B",
                            &request->type, &request->commandID,
                            &request->tableID, &request->key, &request->test);
        break;
    case CLIENTREQUEST_ADD:
        read = buffer.Readf("%c:%U:%U:%#B:%I",
                            &request->type, &request->commandID,
                            &request->tableID, &request->key, &request->number);
        break;
    case CLIENTREQUEST_APPEND:
        read = buffer.Readf("%c:%U:%U:%#B:%#B",
                            &request->type, &request->commandID,
                            &request->tableID, &request->key, &request->value);
        break;
    case CLIENTREQUEST_DELETE:
    case CLIENTREQUEST_REMOVE:
        read = buffer.Readf("%c:%U:%U:%#B",
                            &request->type, &request->commandID,
                            &request->tableID, &request->key);
        break;

    case CLIENTREQUEST_LIST_KEYS:
    case CLIENTREQUEST_LIST_KEYVALUES:
    case CLIENTREQUEST_COUNT:
        read = buffer.Readf("%c:%U:%U:%#B:%#B:%#B:%U:%U",
                            &request->type, &request->commandID,
                            &request->tableID, &request->key, &request->endKey, &request->prefix,
                            &request->count, &request->offset);
        break;

    case CLIENTREQUEST_SUBMIT:
        read = buffer.Readf("%c:%U",
                            &request->type, &request->quorumID);
        break;

    case CLIENTREQUEST_BULK_LOADING:
        read = buffer.Readf("%c:%U",
                            &request->type, &request->commandID);
        break;

    default:
        return false;
    }

    return (read == (signed)buffer.GetLength() ? true : false);
}
bool ClusterConnection::OnMessage(ReadBuffer& msg)
{
    uint64_t            otherNodeID;
    uint64_t            otherClusterID;
    ReadBuffer          buffer;
    ClusterConnection*  dup;
    int                 read;

    //Log_Debug("ClusterConnection::OnMessage");

    if (progress == ClusterConnection::INCOMING)
    {
        // we have no incoming connections if we don't have a nodeID
        ASSERT(transport->IsAwaitingNodeID() == false);

        // the node at the other end is awaiting its nodeID
        if (msg.GetCharAt(0) == '*')
        {
            read = msg.Readf("*:%#R", &buffer);
            if (read != (int) msg.GetLength())
            {
                // protocol error
                GetSocket().GetEndpoint(endpoint);
                Log_Message("[%s] Cluster protocol error, disconnecting...", endpoint.ToString());
                transport->DeleteConnection(this);
                return true;
            }
            
            if (!endpoint.Set(buffer, true))
            {
                Log_Message("[%R] Cluster invalid network address", &buffer);
                transport->DeleteConnection(this);
                return true;                
            }
            
            progress = ClusterConnection::AWAITING_NODEID;
            Log_Trace("Conn is awaiting nodeID at %s", endpoint.ToString());

            transport->AddConnection(this);
            if (transport->OnAwaitingNodeID(endpoint))
            {
                Log_Trace();
                transport->DeleteConnection(this);
                return true;
            }
            if (nodeID == UNDEFINED_NODEID)
                Log_Message("[%s] Cluster unknown node connected <=", endpoint.ToString());
            else
                Log_Message("[%s] Cluster node %U connected <=", endpoint.ToString(), nodeID);
            return false;
        }
        
        // both ends have nodeIDs
        read = msg.Readf("%U:%U:%#R", &otherClusterID, &otherNodeID, &buffer);
        if (read != (int) msg.GetLength())
        {
            // protocol error
            GetSocket().GetEndpoint(endpoint);
            Log_Message("[%s] Cluster protocol error, disconnecting...", endpoint.ToString());
            transport->DeleteConnection(this);
            return true;
        }
        
        if (otherClusterID > 0)
        {
            if (transport->GetClusterID() == 0)
            {
                // the other side has a clusterID, I don't, so set mine
                // if I'm a config server:
                //   the clusterID also needs to be set in REPLICATON_CONFIG,
                //   this is set in ConfigServer::OnConnectionReady()
                // if I'm a shard server:
                //   the controllers will send a SetNodeID message, which
                //   contains the clusterID, so I'll be fine
                transport->SetClusterID(otherClusterID);
            }
            else
            {
                if (otherClusterID != transport->GetClusterID())
                {
                    Log_Message("[%R] Cluster invalid configuration, disconnecting...", &buffer);
                    Log_Debug("mine: %U != controller %U", transport->GetClusterID(), otherClusterID);
            
                    transport->DeleteConnection(this);          // drop this
                    return true;
                }
            }
        }
        
        dup = transport->GetConnection(otherNodeID);
        if (dup)
        {
            // if the other connections isn't ready yet, drop it
            // OR
            // the other connection is ready
            // in this case, kill the connection that was initiated by higher nodeID
            // in other words, since this is an incoming connection:
            // if nodeID[of initiator] > transport->GetSelfNodeID(): drop

            if (dup->progress != READY || otherNodeID > transport->GetSelfNodeID())
            {
                Log_Trace("delete dup");
                transport->DeleteConnection(dup);       // drop dup
            }
            else if (otherNodeID != transport->GetSelfNodeID())
            {
                Log_Trace("delete this");
                transport->DeleteConnection(this);      // drop this
                return true;
            }
        }
        progress = ClusterConnection::READY;
        SetNodeID(otherNodeID);
        if (!endpoint.Set(buffer, true))
        {
            Log_Message("[%R] Cluster invalid network address", &buffer);
            transport->DeleteConnection(this);
            return true;                
        }

        // check if the other side is not sending its localhost address, when they are on 
        // different nodes
        if (endpoint.GetAddress() == Endpoint::GetLoopbackAddress() && 
         transport->GetSelfEndpoint().GetAddress() != Endpoint::GetLoopbackAddress())
        {
            Log_Message("[%R] Cluster invalid network address", &buffer);
            transport->DeleteConnection(this);
            return true;
        }
        
        Log_Trace("Conn READY to node %U at %s", nodeID, endpoint.ToString());
        if (nodeID != transport->GetSelfNodeID())
        {
            if (nodeID == UNDEFINED_NODEID)
                Log_Message("[%s] Cluster unknown node connected <=", endpoint.ToString());
            else
                Log_Message("[%s] Cluster node %U connected <=", endpoint.ToString(), nodeID);
        }
        
        transport->AddConnection(this);
        transport->OnWriteReadyness(this);
        transport->OnConnectionReady(nodeID, endpoint);
    }
    else if (progress == ClusterConnection::OUTGOING)
        ASSERT_FAIL();
    else
        transport->OnMessage(nodeID, msg); // pass msg to upper layer
    
    return false;
}
Exemple #23
0
bool Endpoint::IsValidEndpoint(ReadBuffer ip_port)
{
    // Valid endpoint is either <IPv4-Address>:<port> or <IPv6-Address>:<port> or <Domain-Name>:<port>
    // Valid IPv4-Address consists only from numbers and three dots between the numbers
    // Valid IPv6-Adresses: http://en.wikipedia.org/wiki/IPv6#Addressing
    // Valid domain names: http://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names

    const char  VALID_CHARS[] = "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    unsigned    i;
    bool        labelStart;
    bool        isNumeric;
    bool        isHexnum;
    bool        isPort;
    bool        isIPv6;
    unsigned    numCommas;
    unsigned    numPortChars;
    char        c;
    char        prev;
    char        sep;
    char*       lastColon;

    // assuming fully numeric names
    isNumeric = true;
    isHexnum = true;
    isPort = false;
    numCommas = 0;
    numPortChars = 0;
    labelStart = true;
    isIPv6 = false;
    prev = ' ';
    sep = ' ';
    lastColon = NULL;
    for (i = 0; i < ip_port.GetLength(); i++)
    {
        c = ip_port.GetCharAt(i);

        if (c == '.' || c == ':')
        {
            if (i == 0)
            {
                // IPv4 and DNS must not start with comma or colon
                if (c == '.')
                    return false;

                isIPv6 = true;
                isHexnum = true;
            }

            // labels must not end with hyphens
            if (prev == VALID_CHARS[0])
                return false;
            
            if (c == '.')
            {
                labelStart = true;
                numCommas++;
                sep = c;
            }
            
            if (c == ':')
            {
                // cannot mix IPv4 and IPv6 addresses this way
                // this however is legal in IPv6: ::ffff:192.0.2.128
                if (isHexnum && sep != '.')
                {
                    isIPv6 = true;
                    sep = ':';
                    isPort = true;
                    numPortChars = 0;
                }
                else
                {
                    if (isPort && !isIPv6)
                        return false;
                    isPort = true;
                    numPortChars = 0;
                }

                lastColon = ip_port.GetBuffer() + i;
            }
        }
        else
        {        
            // labels must not start with hyphens
            if (labelStart && c == VALID_CHARS[0])
                return false;
            
            if (isPort)
            {
                if (!isdigit(c))
                {
                    if (isIPv6)
                        isPort = false;
                    else
                        return false;
                }
                else
                    numPortChars++;
            }
            
            if (isNumeric && !isdigit(c))
                isNumeric = false;
            
            if (isHexnum && !isxdigit(c))
            {
                if (isIPv6)
                    return false;
                isHexnum = false;
            }
            
            if (strchr(VALID_CHARS, c) == NULL)
                return false;

            labelStart = false;
        }
        
        prev = c;
    }

    if (isNumeric && numCommas != 3)
        return false;
    if (isIPv6 && numCommas != 0 && numCommas != 3)
        return false;
    if (numPortChars < 1 || numPortChars > 5)
        return false;
    
    return true;
}
Exemple #24
0
bool ClusterMessage::Read(ReadBuffer& buffer)
{
#define READ_SEPARATOR() \
    read = buffer.Readf(":"); \
    if (read != 1) \
        return false; \
    buffer.Advance(read); \

    int             read;
    ReadBuffer      tempBuffer;
        
    if (buffer.GetLength() < 1)
        return false;
    
    switch (buffer.GetCharAt(0))
    {
        case CLUSTERMESSAGE_SET_NODEID:
            read = buffer.Readf("%c:%U:%U",
             &type, &clusterID, &nodeID);
            break;
        case CLUSTERMESSAGE_UNREGISTER_STOP:
            read = buffer.Readf("%c",
             &type);
            break;
        case CLUSTERMESSAGE_HEARTBEAT:
            read = buffer.Readf("%c:%U:%u:%u",
             &type, &nodeID, &httpPort, &sdbpPort);
            if (read < 3)
                return false;
            buffer.Advance(read);
            READ_SEPARATOR();
            if (!QuorumInfo::ReadList(buffer, quorumInfos))
                return false;
            READ_SEPARATOR();
            if (!QuorumShardInfo::ReadList(buffer, quorumShardInfos))
                return false;
            return true;
            break;
        case CLUSTERMESSAGE_SET_CONFIG_STATE:
            type = CLUSTERMESSAGE_SET_CONFIG_STATE;
            return configState.Read(buffer, true);
        case CLUSTERMESSAGE_REQUEST_LEASE:
            read = buffer.Readf("%c:%U:%U:%U:%U:%U:%u",
             &type, &nodeID, &quorumID, &proposalID, &paxosID, &configID, &duration);
            break;
        case CLUSTERMESSAGE_RECEIVE_LEASE:
            read = buffer.Readf("%c:%U:%U:%U:%U:%u:%b",
             &type, &nodeID, &quorumID, &proposalID, &configID, &duration, &watchingPaxosID);
             if (read < 9)
                return false;
            buffer.Advance(read);
            READ_SEPARATOR();
            if (!MessageUtil::ReadIDList(activeNodes, buffer))
                return false;
            READ_SEPARATOR();
            if (!MessageUtil::ReadIDList(shards, buffer))
                return false;
            return true;
        case CLUSTERMESSAGE_SHARDMIGRATION_INITIATE:
            read = buffer.Readf("%c:%U:%U:%U:%U",
             &type, &nodeID, &quorumID, &srcShardID, &dstShardID);
            break;
        case CLUSTERMESSAGE_SHARDMIGRATION_BEGIN:
            read = buffer.Readf("%c:%U:%U:%U",
             &type, &quorumID, &srcShardID, &dstShardID);
            break;
        case CLUSTERMESSAGE_SHARDMIGRATION_SET:
            read = buffer.Readf("%c:%U:%U:%#R:%#R",
             &type, &quorumID, &shardID, &key, &value);
            break;
        case CLUSTERMESSAGE_SHARDMIGRATION_DELETE:
            read = buffer.Readf("%c:%U:%U:%#R",
             &type, &quorumID, &shardID, &key);
            break;
        case CLUSTERMESSAGE_SHARDMIGRATION_COMMIT:
            read = buffer.Readf("%c:%U:%U",
             &type, &quorumID, &shardID);
            break;
        case CLUSTERMESSAGE_SHARDMIGRATION_COMPLETE:
            read = buffer.Readf("%c:%U:%U",
             &type, &quorumID, &shardID);
            break;
        case CLUSTERMESSAGE_SHARDMIGRATION_PAUSE:
            read = buffer.Readf("%c",
             &type);
            break;
        case CLUSTERMESSAGE_SHARDMIGRATION_RESUME:
            read = buffer.Readf("%c",
             &type);
            break;
        case CLUSTERMESSAGE_HELLO:
            read = buffer.Readf("%c:%U:%#R",
             &type, &clusterID, &value);
            break;
        case CLUSTERMESSAGE_HTTP_ENDPOINT:
            read = buffer.Readf("%c:%U:%#R",
             &type, &nodeID, &endpoint);
            break;
        default:
            return false;
    }
    
    return (read == (signed)buffer.GetLength());
    
#undef READ_SEPARATOR
}