Coverage Summary for Class: HelloMessage (org.ethereum.net.p2p)
Class |
Class, %
|
Method, %
|
Line, %
|
HelloMessage |
0%
(0/1)
|
0%
(0/15)
|
0%
(0/76)
|
1 /*
2 * This file is part of RskJ
3 * Copyright (C) 2017 RSK Labs Ltd.
4 * (derived from ethereumJ library, Copyright (c) 2016 <ether.camp>)
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 package org.ethereum.net.p2p;
21
22 import org.bouncycastle.util.encoders.Hex;
23 import org.ethereum.net.client.Capability;
24 import org.ethereum.util.ByteUtil;
25 import org.ethereum.util.RLP;
26 import org.ethereum.util.RLPElement;
27 import org.ethereum.util.RLPList;
28
29 import java.nio.charset.StandardCharsets;
30 import java.util.ArrayList;
31 import java.util.Collections;
32 import java.util.List;
33 import java.util.stream.Collectors;
34
35 import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY;
36
37 /**
38 * Wrapper around an Ethereum HelloMessage on the network
39 *
40 * @see org.ethereum.net.p2p.P2pMessageCodes#HELLO
41 */
42 public class HelloMessage extends P2pMessage {
43
44 /**
45 * The implemented version of the P2P protocol.
46 */
47 private byte p2pVersion;
48 /**
49 * The underlying client. A user-readable string.
50 */
51 private String clientId;
52 /**
53 * A peer-network capability code, readable ASCII and 3 letters.
54 * Currently only "eth", "shh" and "bzz" are known.
55 */
56 private List<Capability> capabilities = Collections.emptyList();
57 /**
58 * The port on which the peer is listening for an incoming connection
59 */
60 private int listenPort;
61 /**
62 * The identity and public key of the peer
63 */
64 private String peerId;
65
66 public HelloMessage(byte[] encoded) {
67 super(encoded);
68 }
69
70 public HelloMessage(byte p2pVersion, String clientId,
71 List<Capability> capabilities, int listenPort, String peerId) {
72 this.p2pVersion = p2pVersion;
73 this.clientId = clientId;
74 this.capabilities = capabilities;
75 this.listenPort = listenPort;
76 this.peerId = peerId;
77 this.parsed = true;
78 }
79
80 private void parse() {
81 RLPList paramsList = (RLPList) RLP.decode2(encoded).get(0);
82
83 byte[] p2pVersionBytes = paramsList.get(0).getRLPData();
84 this.p2pVersion = p2pVersionBytes != null ? p2pVersionBytes[0] : 0;
85
86 byte[] clientIdBytes = paramsList.get(1).getRLPData();
87 this.clientId = new String(clientIdBytes != null ? clientIdBytes : EMPTY_BYTE_ARRAY);
88
89 RLPList capabilityList = (RLPList) paramsList.get(2);
90 this.capabilities = new ArrayList<>();
91
92 for (int k = 0; k < capabilityList.size(); k++) {
93 Object aCapabilityList = capabilityList.get(k);
94
95 RLPElement capId = ((RLPList) aCapabilityList).get(0);
96 RLPElement capVersion = ((RLPList) aCapabilityList).get(1);
97
98 String name = new String(capId.getRLPData());
99 byte version = capVersion.getRLPData() == null ? 0 : capVersion.getRLPData()[0];
100
101 Capability cap = new Capability(name, version);
102 this.capabilities.add(cap);
103 }
104
105 byte[] peerPortBytes = paramsList.get(3).getRLPData();
106 this.listenPort = ByteUtil.byteArrayToInt(peerPortBytes);
107
108 byte[] peerIdBytes = paramsList.get(4).getRLPData();
109 this.peerId = ByteUtil.toHexString(peerIdBytes);
110 this.parsed = true;
111 }
112
113 private void encode() {
114 byte[] p2pVersion = RLP.encodeByte(this.p2pVersion);
115 byte[] clientId = RLP.encodeString(this.clientId);
116 byte[][] capabilities = new byte[this.capabilities.size()][];
117 for (int i = 0; i < this.capabilities.size(); i++) {
118 Capability capability = this.capabilities.get(i);
119 capabilities[i] = RLP.encodeList(
120 RLP.encodeElement(capability.getName().getBytes(StandardCharsets.UTF_8)),
121 RLP.encodeInt(capability.getVersion()));
122 }
123 byte[] capabilityList = RLP.encodeList(capabilities);
124 byte[] peerPort = RLP.encodeInt(this.listenPort);
125 byte[] peerId = RLP.encodeElement(Hex.decode(this.peerId));
126
127 this.encoded = RLP.encodeList(p2pVersion, clientId,
128 capabilityList, peerPort, peerId);
129 }
130
131 @Override
132 public byte[] getEncoded() {
133 if (encoded == null) {
134 encode();
135 }
136 return encoded;
137 }
138
139 public byte getP2PVersion() {
140 if (!parsed) {
141 parse();
142 }
143 return p2pVersion;
144 }
145
146 public String getClientId() {
147 if (!parsed) {
148 parse();
149 }
150 return clientId;
151 }
152
153 public List<Capability> getCapabilities() {
154 if (!parsed) {
155 parse();
156 }
157 return capabilities;
158 }
159
160 public int getListenPort() {
161 if (!parsed) {
162 parse();
163 }
164 return listenPort;
165 }
166
167 public String getPeerId() {
168 if (!parsed) {
169 parse();
170 }
171 return peerId;
172 }
173
174 @Override
175 public P2pMessageCodes getCommand() {
176 return P2pMessageCodes.HELLO;
177 }
178
179 public void setPeerId(String peerId) {
180 this.peerId = peerId;
181 }
182
183 public void setP2pVersion(byte p2pVersion) {
184 this.p2pVersion = p2pVersion;
185 }
186
187 @Override
188 public Class<?> getAnswerMessage() {
189 return null;
190 }
191
192 public String toString() {
193 if (!parsed) {
194 parse();
195 }
196
197 return String.format(
198 "[%s p2pVersion=%s clientId=%s capabilities=[%s] getPeerPort=%d peerId=%s]",
199 this.getCommand().name(),
200 this.p2pVersion,
201 this.clientId,
202 this.capabilities.stream().map(Capability::toString).collect(Collectors.joining(" ")),
203 this.listenPort,
204 this.peerId
205 );
206 }
207 }