You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

396 lines
13 KiB

  1. // Copyright 2017-2018 DERO Project. All rights reserved.
  2. // Use of this source code in any form is governed by RESEARCH license.
  3. // license can be found in the LICENSE file.
  4. // GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
  5. //
  6. //
  7. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
  8. // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  9. // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
  10. // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  11. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  12. // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  13. // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  14. // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  15. // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  16. package p2p
  17. import "io"
  18. import "net"
  19. import "fmt"
  20. import "time"
  21. import "testing"
  22. import "container/list"
  23. import "encoding/binary"
  24. import "runtime/debug"
  25. import "github.com/romana/rlog"
  26. import log "github.com/sirupsen/logrus"
  27. import "github.com/deroproject/derosuite/globals"
  28. // all communications flow in little endian
  29. const LEVIN_SIGNATURE = 0x0101010101012101 //Bender's nightmare
  30. const LEVIN_SIGNATURE_DATA = 0x0102010101011101
  31. const LEVIN_PROTOCOL_VER_0 = 0
  32. const LEVIN_PROTOCOL_VER_1 = 1
  33. const LEVIN_PACKET_REQUEST = 0x00000001
  34. const LEVIN_PACKET_RESPONSE = 0x00000002
  35. // the whole structure should be packed into 33 bytes
  36. type Levin_Header struct {
  37. Signature uint64
  38. CB uint64 // this contains data size appended to buffer
  39. ReturnData bool
  40. Command uint32
  41. ReturnCode int32
  42. Flags uint32
  43. Protocol_Version uint32
  44. }
  45. // all response will have the signature in big endian form
  46. type Levin_Data_Header struct {
  47. Signature uint64 // LEVIN_SIGNATURE_DATA
  48. //Boost_Header byte
  49. Data []byte
  50. }
  51. // sets timeout based on connection state, so as stale connections are cleared quickly
  52. func set_timeout(connection *Connection) {
  53. if connection.State == HANDSHAKE_PENDING {
  54. connection.Conn.SetReadDeadline(time.Now().Add(20 * time.Second)) // new connections have 20 seconds to handshake
  55. } else {
  56. connection.Conn.SetReadDeadline(time.Now().Add(300 * time.Second)) // good connections have 5 mins to communicate
  57. }
  58. }
  59. /* this is the entire connection handler, all incoming/outgoing connections end up here */
  60. func Handle_Connection(conn net.Conn, remote_addr *net.TCPAddr, incoming bool) {
  61. var connection Connection
  62. var levin_header Levin_Header
  63. connection.Incoming = incoming
  64. connection.Conn = conn
  65. var idle int
  66. connection.Addr = remote_addr // since we may be connecting via socks, get target IP
  67. connection.Command_queue = list.New() // init command queue
  68. connection.State = HANDSHAKE_PENDING
  69. if incoming {
  70. connection.logger = logger.WithFields(log.Fields{"RIP": remote_addr.String(), "DIR": "INC"})
  71. } else {
  72. connection.logger = logger.WithFields(log.Fields{"RIP": remote_addr.String(), "DIR": "OUT"})
  73. }
  74. defer func() {
  75. if r := recover(); r != nil {
  76. connection.logger.Warnf("Recovered while handling connection, Stack trace below", r)
  77. connection.logger.Warnf("Stack trace \n%s", debug.Stack())
  78. }
  79. }()
  80. Connection_Add(&connection) // add connection to pool
  81. if !incoming {
  82. Send_Handshake(&connection) // send handshake
  83. }
  84. // goroutine to exit the connection if signalled
  85. go func() {
  86. ticker := time.NewTicker(1 * time.Second) // 1 second ticker
  87. for {
  88. select {
  89. case <-ticker.C:
  90. idle++
  91. // if idle more than 13 secs, we should send a timed sync
  92. if idle > 13 {
  93. if connection.State != HANDSHAKE_PENDING {
  94. connection.State = IDLE
  95. }
  96. Send_Timed_Sync(&connection)
  97. //connection.logger.Debugf("We should send a timed sync")
  98. idle = 0
  99. }
  100. case <-Exit_Event: // p2p is shutting down, close the connection
  101. connection.Exit = true
  102. ticker.Stop() // release resources of timer
  103. Connection_Delete(&connection)
  104. conn.Close()
  105. return // close the connection and close the routine
  106. }
  107. if connection.Exit { // release resources of timer
  108. ticker.Stop()
  109. Connection_Delete(&connection)
  110. return
  111. }
  112. }
  113. }()
  114. for {
  115. if connection.Exit {
  116. connection.logger.Debugf("Connection exited")
  117. conn.Close()
  118. return
  119. }
  120. // wait and read header
  121. header_data := make([]byte, 33, 33) // size of levin header
  122. idle = 0
  123. rlog.Tracef(10, "waiting to read header bytes from network %s\n", globals.CTXString(connection.logger))
  124. set_timeout(&connection)
  125. read_bytes, err := io.ReadFull(conn, header_data)
  126. if err != nil {
  127. rlog.Tracef(4, "Error while reading levin header exiting err:%s\n", err)
  128. connection.Exit = true
  129. continue
  130. }
  131. rlog.Tracef(10, "Read %d bytes from network\n", read_bytes)
  132. if connection.State != HANDSHAKE_PENDING {
  133. connection.State = ACTIVE
  134. }
  135. err = levin_header.DeSerialize(header_data)
  136. if err != nil {
  137. rlog.Tracef(4, "Error while DeSerializing levin header exiting err:%s\n", err)
  138. connection.Exit = true
  139. continue
  140. }
  141. // read data as per requirement
  142. data := make([]byte, levin_header.CB, levin_header.CB)
  143. set_timeout(&connection)
  144. read_bytes, err = io.ReadFull(conn, data)
  145. rlog.Tracef(10, "Read %d bytes from network for data \n", read_bytes)
  146. if err != nil {
  147. rlog.Tracef(4, "Error while reading levin data exiting err:%s\n", err)
  148. connection.Exit = true
  149. continue
  150. }
  151. name := COMMAND_NAME[levin_header.Command]
  152. if name == "" {
  153. connection.logger.Warnf("No Such command %d exiting\n", levin_header.Command)
  154. connection.Exit = true
  155. continue
  156. }
  157. //connection.logger.WithFields(log.Fields{
  158. // "command": name,
  159. // "flags": levin_header.Flags}).Debugf("Incoming Command")
  160. if levin_header.Flags == LEVIN_PACKET_RESPONSE {
  161. if connection.Command_queue.Len() < 1 {
  162. connection.logger.Warnf("Invalid Response ( we have not queued anything\n")
  163. connection.Exit = true
  164. continue
  165. }
  166. front_command := connection.Command_queue.Front()
  167. if levin_header.Command != front_command.Value.(uint32) {
  168. connection.logger.Warnf("Invalid Response ( we queued some other command\n")
  169. connection.Exit = true
  170. continue
  171. }
  172. connection.Lock()
  173. connection.Command_queue.Remove(front_command)
  174. connection.Unlock()
  175. switch levin_header.Command {
  176. case P2P_COMMAND_HANDSHAKE: // Parse incoming handshake response
  177. Handle_P2P_Handshake_Command_Response(&connection, &levin_header, data)
  178. // if response is OK, mark conncection as good and add it to list
  179. case P2P_COMMAND_TIMED_SYNC: // we never send timed response
  180. // connection.logger.Infof("Response for timed sync arrived")
  181. Handle_P2P_Timed_Sync_Response(&connection, &levin_header, data)
  182. case P2P_COMMAND_PING: // we never send ping packets
  183. case P2P_COMMAND_REQUEST_SUPPORT_FLAGS: // we never send flags packet
  184. }
  185. }
  186. if levin_header.Flags == LEVIN_PACKET_REQUEST {
  187. switch levin_header.Command {
  188. case P2P_COMMAND_HANDSHAKE: // send response
  189. connection.logger.Debugf("Incoming handshake command")
  190. Handle_P2P_Handshake_Command(&connection, &levin_header, data)
  191. case P2P_COMMAND_REQUEST_SUPPORT_FLAGS: // send reponse
  192. Handle_P2P_Support_Flags(&connection, &levin_header, data)
  193. case P2P_COMMAND_TIMED_SYNC:
  194. Handle_P2P_Timed_Sync(&connection, &levin_header, data)
  195. // crypto note core protocols commands related to blockchain
  196. // peer wants to syncronise his chain to ours
  197. case BC_NOTIFY_REQUEST_CHAIN:
  198. Handle_BC_Notify_Chain(&connection, &levin_header, data)
  199. // we want to syncronise our chain to peers
  200. case BC_NOTIFY_RESPONSE_CHAIN_ENTRY:
  201. Handle_BC_Notify_Response_Chain_Entry(&connection, &levin_header, data)
  202. case BC_NOTIFY_REQUEST_GET_OBJECTS: // peer requested some object
  203. Handle_BC_Notify_Request_GetObjects(&connection, &levin_header, data)
  204. case BC_NOTIFY_RESPONSE_GET_OBJECTS: // peer responded to our object requests
  205. Handle_BC_Notify_Response_GetObjects(&connection, &levin_header, data)
  206. case BC_NOTIFY_NEW_TRANSACTIONS:
  207. Handle_BC_Notify_New_Transactions(&connection, &levin_header, data)
  208. case BC_NOTIFY_NEW_BLOCK:
  209. Handle_BC_Notify_New_Block(&connection, &levin_header, data)
  210. }
  211. }
  212. }
  213. }
  214. /* this operation can never fail */
  215. func SerializeLevinHeader(header Levin_Header) []byte {
  216. packed_buffer := make([]byte, 33, 33)
  217. binary.LittleEndian.PutUint64(packed_buffer[0:8], LEVIN_SIGNATURE) // packed 8 bytes
  218. binary.LittleEndian.PutUint64(packed_buffer[8:16], header.CB) // packed 8 + 8 bytes
  219. if header.ReturnData {
  220. packed_buffer[16] = 1 // packed 8 + 8 + 1
  221. }
  222. binary.LittleEndian.PutUint32(packed_buffer[17:17+4], header.Command) // packed 8+8+1+4 bytes
  223. binary.LittleEndian.PutUint32(packed_buffer[21:21+4], uint32(header.ReturnCode)) // packed 8+8+1+4 bytes
  224. binary.LittleEndian.PutUint32(packed_buffer[25:25+4], header.Flags) // packed 8+8+1+4 bytes
  225. binary.LittleEndian.PutUint32(packed_buffer[29:29+4], LEVIN_PROTOCOL_VER_1) // packed 8+8+1+4 bytes
  226. return packed_buffer
  227. }
  228. func (header Levin_Header) Serialize() ([]byte, int) {
  229. packed_buffer := make([]byte, 33, 33)
  230. binary.LittleEndian.PutUint64(packed_buffer[0:8], LEVIN_SIGNATURE) // packed 8 bytes
  231. binary.LittleEndian.PutUint64(packed_buffer[8:16], header.CB) // packed 8 + 8 bytes
  232. if header.ReturnData {
  233. packed_buffer[16] = 1 // packed 8 + 8 + 1
  234. }
  235. binary.LittleEndian.PutUint32(packed_buffer[17:17+4], header.Command) // packed 8+8+1+4 bytes
  236. binary.LittleEndian.PutUint32(packed_buffer[21:21+4], uint32(header.ReturnCode)) // packed 8+8+1+4 bytes
  237. binary.LittleEndian.PutUint32(packed_buffer[25:25+4], header.Flags) // packed 8+8+1+4 bytes
  238. binary.LittleEndian.PutUint32(packed_buffer[29:29+4], LEVIN_PROTOCOL_VER_1) // packed 8+8+1+4 bytes
  239. return packed_buffer, len(packed_buffer)
  240. }
  241. // extract structure info from hardcoded node
  242. func (header *Levin_Header) DeSerialize(packed_buffer []byte) (err error) {
  243. if len(packed_buffer) != 33 {
  244. return fmt.Errorf("Insufficient header bytes")
  245. }
  246. header.Signature = binary.LittleEndian.Uint64(packed_buffer[0:8]) // packed 8 bytes
  247. if header.Signature != LEVIN_SIGNATURE {
  248. return fmt.Errorf("Incorrect Levin Signature")
  249. }
  250. header.CB = binary.LittleEndian.Uint64(packed_buffer[8:16]) // packed 8 + 8 bytes
  251. if packed_buffer[16] == 0 {
  252. header.ReturnData = false // packed 8 + 8 + 1
  253. } else {
  254. header.ReturnData = true // packed 8 + 8 + 1
  255. }
  256. header.Command = binary.LittleEndian.Uint32(packed_buffer[17 : 17+4]) // packed 8+8+1+4 bytes
  257. header.ReturnCode = (int32)(binary.LittleEndian.Uint32(packed_buffer[21 : 21+4])) // packed 8+8+1+4 bytes
  258. header.Flags = binary.LittleEndian.Uint32(packed_buffer[25 : 25+4]) // packed 8+8+1+4 bytes
  259. header.Protocol_Version = binary.LittleEndian.Uint32(packed_buffer[29 : 29+4]) // packed 8+8+1+4 bytes
  260. return nil
  261. }
  262. func (header Levin_Data_Header) Serialize() ([]byte, int) {
  263. var packed_buffer []byte
  264. // if nothing is to be placed
  265. if len(header.Data) == 0 {
  266. packed_buffer = make([]byte, 8+2, 8+2) // 10 bytes minimum heade
  267. binary.LittleEndian.PutUint64(packed_buffer[0:8], LEVIN_SIGNATURE_DATA) // packed 8 bytes
  268. packed_buffer[8] = 1
  269. packed_buffer[9] = 0
  270. return packed_buffer, len(packed_buffer)
  271. }
  272. packed_buffer = make([]byte, 8+2+len(header.Data), 8+2+len(header.Data))
  273. binary.LittleEndian.PutUint64(packed_buffer[0:8], LEVIN_SIGNATURE_DATA) // packed 8 bytes
  274. packed_buffer[8] = 1
  275. packed_buffer[9] = 8
  276. copy(packed_buffer[10:], header.Data)
  277. return packed_buffer, len(packed_buffer)
  278. }
  279. // extract structure info from hardcoded node
  280. func (header *Levin_Data_Header) DeSerialize(packed_buffer []byte) (err error) {
  281. if len(packed_buffer) < 10 {
  282. return fmt.Errorf("Insufficient header bytes")
  283. }
  284. header.Signature = binary.LittleEndian.Uint64(packed_buffer[0:8]) // packed 8 bytes
  285. if header.Signature != LEVIN_SIGNATURE_DATA {
  286. return fmt.Errorf("WRONG LEVIN_SIGNATURE_DATA")
  287. }
  288. if len(packed_buffer)-8 == 2 {
  289. return nil
  290. }
  291. header.Data = make([]byte, len(packed_buffer)-8+2, len(packed_buffer)-8+2)
  292. // ignore 2 bytes
  293. // packed_buffer[8]=1 // version
  294. // packed_buffer[9]=8 // boost 8 , this can be anything as per boost level
  295. copy(header.Data, packed_buffer[10:])
  296. return nil
  297. }
  298. func DeSerializeLevinHeader(packed_buffer []byte, header *Levin_Header) error {
  299. if len(packed_buffer) != 33 {
  300. return fmt.Errorf("Insufficient header bytes")
  301. }
  302. header.Signature = binary.LittleEndian.Uint64(packed_buffer[0:8]) // packed 8 bytes
  303. header.CB = binary.LittleEndian.Uint64(packed_buffer[8:16]) // packed 8 + 8 bytes
  304. if packed_buffer[16] == 0 {
  305. header.ReturnData = false // packed 8 + 8 + 1
  306. } else {
  307. header.ReturnData = true // packed 8 + 8 + 1
  308. }
  309. header.Command = binary.LittleEndian.Uint32(packed_buffer[17 : 17+4]) // packed 8+8+1+4 bytes
  310. header.ReturnCode = (int32)(binary.LittleEndian.Uint32(packed_buffer[21 : 21+4])) // packed 8+8+1+4 bytes
  311. header.Flags = binary.LittleEndian.Uint32(packed_buffer[25 : 25+4]) // packed 8+8+1+4 bytes
  312. header.Protocol_Version = binary.LittleEndian.Uint32(packed_buffer[29 : 29+4]) // packed 8+8+1+4 bytes
  313. return nil
  314. }
  315. func TestSerializeDeserialize(t *testing.T) {
  316. }