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); }
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; }
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; } }
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); }
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); }
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); }
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; }
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; }
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); }
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; }
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; }
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()); }
void Buffer::Append(ReadBuffer other) { Append(other.GetBuffer(), other.GetLength()); }
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(); }
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; }
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; }
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 }