001/* 002 * This file is part of the Kompics component model runtime. 003 * 004 * Copyright (C) 2009 Swedish Institute of Computer Science (SICS) 005 * Copyright (C) 2009 Royal Institute of Technology (KTH) 006 * 007 * This program is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU General Public License 009 * as published by the Free Software Foundation; either version 2 010 * of the License, or (at your option) any later version. 011 * 012 * This program is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 015 * GNU General Public License for more details. 016 * 017 * You should have received a copy of the GNU General Public License 018 * along with this program; if not, write to the Free Software 019 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 020 */ 021package se.sics.kompics.network.netty.serialization; 022 023import java.util.Optional; 024import com.google.common.primitives.Ints; 025import com.google.common.primitives.UnsignedBytes; 026import io.netty.buffer.ByteBuf; 027import java.net.InetAddress; 028import java.net.InetSocketAddress; 029import java.net.UnknownHostException; 030import java.util.ArrayList; 031import java.util.Arrays; 032import java.util.UUID; 033import se.sics.kompics.network.Address; 034import se.sics.kompics.network.Transport; 035import se.sics.kompics.network.netty.DirectMessage; 036import se.sics.kompics.network.netty.NettyAddress; 037 038/** 039 * 040 * @author Lars Kroll {@literal <[email protected]>} 041 */ 042public abstract class SpecialSerializers { 043 044 public static class NullSerializer implements Serializer { 045 046 @Override 047 public int identifier() { 048 return 0; 049 } 050 051 @Override 052 public void toBinary(Object o, ByteBuf buf) { 053 // simply ignore input 054 } 055 056 @Override 057 public Object fromBinary(ByteBuf buf, Optional<Object> hint) { 058 return null; 059 } 060 061 } 062 063 public static class ByteSerializer implements Serializer { 064 065 @Override 066 public int identifier() { 067 return 1; 068 } 069 070 @Override 071 public void toBinary(Object o, ByteBuf buf) { 072 byte[] bytes = (byte[]) o; 073 int code = buf.ensureWritable(bytes.length + 4, true); 074 if (code == 1 || code == 3) { 075 Serializers.LOG.error( 076 "ByteSerializer: Not enough space left on buffer to serialize " + bytes.length + " bytes."); 077 return; 078 } 079 buf.writeInt(bytes.length); 080 buf.writeBytes(bytes); 081 } 082 083 @Override 084 public Object fromBinary(ByteBuf buf, Optional<Object> hint) { 085 int length = buf.readInt(); 086 byte[] bytes = new byte[length]; 087 buf.readBytes(bytes); 088 return bytes; 089 } 090 091 } 092 093 public static class AddressSerializer implements Serializer { 094 095 public static final int BYTE_KEY_SIZE = 255; 096 public static final int INT_BYTE_SIZE = Integer.SIZE / 8; 097 public static final AddressSerializer INSTANCE = new AddressSerializer(); 098 099 @Override 100 public int identifier() { 101 return 2; 102 } 103 104 @Override 105 public void toBinary(Object o, ByteBuf buf) { 106 Address addr = (Address) o; 107 if (addr == null) { 108 buf.writeInt(0); // simply put four 0 bytes since 0.0.0.0 is not a valid host ip 109 return; 110 } 111 112 socketToBinary(addr.asSocket(), buf); 113 } 114 115 @Override 116 public Object fromBinary(ByteBuf buf, Optional<Object> hint) { 117 byte[] ipBytes = new byte[4]; 118 buf.readBytes(ipBytes); 119 if ((ipBytes[0] == 0) && (ipBytes[1] == 0) && (ipBytes[2] == 0) && (ipBytes[3] == 0)) { 120 return null; // IP 0.0.0.0 is not valid but null Address encoding 121 } 122 InetAddress ip; 123 try { 124 ip = InetAddress.getByAddress(ipBytes); 125 } catch (UnknownHostException ex) { 126 Serializers.LOG.error("AddressSerializer: Could not create InetAddress.", ex); 127 return null; 128 } 129 byte portUpper = buf.readByte(); 130 byte portLower = buf.readByte(); 131 int port = Ints.fromBytes((byte) 0, (byte) 0, portUpper, portLower); 132 133 return new NettyAddress(ip, port); 134 } 135 136 public void socketToBinary(InetSocketAddress isa, ByteBuf buf) { 137 buf.writeBytes(isa.getAddress().getAddress()); 138 // Write ports as 2 bytes instead of 4 139 byte[] portBytes = Ints.toByteArray(isa.getPort()); 140 buf.writeByte(portBytes[2]); 141 buf.writeByte(portBytes[3]); 142 } 143 144 public InetSocketAddress socketFromBinary(ByteBuf buf) { 145 byte[] ipBytes = new byte[4]; 146 buf.readBytes(ipBytes); 147 InetAddress ip; 148 try { 149 ip = InetAddress.getByAddress(ipBytes); 150 } catch (UnknownHostException ex) { 151 Serializers.LOG.error("AddressSerializer: Could not create InetAddress.", ex); 152 return null; 153 } 154 byte portUpper = buf.readByte(); 155 byte portLower = buf.readByte(); 156 int port = Ints.fromBytes((byte) 0, (byte) 0, portUpper, portLower); 157 return new InetSocketAddress(ip, port); 158 } 159 160 } 161 162 public static class UUIDSerializer implements Serializer { 163 164 public static final UUIDSerializer INSTANCE = new UUIDSerializer(); 165 166 @Override 167 public int identifier() { 168 return 6; 169 } 170 171 @Override 172 public void toBinary(Object o, ByteBuf buf) { 173 if (o instanceof UUID) { 174 UUID id = (UUID) o; 175 buf.writeLong(id.getMostSignificantBits()); 176 buf.writeLong(id.getLeastSignificantBits()); 177 } 178 } 179 180 @Override 181 public Object fromBinary(ByteBuf buf, Optional<Object> hint) { 182 return new UUID(buf.readLong(), buf.readLong()); 183 } 184 185 } 186 187 public static abstract class MessageSerializationUtil { 188 189 public static void msgToBinary(DirectMessage msg, ByteBuf buf, boolean flag1, boolean flag2) { 190 BitBuffer bbuf = BitBuffer.create(flag1, flag2, // good that a byte has so many bits... can compress it more 191 // if more protocols are necessary 192 msg.getProtocol() == Transport.UDP, msg.getProtocol() == Transport.TCP, 193 msg.getProtocol() == Transport.MULTICAST_UDP, msg.getProtocol() == Transport.UDT, 194 msg.getProtocol() == Transport.LEDBAT); 195 byte[] bbufb = bbuf.finalise(); 196 buf.writeBytes(bbufb); 197 // Addresses 198 AddressSerializer.INSTANCE.toBinary(msg.getSource(), buf); 199 AddressSerializer.INSTANCE.toBinary(msg.getDestination(), buf); 200 } 201 202 public static MessageFields msgFromBinary(ByteBuf buf) { 203 MessageFields fields = new MessageFields(); 204 205 byte[] flagB = new byte[1]; 206 buf.readBytes(flagB); 207 boolean[] flags = BitBuffer.extract(8, flagB); 208 fields.flag1 = flags[0]; 209 fields.flag2 = flags[1]; 210 if (flags[2]) { 211 fields.proto = Transport.UDP; 212 } 213 if (flags[3]) { 214 fields.proto = Transport.TCP; 215 } 216 if (flags[4]) { 217 fields.proto = Transport.MULTICAST_UDP; 218 } 219 if (flags[5]) { 220 fields.proto = Transport.UDT; 221 } 222 if (flags[6]) { 223 fields.proto = Transport.LEDBAT; 224 } 225 226 // Addresses 227 fields.src = (NettyAddress) AddressSerializer.INSTANCE.fromBinary(buf, Optional.empty()); 228 fields.dst = (NettyAddress) AddressSerializer.INSTANCE.fromBinary(buf, Optional.empty()); 229 fields.orig = fields.src; 230 231 return fields; 232 } 233 234 public static class MessageFields { 235 236 public NettyAddress src; 237 public NettyAddress dst; 238 public NettyAddress orig; 239 public Transport proto; 240 public boolean flag1; 241 public boolean flag2; 242 } 243 } 244 245 static class BitBuffer { 246 247 private static final int ZERO = 0; 248 private static final int[] POS = { 1, 2, 4, 8, 16, 32, 64, 128 }; 249 250 private final ArrayList<Boolean> buffer = new ArrayList<Boolean>(); 251 252 private BitBuffer() { 253 } 254 255 public static BitBuffer create(Boolean... args) { 256 BitBuffer b = new BitBuffer(); 257 b.buffer.addAll(Arrays.asList(args)); 258 return b; 259 } 260 261 public BitBuffer write(Boolean... args) { 262 buffer.addAll(Arrays.asList(args)); 263 return this; 264 } 265 266 public byte[] finalise() { 267 int numBytes = (int) Math.ceil(((double) buffer.size()) / 8.0); 268 byte[] bytes = new byte[numBytes]; 269 for (int i = 0; i < numBytes; i++) { 270 int b = ZERO; 271 for (int j = 0; j < 8; j++) { 272 int pos = i * 8 + j; 273 if (buffer.size() > pos) { 274 if (buffer.get(pos)) { 275 b = b ^ POS[j]; 276 } 277 } 278 } 279 bytes[i] = UnsignedBytes.checkedCast(b); 280 } 281 return bytes; 282 } 283 284 public static boolean[] extract(int numValues, byte[] bytes) { 285 assert (((int) Math.ceil(((double) numValues) / 8.0)) <= bytes.length); 286 287 boolean[] output = new boolean[numValues]; 288 for (int i = 0; i < bytes.length; i++) { 289 int b = bytes[i]; 290 for (int j = 0; j < 8; j++) { 291 int pos = i * 8 + j; 292 if (pos >= numValues) { 293 return output; 294 } 295 output[pos] = ((b & POS[j]) != 0); 296 } 297 } 298 299 return output; 300 } 301 } 302}