public Enum<?> putConfirm(PublicKey publicKey, Number640 key, Data newData) { RangeLock<Number640>.Range lock = lock(key); try { if (!securityEntryCheck( key.locationAndDomainAndContentKey(), publicKey, newData.publicKey(), newData.isProtectedEntry())) { return PutStatus.FAILED_SECURITY; } final Data data = backend.get(key); if (data != null) { // remove prepare flag data.prepareFlag(false); data.validFromMillis(newData.validFromMillis()); data.ttlSeconds(newData.ttlSeconds()); long expiration = data.expirationMillis(); // handle timeout backend.addTimeout(key, expiration); backend.put(key, data); // don't release data as we just update return PutStatus.OK; } else { return PutStatus.NOT_FOUND; } } finally { newData.release(); lock.unlock(); } // TODO: check for FORKS! }
public static int encodeData(ProtocolChunkedInput input, final Message message, Data data) { int count = 4 + 4; // encode entry protection in millis as the sign bit. Thus the max value // of millis is 2^31, which is more than enough int seconds = data.getTTLSeconds(); seconds = data.isProtectedEntry() ? seconds | 0x80000000 : seconds & 0x7FFFFFFF; input.copyToCurrent(seconds); input.copyToCurrent(data.getLength()); // the real data input.copyToCurrent(data.getData(), data.getOffset(), data.getLength()); count += data.getLength(); return count; }
public Enum<?> updateMeta(PublicKey publicKey, Number640 key, Data newData) { RangeLock<Number640>.Range lock = lock(key); try { if (!securityEntryCheck( key.locationAndDomainAndContentKey(), publicKey, newData.publicKey(), newData.isProtectedEntry())) { return PutStatus.FAILED_SECURITY; } final Data data = backend.get(key); boolean changed = false; if (data != null && newData.publicKey() != null) { data.publicKey(newData.publicKey()); changed = true; } if (data != null && newData.isSigned()) { data.signature(newData.signature()); changed = true; } if (data != null) { data.validFromMillis(newData.validFromMillis()); data.ttlSeconds(newData.ttlSeconds()); changed = true; } if (changed) { long expiration = data.expirationMillis(); // handle timeout backend.addTimeout(key, expiration); // no release of old data, as we just update it backend.put(key, data); return PutStatus.OK; } else { return PutStatus.NOT_FOUND; } } finally { newData.release(); lock.unlock(); } }
/** * Decodes the payload from a Netty buffer in a big switch * * @param content The content type * @param buffer The buffer to read from * @param message The message to store the results * @throws IndexOutOfBoundsException If a buffer is read beyond its limits * @throws NoSuchAlgorithmException * @throws SignatureException * @throws InvalidKeyException * @throws InvalidKeySpecException * @throws InvalidKeySpecException * @throws IOException * @throws DecoderException * @throws ASN1Exception * @throws UnsupportedEncodingException If UTF-8 is not there */ public static boolean decodePayload( final Content content, final ChannelBuffer buffer, final Message message) throws InvalidKeyException, SignatureException, NoSuchAlgorithmException, InvalidKeySpecException, IOException, DecoderException { final int len; byte[] me; switch (content) { case KEY: if (buffer.readableBytes() < 20) return false; message.setKey0(readID(buffer)); return true; case KEY_KEY: if (buffer.readableBytes() < 40) return false; message.setKeyKey0(readID(buffer), readID(buffer)); return true; case MAP_KEY_DATA: if (buffer.readableBytes() < 4) return false; int size = buffer.readInt(); Map<Number160, Data> result = new HashMap<Number160, Data>(size); for (int i = 0; i < size; i++) { if (buffer.readableBytes() < 20) return false; Number160 key = readID(buffer); final Data data = decodeData(new ChannelDecoder(buffer), message.getSender()); if (data == null) return false; if (message.isRequest()) { if (data.isProtectedEntry() && message.getPublicKey() == null) throw new DecoderException( "You indicated that you want to protect the data, but you did not provide or provided too late a public key."); data.setPublicKey(message.getPublicKey()); } result.put(key, data); } message.setDataMap0(result); return true; case MAP_KEY_KEY: if (buffer.readableBytes() < 4) return false; len = buffer.readInt(); if (buffer.readableBytes() < ((20 + 20) * len)) return false; final Map<Number160, Number160> keyMap = new HashMap<Number160, Number160>(); for (int i = 0; i < len; i++) { final Number160 key1 = readID(buffer); final Number160 key2 = readID(buffer); keyMap.put(key1, key2); } message.setKeyMap0(keyMap); return true; case SET_KEYS: // can be 31bit long ~ 2GB if (buffer.readableBytes() < 4) return false; len = buffer.readInt(); if (buffer.readableBytes() < (20 * len)) return false; final Collection<Number160> tmp = new ArrayList<Number160>(len); for (int i = 0; i < len; i++) { Number160 key = readID(buffer); tmp.add(key); } message.setKeys0(tmp); return true; case SET_NEIGHBORS: if (buffer.readableBytes() < 1) return false; len = buffer.readUnsignedByte(); if (buffer.readableBytes() < (len * PeerAddress.SIZE_IPv4)) return false; final Collection<PeerAddress> neighbors = new ArrayList<PeerAddress>(len); for (int i = 0; i < len; i++) { PeerAddress peerAddress = readPeerAddress(buffer); if (peerAddress == null) return false; neighbors.add(peerAddress); } message.setNeighbors0(neighbors); return true; case SET_TRACKER_DATA: if (buffer.readableBytes() < 1) return false; len = buffer.readUnsignedByte(); if (buffer.readableBytes() < (len * (PeerAddress.SIZE_IPv4 + 1))) return false; final Collection<TrackerData> trackerDatas = new ArrayList<TrackerData>(len); for (int i = 0; i < len; i++) { PeerAddress peerAddress = readPeerAddress(buffer); if (peerAddress == null) return false; byte[] attachment = null; int offset = 0; int length = 0; if (buffer.readableBytes() < 1) return false; byte miniHeader = buffer.readByte(); if (miniHeader != 0) { if (buffer.readableBytes() < 4) return false; length = buffer.readInt(); if (buffer.readableBytes() < length) return false; attachment = new byte[length]; buffer.readBytes(attachment); } trackerDatas.add( new TrackerData(peerAddress, message.getSender(), attachment, offset, length)); } message.setTrackerData0(trackerDatas); return true; case CHANNEL_BUFFER: if (buffer.readableBytes() < 4) return false; len = buffer.readInt(); if (buffer.readableBytes() < len) return false; // you can only use slice if no execution handler is in place, // otherwise, you will overwrite stuff final ChannelBuffer tmpBuffer = buffer.slice(buffer.readerIndex(), len); buffer.skipBytes(len); message.setPayload0(tmpBuffer); return true; case LONG: if (buffer.readableBytes() < 8) return false; message.setLong0(buffer.readLong()); return true; case INTEGER: if (buffer.readableBytes() < 4) return false; message.setInteger0(buffer.readInt()); return true; case PUBLIC_KEY: case PUBLIC_KEY_SIGNATURE: if (buffer.readableBytes() < 2) return false; len = buffer.readUnsignedShort(); me = new byte[len]; if (buffer.readableBytes() < len) return false; message.setPublicKey0(decodePublicKey(new ChannelDecoder(buffer), me)); if (content == Content.PUBLIC_KEY_SIGNATURE) { message.setHintSign(true); } return true; case EMPTY: case RESERVED1: case RESERVED2: case RESERVED3: default: return true; } }
public Map<Number640, Enum<?>> putAll( final NavigableMap<Number640, Data> dataMap, PublicKey publicKey, boolean putIfAbsent, boolean domainProtection, boolean sendSelf) { if (dataMap.isEmpty()) { return Collections.emptyMap(); } final Number640 min = dataMap.firstKey(); final Number640 max = dataMap.lastKey(); final Map<Number640, Enum<?>> retVal = new HashMap<Number640, Enum<?>>(); final HashSet<Number480> keysToCheck = new HashSet<Number480>(); final RangeLock<Number640>.Range lock = lock(min, max); try { for (Map.Entry<Number640, Data> entry : dataMap.entrySet()) { Number640 key = entry.getKey(); keysToCheck.add(key.locationAndDomainAndContentKey()); Data newData = entry.getValue(); if (!securityDomainCheck( key.locationAndDomainKey(), publicKey, publicKey, domainProtection)) { retVal.put(key, PutStatus.FAILED_SECURITY); newData.release(); continue; } // We need this check in case we did not use the encoder/decoder, // which is the case if we send the message to ourself. In that // case, the public key of the data is never set to the message // publick key, if the publick key of the data was null. final PublicKey dataKey; if (sendSelf && newData.publicKey() == null) { dataKey = publicKey; } else { dataKey = newData.publicKey(); } if (!securityEntryCheck( key.locationAndDomainAndContentKey(), publicKey, dataKey, newData.isProtectedEntry())) { retVal.put(key, PutStatus.FAILED_SECURITY); newData.release(); continue; } final Data oldDataGet = backend.get(key); if (oldDataGet != null) { if (putIfAbsent) { retVal.put(key, PutStatus.FAILED_NOT_ABSENT); newData.release(); continue; } if (oldDataGet.isDeleted()) { retVal.put(key, PutStatus.DELETED); newData.release(); continue; } if (!oldDataGet.basedOnSet().equals(newData.basedOnSet())) { retVal.put(key, PutStatus.VERSION_FORK); newData.release(); continue; } } final Data oldDataPut = backend.put(key, newData); long expiration = newData.expirationMillis(); // handle timeout backend.addTimeout(key, expiration); if (newData.hasPrepareFlag()) { retVal.put(key, PutStatus.OK_PREPARED); } else { retVal.put(key, PutStatus.OK); } if (oldDataPut != null && oldDataPut != newData) { oldDataPut.release(); } } for (Number480 key : keysToCheck) { // now check for forks Number640 minVersion = new Number640(key, Number160.ZERO); Number640 maxVersion = new Number640(key, Number160.MAX_VALUE); NavigableMap<Number640, Data> tmp = backend.subMap(minVersion, maxVersion); tmp = filterCopyOrig(tmp, -1, true); NavigableMap<Number640, Data> heads = getLatestInternalOrig(tmp); final boolean forked = heads.size() > 1; for (final Map.Entry<Number640, Data> entry : heads.entrySet()) { if (forked) { if (retVal.containsKey(entry.getKey())) { retVal.put(entry.getKey(), PutStatus.VERSION_FORK); } } } // now remove old versions if (maxVersions > 0) { NavigableMap<Number640, Data> versions = backend.subMap(minVersion, maxVersion); while (!versions.isEmpty() && versions.firstKey().versionKey().timestamp() + maxVersions <= versions.lastKey().versionKey().timestamp()) { Map.Entry<Number640, Data> entry = versions.pollFirstEntry(); Data removed = backend.remove(entry.getKey(), true); if (removed != null) { removed.release(); } backend.removeTimeout(entry.getKey()); } } } return retVal; } finally { lock.unlock(); } }