├── .gitattributes ├── ReadMe.txt └── p2pChat ├── .project ├── bin └── test.txt └── src ├── c1.txt ├── c2.txt ├── node.go ├── otherExamples ├── Server.go └── client.go ├── s.txt ├── s3guest@10.227.80.240 └── s3guest@110.227.80.244 /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /ReadMe.txt: -------------------------------------------------------------------------------- 1 | This project will implement a Peer-to-Peer command-line chat in Go language. 2 | 3 | March 2013 -------------------------------------------------------------------------------- /p2pChat/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | p2pChat 4 | 5 | 6 | 7 | 8 | 9 | com.googlecode.goclipse.goBuilder 10 | 11 | 12 | 13 | 14 | 15 | goclipse.goNature 16 | 17 | 18 | -------------------------------------------------------------------------------- /p2pChat/bin/test.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mshahriarinia/Golang/ddbae4d48d3630e457afa69ba03ea87c9445be9b/p2pChat/bin/test.txt -------------------------------------------------------------------------------- /p2pChat/src/c1.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | Welcome to Peer-to-Peer (P2P) Command-Line Chat in Go language. 4 | 5 | 6 | Run this node as main server? (y/n) Node is a normal p2p node. 7 | New node: 127.0.0.1:5555 8 | Server Socket: 127.0.0.1:5555 9 | port isSSSSSS: 5555 10 | found connection. 11 | setted port to 5555 12 | found connection. 13 | Local Socket: 192.168.0.103:9639 14 | --------------------------------------------------------- 15 | Error connecting to: dial tcp: missing address 16 | 17 | Connection List: [127.0.0.1:5555] 18 | 127.0.0.1:5555 says: :!q 5555 19 | user@Home[\ New node: 127.0.0.1:60105 20 | port isSSSSSS: 6506 21 | found connection. 22 | setted port to 6506 23 | found connection. 24 | 25 | Connection List: [127.0.0.1:5555 127.0.0.1:6506] 26 | 127.0.0.1:60105 says: :!q 6506 127.0.0.1:5555 27 | Error in reading from connection 127.0.0.1:5555 28 | found connection. 29 | Closing 127.0.0.1:5555 30 | user@Home[\ -------------------------------------------------------------------------------- /p2pChat/src/c2.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | Welcome to Peer-to-Peer (P2P) Command-Line Chat in Go language. 4 | 5 | 6 | Run this node as main server? (y/n) Can not read from command line. 7 | -------------------------------------------------------------------------------- /p2pChat/src/node.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | /** 4 | This project will implement a Peer-to-Peer command-line chat in Go language. in one control 5 | message only send the actual ipport combination of other peers and let others know 6 | about other peers. One node can be the server (default port of connection for all nodes) 7 | but once nodes connect the peer-to-peer chat works even with the server being taken down 8 | or any of the other nodes being taken down. 9 | 10 | Go version: go1.0.3 11 | 12 | @March 2013 13 | @by Morteza Shahriari Nia @mshahriarinia 14 | 15 | 16 | Reading arbitrary strings from command-line was a bit trickey as I couldn't get a straight-forward example 17 | on telling how to do it. But after visiting tens of pages and blogs it was fixed. Buffers, buffered reader, 18 | streams, ... The diffference between when you learn something and when you actually do it. 19 | 20 | Multi-threading communciation via channels is very useful but not in our context. We need Mutex 21 | for handling our clients which is not straightforward or natural in channels and message streams. 22 | 23 | The last time consuming issue was the matter of pointers and how to differnetiate 24 | between pass by reference/value. I could not find a good resource online explaining this 25 | and had to hack through 26 | 27 | Debugging without a debugger was a killer but ended up being ok. 28 | */ 29 | 30 | import ( 31 | "bufio" 32 | "fmt" 33 | "math/rand" 34 | "net" 35 | "os" 36 | "runtime" 37 | "strconv" 38 | "strings" 39 | // "strings" 40 | "container/list" 41 | "sync" 42 | "time" 43 | ) 44 | 45 | var ( 46 | port string 47 | SERVER_IP = "10.136.45.240" //TODO fix server ip 48 | SERVER_PORT string = "5555" //default port as the main p2p server 49 | stop = false 50 | mutexPeerList sync.Mutex 51 | CONTROL_MESSAGE_PREAMBLE = "\u001B" + ":!q" //char code used in VIM to exit the program 52 | ) 53 | 54 | type Peer struct { 55 | conn net.Conn 56 | port string 57 | ip string 58 | } 59 | 60 | func main() { 61 | //initialize values 62 | reader := bufio.NewReader(os.Stdin) //read line from standard input 63 | peerList := list.New() //list of p2p chat users. 64 | 65 | fmt.Println("\n\n Welcome to Peer-to-Peer (P2P) Command-Line Chat in Go language.\n\n") 66 | fmt.Print("Run this node as main server? (y/n) ") 67 | 68 | str, err := reader.ReadString('\n') //ignore the error by sending it to nil 69 | if err != nil { 70 | fmt.Println("Can not read from command line.") 71 | os.Exit(1) 72 | } 73 | 74 | if []byte(str)[0] == 'y' { 75 | fmt.Println("Node is the main p2p server.") 76 | port = SERVER_PORT 77 | } else if []byte(str)[0] == 'n' { 78 | fmt.Println("Node is a normal p2p node.") 79 | port = generatePortNo() 80 | connectToIpPort(SERVER_IP+":"+SERVER_PORT, peerList) 81 | } else { 82 | fmt.Println("Wrong argument type.") 83 | os.Exit(1) 84 | } 85 | 86 | fmt.Println("Server Socket: " + SERVER_IP + ":" + SERVER_PORT) 87 | localIp := getLocalIP() 88 | fmt.Println(" Local Socket: " + localIp[0] + ":" + port) 89 | fmt.Println("---------------------------------------------------------") 90 | 91 | go acceptPeers(port, peerList) 92 | go chatSay(peerList) 93 | 94 | runtime.Gosched() //let the new thread to start, otherwuse it will not execute. 95 | 96 | //it's good to not include accepting new clients from main just in case the user 97 | //wants to quit by typing some keywords, the main thread is not stuck at 98 | // net.listen.accept forever 99 | for !stop { 100 | time.Sleep(1000 * time.Millisecond) 101 | } //keep main thread alive 102 | } 103 | 104 | /** 105 | When a peer receives a control message consisting of its list of peers, other peers 106 | connect to that list one by one. list in this message is a string of ipport combinations 107 | */ 108 | func connectToPeers(peer Peer, controlMessage string, peerList *list.List) { 109 | strArr := strings.Split(controlMessage, " ") 110 | for i, ipport := range strArr { 111 | if i == 0 { 112 | //skip preamble 113 | } else if i ==1 { //set actual port for the peer sending this message 114 | peer.port = ipport 115 | }else if !isSelf(ipport) { //skip preamble 116 | connectToIpPort(ipport, peerList) 117 | } 118 | } 119 | } 120 | 121 | /** 122 | ask for a connection from a node via ipport 123 | */ 124 | func connectToIpPort(ipport string, peerList *list.List) { 125 | if strings.Contains(ipport, "nil"){ 126 | return 127 | } 128 | if len(strings.Trim(ipport, " ")) == 0{ 129 | return 130 | } 131 | 132 | if isAlreadyconnected(ipport, peerList){ 133 | return 134 | } 135 | 136 | mutexPeerList.Lock() 137 | conn, err := net.Dial("tcp", ipport) 138 | if err != nil { 139 | fmt.Println("Error connecting to:", ipport, err.Error()) 140 | mutexPeerList.Unlock() 141 | return 142 | 143 | } 144 | peer := &Peer{conn, "nilport", getIP(conn)} 145 | 146 | //peerList.PushBack(peer) 147 | addToList(*peer, peerList) 148 | mutexPeerList.Unlock() 149 | 150 | go handlePeer(peer, peerList) 151 | runtime.Gosched() 152 | } 153 | 154 | 155 | /** 156 | read access to channel list 157 | */ 158 | func chatSay(peerList *list.List) { 159 | reader := bufio.NewReader(os.Stdin) //get teh reader to read lines from standard input 160 | 161 | //conn, err := net.Dial("tcp", serverIP+":"+SERVER_PORT) 162 | 163 | for !stop { //keep reading inputs forever 164 | fmt.Print("user@Home[\\ ") 165 | str, _ := reader.ReadString('\n') 166 | 167 | mutexPeerList.Lock() 168 | for e := peerList.Front(); e != nil; e = e.Next() { 169 | conn := e.Value.(*Peer).conn 170 | _, err := conn.Write([]byte(str)) //transmit string as byte array 171 | if err != nil { 172 | fmt.Println("Error sending reply:", err.Error()) 173 | } 174 | } 175 | mutexPeerList.Unlock() 176 | } 177 | } 178 | 179 | /** 180 | Accept new clients. 181 | */ 182 | func acceptPeers(port string, peerList *list.List) { 183 | //fmt.Println("Listenning to port", port) 184 | ln, err := net.Listen("tcp", ":"+port) 185 | if err != nil { 186 | fmt.Println("Error listenning to port ", port) 187 | stop = true 188 | } 189 | for !stop { 190 | conn, err := ln.Accept() 191 | if err != nil { 192 | fmt.Println("Error in accepting connection.") 193 | stop = true 194 | continue 195 | } 196 | 197 | mutexPeerList.Lock() 198 | peer := &Peer{conn, "nilport", getIP(conn)} 199 | peerList.PushBack(peer) 200 | mutexPeerList.Unlock() 201 | 202 | go handlePeer(peer, peerList) 203 | runtime.Gosched() 204 | } 205 | } 206 | 207 | /** 208 | Receive message from client. 209 | Listen and wait for content from client. the write to 210 | client will be performed when the current user enters an input 211 | */ 212 | func handlePeer(peer *Peer, peerList *list.List) { 213 | stopConn := false 214 | fmt.Println("New node: ", peer.conn.RemoteAddr()) 215 | 216 | 217 | //send current peer list 218 | str := peerListToStr(peerList) 219 | _, err := peer.conn.Write([]byte(CONTROL_MESSAGE_PREAMBLE + " " + port + " " + str)) //transmit string as byte array 220 | if err != nil { 221 | fmt.Println("Error sending reply:", err.Error()) 222 | } 223 | 224 | //Listen for the peer messages 225 | buffer := make([]byte, 1024) 226 | 227 | for !stopConn { 228 | bytesRead, err := peer.conn.Read(buffer) 229 | if err != nil { //stop for loop, remove peer from list 230 | 231 | stopConn = true 232 | fmt.Println("Error in reading from connection", peer.conn.RemoteAddr()) 233 | mutexPeerList.Lock() 234 | el := getListElement(*peer, peerList) 235 | if el != nil { 236 | peerList.Remove(el) 237 | } 238 | mutexPeerList.Unlock() 239 | 240 | } else { 241 | messageStr := string(buffer[0:bytesRead]) 242 | 243 | 244 | 245 | if strings.Contains(messageStr, CONTROL_MESSAGE_PREAMBLE) { 246 | //pass peer itself to set actual port 247 | sArr := strings.Split(messageStr, " ") 248 | fmt.Println("port isSSSSSS: ", sArr[1]) 249 | 250 | 251 | el := getListElement(*peer, peerList) 252 | if el != nil { 253 | p := el.Value.(*Peer) 254 | p.port = sArr[1] 255 | //peer.port = sArr[1] 256 | fmt.Println("setted port to", p.port) 257 | setPort(*peer, peerList, sArr[1]) 258 | 259 | connectToPeers(*peer, messageStr, peerList) 260 | printlist(peerList) 261 | } 262 | fmt.Println(peer.ipport(), " says: ", messageStr) 263 | }else{ 264 | printlist(peerList) 265 | fmt.Println(peer.ipport(), " says: ", messageStr) 266 | } 267 | } 268 | } 269 | fmt.Println("Closing ", peer.conn.RemoteAddr()) 270 | peer.conn.Close() 271 | } 272 | 273 | /** 274 | When the peer sends the port of its TCP listener for new peers we need to set 275 | it in our Peer struct and later on use it for forwarding this port to other peers 276 | */ 277 | func setPort(peer Peer, l *list.List, port string) *list.Element { 278 | for e := l.Front(); e != nil; e = e.Next() { 279 | temp := e.Value.(*Peer) 280 | 281 | if peer.conn.RemoteAddr() == temp.conn.RemoteAddr() { 282 | fmt.Println("found connection.") 283 | temp.port = port 284 | return e 285 | } 286 | } 287 | return nil 288 | } 289 | 290 | /** 291 | return the element of the list that represents the same peer as the arguemnt 292 | */ 293 | func getListElement(peer Peer, l *list.List) *list.Element { 294 | for e := l.Front(); e != nil; e = e.Next() { 295 | temp := e.Value.(*Peer) 296 | 297 | if peer.conn.RemoteAddr() == temp.conn.RemoteAddr() { 298 | fmt.Println("found connection.") 299 | return e 300 | } 301 | } 302 | return nil 303 | } 304 | 305 | 306 | 307 | /** 308 | Avoid adding redundant peers to list, shall be already locked by mutex 309 | */ 310 | func addToList(peer Peer, l *list.List) { 311 | if ! isAlreadyconnected(peer.ipport(), l){ 312 | l.PushBack(&peer) 313 | } 314 | return 315 | } 316 | 317 | /** 318 | check if the ipport combination is already being conneted to 319 | */ 320 | func isAlreadyconnected(ipport string, l *list.List)bool{ 321 | for e := l.Front(); e != nil; e = e.Next() { 322 | temp := e.Value.(*Peer) 323 | if ipport == temp.ipport() { 324 | return true 325 | } 326 | } 327 | return false 328 | } 329 | 330 | 331 | /** 332 | Get a string of the peer list as ip:port 333 | */ 334 | func peerListToStr(l *list.List) string { 335 | if l == nil { 336 | return "" 337 | } 338 | s := "" 339 | mutexPeerList.Lock() 340 | for e := l.Front(); e != nil; e = e.Next() { 341 | peer := e.Value.(*Peer) 342 | if peer.port != "nilport"{ 343 | s = s + peer.ip + ":" + peer.port + " " 344 | } 345 | } 346 | //s = s + getLocalIP()[0] + ":" + port 347 | mutexPeerList.Unlock() 348 | return strings.Trim(s, " ") 349 | } 350 | 351 | /** 352 | print ipport combination of the current peer list 353 | */ 354 | func printlist(l *list.List) { 355 | fmt.Print("\nPeer List: [") 356 | fmt.Print(peerListToStr(l)) 357 | fmt.Println("]") 358 | } 359 | 360 | /** 361 | struct function to return the ipport combination to be used for comparisons 362 | */ 363 | func (p *Peer) ipport() string{ 364 | return p.ip + ":" + p.port 365 | } 366 | 367 | /** 368 | Checks to see if the ipport combination is the current node itself. 369 | */ 370 | func isSelf(ipport string) bool { 371 | ipArr := getLocalIP() 372 | 373 | for _, ip := range ipArr { 374 | if ipport == ip+":"+port { 375 | return true 376 | } 377 | } 378 | if ipport == "127.0.0.1"+":"+port || ipport == "localhost"+":"+port { 379 | return true 380 | } 381 | return false 382 | } 383 | 384 | /** 385 | Generate a port number 386 | */ 387 | func generatePortNo() string { 388 | rand.Seed(time.Now().Unix()) 389 | return strconv.Itoa(rand.Intn(5000) + 5000) //generate a valid port 390 | } 391 | 392 | /** 393 | return the ip address of a tcp connection 394 | */ 395 | func getIP(conn net.Conn) string{ 396 | s := conn.RemoteAddr().String() 397 | s = strings.Split(s, ":")[0] 398 | s = strings.Trim(s, ":") 399 | return s 400 | } 401 | 402 | 403 | /** 404 | Determine the local IP addresses 405 | */ 406 | func getLocalIP() []string { 407 | name, err := os.Hostname() 408 | if err != nil { 409 | fmt.Printf("Oops: %v\n", err) 410 | return []string{} 411 | } 412 | //fmt.Print("Local Hostname: " + name) 413 | 414 | addrs, err := net.LookupHost(name) 415 | if err != nil { 416 | fmt.Printf("Oops: %v\n", err) 417 | return []string{} 418 | } 419 | // fmt.Print("\t\tLocal IP Addresses: ", addrs) 420 | 421 | return addrs 422 | } 423 | -------------------------------------------------------------------------------- /p2pChat/src/otherExamples/Server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt"; 5 | "net"; 6 | "log"; 7 | "os"; 8 | "container/list"; 9 | "strings"; 10 | "bytes"; 11 | "flag"; 12 | ) 13 | 14 | // flag for debuging info. or a simple log 15 | var debug = flag.Bool("d", false, "set the debug modus( print informations )") 16 | 17 | type ClientChat struct { 18 | Name string; // name of user 19 | IN chan string; // input channel for to send to user 20 | OUT chan string; // input channel from user to all 21 | Con *net.Conn; // connection of client 22 | Quit chan bool; // quit channel for all goroutines 23 | ListChain *list.List; // reference to list 24 | } 25 | 26 | // read from connection and return true if ok 27 | func (c *ClientChat) Read(buf []byte) bool{ 28 | nr, err := c.Con.Read(buf); 29 | if err!=nil { 30 | c.Close(); 31 | return false; 32 | } 33 | Log("Read(): ", nr, " bytes"); 34 | return true; 35 | } 36 | 37 | // close the connection and send quit to sender 38 | func (c *ClientChat) Close() { 39 | c.Quit<-true; 40 | c.Con.Close(); 41 | c.deleteFromList(); 42 | } 43 | 44 | // compare two clients: name and network connection 45 | func (c *ClientChat) Equal(cl *ClientChat) bool { 46 | if bytes.Equal(strings.Bytes(c.Name), strings.Bytes(cl.Name)) { 47 | if c.Con == cl.Con { 48 | return true; 49 | } 50 | } 51 | return false; 52 | } 53 | 54 | // delete the client from list 55 | func (c *ClientChat) deleteFromList() { 56 | for e := c.ListChain.Front(); e != nil; e = e.Next() { 57 | client := e.Value.(ClientChat); 58 | if c.Equal(&client) { 59 | Log("deleteFromList(): ", c.Name); 60 | c.ListChain.Remove(e); 61 | } 62 | } 63 | } 64 | 65 | // func Log(v ...): loging. give log information if debug is true 66 | func Log(v ...interface{}) { 67 | if *debug == true { 68 | ret := fmt.Sprint(v); 69 | log.Stdoutf("SERVER: %s", ret); 70 | } 71 | } 72 | 73 | // func test(): testing for error 74 | func test(err os.Error, mesg string) { 75 | if err!=nil { 76 | log.Stderr("SERVER: ERROR: ", mesg); 77 | os.Exit(-1); 78 | } else{ 79 | Log("Ok: ", mesg) 80 | } 81 | } 82 | 83 | // handlingINOUT(): handle inputs from client, and send it to all other client via channels. 84 | func handlingINOUT(IN <-chan string, lst *list.List) { 85 | for { 86 | Log("handlingINOUT(): wait for input"); 87 | input := <-IN; // input, get from client 88 | // send to all client back 89 | Log("handlingINOUT(): handling input: ", input); 90 | for value := range lst.Iter() { 91 | client := value.(ClientChat); 92 | Log("handlingINOUT(): send to client: ", client.Name); 93 | client.IN<- input; 94 | } 95 | } 96 | } 97 | 98 | 99 | 100 | // clientreceiver wait for an input from network, after geting data it send to 101 | // handlingINOUT via a channel. 102 | func clientreceiver(client *ClientChat) { 103 | buf := make([]byte, 2048); 104 | 105 | Log("clientreceiver(): start for: ", client.Name); 106 | for client.Read(buf) { 107 | 108 | if bytes.Equal(buf, strings.Bytes("/quit")) { 109 | client.Close(); 110 | break; 111 | } 112 | Log("clientreceiver(): received from ",client.Name, " (", string(buf), ")"); 113 | send := client.Name+"> "+string(buf); 114 | client.OUT<- send; 115 | for i:=0; i<2048;i++ { 116 | buf[i]=0x00; 117 | } 118 | } 119 | 120 | client.OUT <- client.Name+" has left chat"; 121 | Log("clientreceiver(): stop for: ", client.Name); 122 | } 123 | 124 | // clientsender(): get the data from handlingINOUT via channel (or quit signal from 125 | // clientreceiver) and send it via network 126 | func clientsender(client *ClientChat) { 127 | Log("clientsender(): start for: ", client.Name); 128 | for { 129 | Log("clientsender(): wait for input to send"); 130 | select { 131 | case buf := <- client.IN: 132 | Log("clientsender(): send to \"", client.Name, "\": ", string(buf)); 133 | client.Con.Write(strings.Bytes(buf)); 134 | case <-client.Quit: 135 | Log("clientsender(): client want to quit"); 136 | client.Con.Close(); 137 | break; 138 | } 139 | } 140 | Log("clientsender(): stop for: ", client.Name); 141 | } 142 | 143 | // clientHandling(): get the username and create the clientsturct 144 | // start the clientsender/receiver, add client to list. 145 | func clientHandling(con *net.Conn, ch chan string, lst *list.List) { 146 | buf := make([]byte, 1024); 147 | con.Read(buf); 148 | name := string(buf); 149 | newclient := &ClientChat{name, make(chan string), ch, con, make(chan bool), lst}; 150 | 151 | Log("clientHandling(): for ", name); 152 | go clientsender(newclient); 153 | go clientreceiver(newclient); 154 | lst.PushBack(*newclient); 155 | ch<- name+" has joinet the chat"; 156 | } 157 | 158 | func main() { 159 | flag.Parse(); 160 | Log("main(): start"); 161 | 162 | // create the list of clients 163 | clientlist := list.New(); 164 | in := make(chan string); 165 | Log("main(): start handlingINOUT()"); 166 | go handlingINOUT(in, clientlist); 167 | 168 | // create the connection 169 | netlisten, err := net.Listen("tcp", "127.0.0.1:9988"); 170 | test(err, "main Listen"); 171 | defer netlisten.Close(); 172 | 173 | for { 174 | // wait for clients 175 | Log("main(): wait for client ..."); 176 | conn, err := netlisten.Accept(); 177 | test(err, "main: Accept for client"); 178 | go clientHandling(&conn, in, clientlist); 179 | } 180 | } -------------------------------------------------------------------------------- /p2pChat/src/otherExamples/client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt"; 5 | "net"; 6 | "log"; 7 | "os"; 8 | "bytes"; 9 | "bufio"; 10 | "strings"; 11 | "time"; 12 | "flag"; 13 | ) 14 | 15 | var running bool; // global variable if client is running 16 | 17 | var debug = flag.Bool("d", false, "set the debug modus( print informations )") 18 | 19 | // func Log(v ...): loging. give log information if debug is true 20 | func Log(v ...) { 21 | if *debug == true { 22 | ret := fmt.Sprint(v); 23 | log.Stdoutf("CLIENT: %s", ret); 24 | } 25 | } 26 | 27 | // func test(): testing for error 28 | func test(err os.Error, mesg string) { 29 | if err!=nil { 30 | log.Stderr("CLIENT: ERROR: ", mesg); 31 | os.Exit(-1); 32 | } else 33 | Log("Ok: ", mesg); 34 | } 35 | 36 | // read from connection and return true if ok 37 | func Read(con *net.Conn) string{ 38 | var buf [4048]byte; /////////////////////// 39 | _, err := con.Read(&buf); /////////////////////// 40 | if err!=nil { 41 | con.Close(); 42 | running=false; 43 | return "Error in reading!"; 44 | } 45 | str := string(&buf); /////////////////////// 46 | fmt.Println(); 47 | return string(str); 48 | } 49 | 50 | // clientsender(): read from stdin and send it via network 51 | func clientsender(cn *net.Conn) { 52 | reader := bufio.NewReader(os.Stdin); 53 | for { 54 | fmt.Print("you> "); 55 | input, _ := reader.ReadBytes('\n'); 56 | if bytes.Equal(input, strings.Bytes("/quit\n")) { 57 | cn.Write(strings.Bytes("/quit")); 58 | running = false; 59 | break; 60 | } 61 | Log("clientsender(): send: ", string(input[0:len(input)-1])); 62 | cn.Write(input[0:len(input)-1]);///////////////////////// 63 | } 64 | } 65 | 66 | // clientreceiver(): wait for input from network and print it out 67 | func clientreceiver(cn *net.Conn) { 68 | for running {/////////////////////////////// 69 | fmt.Println(Read(cn)); 70 | fmt.Print("you> "); 71 | } 72 | } 73 | 74 | func main() { 75 | flag.Parse(); 76 | running = true; 77 | Log("main(): start "); 78 | 79 | // connect 80 | destination := "127.0.0.1:9988"; 81 | Log("main(): connecto to ", destination); 82 | cn, err := net.Dial("tcp", "", destination); 83 | test(err, "dialing"); 84 | defer cn.Close(); 85 | Log("main(): connected "); 86 | 87 | // get the user name 88 | fmt.Print("Please give you name: "); 89 | reader := bufio.NewReader(os.Stdin); 90 | name, _ := reader.ReadBytes('\n'); 91 | 92 | //cn.Write(strings.Bytes("User: ")); 93 | cn.Write(name[0:len(name)-1]); 94 | 95 | // start receiver and sender 96 | Log("main(): start receiver"); 97 | go clientreceiver(&cn); 98 | Log("main(): start sender"); 99 | go clientsender(&cn); 100 | 101 | // wait for quiting (/quit). run until running is true 102 | for ;running; { 103 | time.Sleep(1*1e9); 104 | } 105 | Log("main(): stoped"); 106 | } 107 | -------------------------------------------------------------------------------- /p2pChat/src/s.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | Welcome to Peer-to-Peer (P2P) Command-Line Chat in Go language. 4 | 5 | 6 | Run this node as main server? (y/n) Node is the main p2p server. 7 | Server Socket: 127.0.0.1:5555 8 | Local Socket: 192.168.0.103:5555 9 | --------------------------------------------------------- 10 | user@Home[\ New node: 127.0.0.1:60096 11 | port isSSSSSS: 9639 12 | found connection. 13 | setted port to 9639 14 | found connection. 15 | Error connecting to: dial tcp: missing address 16 | 17 | Connection List: [127.0.0.1:9639] 18 | 127.0.0.1:60096 says: :!q 9639 19 | New node: 127.0.0.1:60104 20 | port isSSSSSS: 6506 21 | found connection. 22 | setted port to 6506 23 | found connection. 24 | Error connecting to: dial tcp: missing address 25 | 26 | Connection List: [127.0.0.1:9639 127.0.0.1:6506] 27 | 127.0.0.1:60104 says: :!q 6506 28 | -------------------------------------------------------------------------------- /p2pChat/src/s3guest@10.227.80.240: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | /** 4 | This project will implement a Peer-to-Peer command-line chat in Go language. in one control 5 | message only send the actual ipport combination of other peers and let others know 6 | about other peers. One node can be the server (default port of connection for all nodes) 7 | but once nodes connect the peer-to-peer chat works even with the server being taken down 8 | or any of the other nodes being taken down. 9 | 10 | Go version: go1.0.3 11 | 12 | @March 2013 13 | @by Morteza Shahriari Nia @mshahriarinia 14 | 15 | 16 | Reading arbitrary strings from command-line was a bit trickey as I couldn't get a straight-forward example 17 | on telling how to do it. But after visiting tens of pages and blogs it was fixed. Buffers, buffered reader, 18 | streams, ... The diffference between when you learn womething and when you actually do it. 19 | 20 | Multi-threading communciation via channels is very useful but not in our context. We need Mutex 21 | for handling our clients which is not straightforward or natural in channels and message streams. 22 | 23 | The last time consuming issue was the matter of pointers and how to differnetiate 24 | between pass by reference/value. I could not find a good resource online explaining this 25 | and had to hack through 26 | 27 | Debugging without a debugger was a killer but ended up being ok. 28 | */ 29 | 30 | import ( 31 | "bufio" 32 | "fmt" 33 | "math/rand" 34 | "net" 35 | "os" 36 | "runtime" 37 | "strconv" 38 | "strings" 39 | // "strings" 40 | "container/list" 41 | "sync" 42 | "time" 43 | ) 44 | 45 | var ( 46 | port string 47 | SERVER_IP = "127.0.0.1" //TODO fix server ip 48 | SERVER_PORT string = "5555" //default port as the main p2p server 49 | stop = false 50 | mutexPeerList sync.Mutex 51 | CONTROL_MESSAGE_PREAMBLE = "\u001B" + ":!q" //char code used in VIM to exit the program 52 | ) 53 | 54 | type Peer struct { 55 | conn net.Conn 56 | port string 57 | ip string 58 | } 59 | 60 | func main() { 61 | //initialize values 62 | reader := bufio.NewReader(os.Stdin) //read line from standard input 63 | peerList := list.New() //list of p2p chat users. 64 | 65 | fmt.Println("\n\n Welcome to Peer-to-Peer (P2P) Command-Line Chat in Go language.\n\n") 66 | fmt.Print("Run this node as main server? (y/n) ") 67 | 68 | str, err := reader.ReadString('\n') //ignore the error by sending it to nil 69 | if err != nil { 70 | fmt.Println("Can not read from command line.") 71 | os.Exit(1) 72 | } 73 | 74 | if []byte(str)[0] == 'y' { 75 | fmt.Println("Node is the main p2p server.") 76 | port = SERVER_PORT 77 | } else if []byte(str)[0] == 'n' { 78 | fmt.Println("Node is a normal p2p node.") 79 | port = generatePortNo() 80 | connectToIpPort(SERVER_IP+":"+SERVER_PORT, peerList) 81 | } else { 82 | fmt.Println("Wrong argument type.") 83 | os.Exit(1) 84 | } 85 | 86 | fmt.Println("Server Socket: " + SERVER_IP + ":" + SERVER_PORT) 87 | localIp := getLocalIP() 88 | fmt.Println(" Local Socket: " + localIp[0] + ":" + port) 89 | fmt.Println("---------------------------------------------------------") 90 | 91 | go acceptPeers(port, peerList) 92 | go chatSay(peerList) 93 | 94 | runtime.Gosched() //let the new thread to start, otherwuse it will not execute. 95 | 96 | //it's good to not include accepting new clients from main just in case the user 97 | //wants to quit by typing some keywords, the main thread is not stuck at 98 | // net.listen.accept forever 99 | for !stop { 100 | time.Sleep(1000 * time.Millisecond) 101 | } //keep main thread alive 102 | } 103 | 104 | /** 105 | When a peer receives a control message consisting of its list of peers, other peers 106 | connect to that list one by one. list in this message is a string of ipport combinations 107 | */ 108 | func connectToPeers(peer Peer, controlMessage string, peerList *list.List) { 109 | strArr := strings.Split(controlMessage, " ") 110 | for i, ipport := range strArr { 111 | if i == 0 { 112 | //skip preamble 113 | } else if i ==1 { //set actual port for the peer sending this message 114 | peer.port = ipport 115 | }else if !isSelf(ipport) { //skip preamble 116 | connectToIpPort(ipport, peerList) 117 | } 118 | } 119 | } 120 | 121 | /** 122 | ask for a connection from a node via ipport 123 | */ 124 | func connectToIpPort(ipport string, peerList *list.List) { 125 | if strings.Contains(ipport, "nil"){ 126 | return 127 | } 128 | if len(strings.Trim(ipport, " ")) == 0{ 129 | return 130 | } 131 | 132 | if isAlreadyconnected(ipport, peerList){ 133 | return 134 | } 135 | 136 | mutexPeerList.Lock() 137 | conn, err := net.Dial("tcp", ipport) 138 | if err != nil { 139 | fmt.Println("Error connecting to:", ipport, err.Error()) 140 | mutexPeerList.Unlock() 141 | return 142 | 143 | } 144 | peer := &Peer{conn, "nilport", getIP(conn)} 145 | 146 | //peerList.PushBack(peer) 147 | addToList(*peer, peerList) 148 | mutexPeerList.Unlock() 149 | 150 | go handlePeer(peer, peerList) 151 | runtime.Gosched() 152 | } 153 | 154 | 155 | /** 156 | read access to channel list 157 | */ 158 | func chatSay(peerList *list.List) { 159 | reader := bufio.NewReader(os.Stdin) //get teh reader to read lines from standard input 160 | 161 | //conn, err := net.Dial("tcp", serverIP+":"+SERVER_PORT) 162 | 163 | for !stop { //keep reading inputs forever 164 | fmt.Print("user@Home[\\ ") 165 | str, _ := reader.ReadString('\n') 166 | 167 | mutexPeerList.Lock() 168 | for e := peerList.Front(); e != nil; e = e.Next() { 169 | conn := e.Value.(*Peer).conn 170 | _, err := conn.Write([]byte(str)) //transmit string as byte array 171 | if err != nil { 172 | fmt.Println("Error sending reply:", err.Error()) 173 | } 174 | } 175 | mutexPeerList.Unlock() 176 | } 177 | } 178 | 179 | /** 180 | Accept new clients. 181 | */ 182 | func acceptPeers(port string, peerList *list.List) { 183 | //fmt.Println("Listenning to port", port) 184 | ln, err := net.Listen("tcp", ":"+port) 185 | if err != nil { 186 | fmt.Println("Error listenning to port ", port) 187 | stop = true 188 | } 189 | for !stop { 190 | conn, err := ln.Accept() 191 | if err != nil { 192 | fmt.Println("Error in accepting connection.") 193 | stop = true 194 | continue 195 | } 196 | 197 | mutexPeerList.Lock() 198 | peer := &Peer{conn, "nilport", getIP(conn)} 199 | peerList.PushBack(peer) 200 | mutexPeerList.Unlock() 201 | 202 | go handlePeer(peer, peerList) 203 | runtime.Gosched() 204 | } 205 | } 206 | 207 | /** 208 | Receive message from client. 209 | Listen and wait for content from client. the write to 210 | client will be performed when the current user enters an input 211 | */ 212 | func handlePeer(peer *Peer, peerList *list.List) { 213 | stopConn := false 214 | fmt.Println("New node: ", peer.conn.RemoteAddr()) 215 | 216 | 217 | //send current peer list 218 | str := peerListToStr(peerList) 219 | _, err := peer.conn.Write([]byte(CONTROL_MESSAGE_PREAMBLE + " " + port + " " + str)) //transmit string as byte array 220 | if err != nil { 221 | fmt.Println("Error sending reply:", err.Error()) 222 | } 223 | 224 | //Listen for the peer messages 225 | buffer := make([]byte, 1024) 226 | 227 | for !stopConn { 228 | bytesRead, err := peer.conn.Read(buffer) 229 | if err != nil { //stop for loop, remove peer from list 230 | 231 | stopConn = true 232 | fmt.Println("Error in reading from connection", peer.conn.RemoteAddr()) 233 | mutexPeerList.Lock() 234 | el := getListElement(*peer, peerList) 235 | if el != nil { 236 | peerList.Remove(el) 237 | } 238 | mutexPeerList.Unlock() 239 | 240 | } else { 241 | messageStr := string(buffer[0:bytesRead]) 242 | 243 | 244 | 245 | if strings.Contains(messageStr, CONTROL_MESSAGE_PREAMBLE) { 246 | //pass peer itself to set actual port 247 | sArr := strings.Split(messageStr, " ") 248 | fmt.Println("port isSSSSSS: ", sArr[1]) 249 | 250 | 251 | el := getListElement(*peer, peerList) 252 | if el != nil { 253 | p := el.Value.(*Peer) 254 | p.port = sArr[1] 255 | //peer.port = sArr[1] 256 | fmt.Println("setted port to", p.port) 257 | setPort(*peer, peerList, sArr[1]) 258 | 259 | connectToPeers(*peer, messageStr, peerList) 260 | printlist(peerList) 261 | } 262 | fmt.Println(peer.ipport(), " says: ", messageStr) 263 | }else{ 264 | printlist(peerList) 265 | fmt.Println(peer.ipport(), " says: ", messageStr) 266 | } 267 | } 268 | } 269 | fmt.Println("Closing ", peer.conn.RemoteAddr()) 270 | peer.conn.Close() 271 | } 272 | 273 | /** 274 | When the peer sends the port of its TCP listener for new peers we need to set 275 | it in our Peer struct and later on use it for forwarding this port to other peers 276 | */ 277 | func setPort(peer Peer, l *list.List, port string) *list.Element { 278 | for e := l.Front(); e != nil; e = e.Next() { 279 | temp := e.Value.(*Peer) 280 | 281 | if peer.conn.RemoteAddr() == temp.conn.RemoteAddr() { 282 | fmt.Println("found connection.") 283 | temp.port = port 284 | return e 285 | } 286 | } 287 | return nil 288 | } 289 | 290 | /** 291 | return the element of the list that represents the same peer as the arguemnt 292 | */ 293 | func getListElement(peer Peer, l *list.List) *list.Element { 294 | for e := l.Front(); e != nil; e = e.Next() { 295 | temp := e.Value.(*Peer) 296 | 297 | if peer.conn.RemoteAddr() == temp.conn.RemoteAddr() { 298 | fmt.Println("found connection.") 299 | return e 300 | } 301 | } 302 | return nil 303 | } 304 | 305 | 306 | 307 | /** 308 | Avoid adding redundant peers to list, shall be already locked by mutex 309 | */ 310 | func addToList(peer Peer, l *list.List) { 311 | if ! isAlreadyconnected(peer.ipport(), l){ 312 | l.PushBack(&peer) 313 | } 314 | return 315 | } 316 | 317 | /** 318 | check if the ipport combination is already being conneted to 319 | */ 320 | func isAlreadyconnected(ipport string, l *list.List)bool{ 321 | for e := l.Front(); e != nil; e = e.Next() { 322 | temp := e.Value.(*Peer) 323 | if ipport == temp.ipport() { 324 | return true 325 | } 326 | } 327 | return false 328 | } 329 | 330 | 331 | /** 332 | Get a string of the peer list as ip:port 333 | */ 334 | func peerListToStr(l *list.List) string { 335 | if l == nil { 336 | return "" 337 | } 338 | s := "" 339 | mutexPeerList.Lock() 340 | for e := l.Front(); e != nil; e = e.Next() { 341 | peer := e.Value.(*Peer) 342 | if peer.port != "nilport"{ 343 | s = s + peer.ip + ":" + peer.port + " " 344 | } 345 | } 346 | //s = s + getLocalIP()[0] + ":" + port 347 | mutexPeerList.Unlock() 348 | return strings.Trim(s, " ") 349 | } 350 | 351 | /** 352 | print ipport combination of the current peer list 353 | */ 354 | func printlist(l *list.List) { 355 | fmt.Print("\nPeer List: [") 356 | fmt.Print(peerListToStr(l)) 357 | fmt.Println("]") 358 | } 359 | 360 | /** 361 | struct function to return the ipport combination to be used for comparisons 362 | */ 363 | func (p *Peer) ipport() string{ 364 | return p.ip + ":" + p.port 365 | } 366 | 367 | /** 368 | Checks to see if the ipport combination is the current node itself. 369 | */ 370 | func isSelf(ipport string) bool { 371 | ipArr := getLocalIP() 372 | 373 | for _, ip := range ipArr { 374 | if ipport == ip+":"+port { 375 | return true 376 | } 377 | } 378 | if ipport == "127.0.0.1"+":"+port || ipport == "localhost"+":"+port { 379 | return true 380 | } 381 | return false 382 | } 383 | 384 | /** 385 | Generate a port number 386 | */ 387 | func generatePortNo() string { 388 | rand.Seed(time.Now().Unix()) 389 | return strconv.Itoa(rand.Intn(5000) + 5000) //generate a valid port 390 | } 391 | 392 | /** 393 | return the ip address of a tcp connection 394 | */ 395 | func getIP(conn net.Conn) string{ 396 | s := conn.RemoteAddr().String() 397 | s = strings.Split(s, ":")[0] 398 | s = strings.Trim(s, ":") 399 | return s 400 | } 401 | 402 | 403 | /** 404 | Determine the local IP addresses 405 | */ 406 | func getLocalIP() []string { 407 | name, err := os.Hostname() 408 | if err != nil { 409 | fmt.Printf("Oops: %v\n", err) 410 | return []string{} 411 | } 412 | //fmt.Print("Local Hostname: " + name) 413 | 414 | addrs, err := net.LookupHost(name) 415 | if err != nil { 416 | fmt.Printf("Oops: %v\n", err) 417 | return []string{} 418 | } 419 | // fmt.Print("\t\tLocal IP Addresses: ", addrs) 420 | 421 | return addrs 422 | } 423 | -------------------------------------------------------------------------------- /p2pChat/src/s3guest@110.227.80.244: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | /** 4 | This project will implement a Peer-to-Peer command-line chat in Go language. in one control 5 | message only send the actual ipport combination of other peers and let others know 6 | about other peers. One node can be the server (default port of connection for all nodes) 7 | but once nodes connect the peer-to-peer chat works even with the server being taken down 8 | or any of the other nodes being taken down. 9 | 10 | Go version: go1.0.3 11 | 12 | @March 2013 13 | @by Morteza Shahriari Nia @mshahriarinia 14 | 15 | 16 | Reading arbitrary strings from command-line was a bit trickey as I couldn't get a straight-forward example 17 | on telling how to do it. But after visiting tens of pages and blogs it was fixed. Buffers, buffered reader, 18 | streams, ... The diffference between when you learn womething and when you actually do it. 19 | 20 | Multi-threading communciation via channels is very useful but not in our context. We need Mutex 21 | for handling our clients which is not straightforward or natural in channels and message streams. 22 | 23 | The last time consuming issue was the matter of pointers and how to differnetiate 24 | between pass by reference/value. I could not find a good resource online explaining this 25 | and had to hack through 26 | 27 | Debugging without a debugger was a killer but ended up being ok. 28 | */ 29 | 30 | import ( 31 | "bufio" 32 | "fmt" 33 | "math/rand" 34 | "net" 35 | "os" 36 | "runtime" 37 | "strconv" 38 | "strings" 39 | // "strings" 40 | "container/list" 41 | "sync" 42 | "time" 43 | ) 44 | 45 | var ( 46 | port string 47 | SERVER_IP = "127.0.0.1" //TODO fix server ip 48 | SERVER_PORT string = "5555" //default port as the main p2p server 49 | stop = false 50 | mutexPeerList sync.Mutex 51 | CONTROL_MESSAGE_PREAMBLE = "\u001B" + ":!q" //char code used in VIM to exit the program 52 | ) 53 | 54 | type Peer struct { 55 | conn net.Conn 56 | port string 57 | ip string 58 | } 59 | 60 | func main() { 61 | //initialize values 62 | reader := bufio.NewReader(os.Stdin) //read line from standard input 63 | peerList := list.New() //list of p2p chat users. 64 | 65 | fmt.Println("\n\n Welcome to Peer-to-Peer (P2P) Command-Line Chat in Go language.\n\n") 66 | fmt.Print("Run this node as main server? (y/n) ") 67 | 68 | str, err := reader.ReadString('\n') //ignore the error by sending it to nil 69 | if err != nil { 70 | fmt.Println("Can not read from command line.") 71 | os.Exit(1) 72 | } 73 | 74 | if []byte(str)[0] == 'y' { 75 | fmt.Println("Node is the main p2p server.") 76 | port = SERVER_PORT 77 | } else if []byte(str)[0] == 'n' { 78 | fmt.Println("Node is a normal p2p node.") 79 | port = generatePortNo() 80 | connectToIpPort(SERVER_IP+":"+SERVER_PORT, peerList) 81 | } else { 82 | fmt.Println("Wrong argument type.") 83 | os.Exit(1) 84 | } 85 | 86 | fmt.Println("Server Socket: " + SERVER_IP + ":" + SERVER_PORT) 87 | localIp := getLocalIP() 88 | fmt.Println(" Local Socket: " + localIp[0] + ":" + port) 89 | fmt.Println("---------------------------------------------------------") 90 | 91 | go acceptPeers(port, peerList) 92 | go chatSay(peerList) 93 | 94 | runtime.Gosched() //let the new thread to start, otherwuse it will not execute. 95 | 96 | //it's good to not include accepting new clients from main just in case the user 97 | //wants to quit by typing some keywords, the main thread is not stuck at 98 | // net.listen.accept forever 99 | for !stop { 100 | time.Sleep(1000 * time.Millisecond) 101 | } //keep main thread alive 102 | } 103 | 104 | /** 105 | When a peer receives a control message consisting of its list of peers, other peers 106 | connect to that list one by one. list in this message is a string of ipport combinations 107 | */ 108 | func connectToPeers(peer Peer, controlMessage string, peerList *list.List) { 109 | strArr := strings.Split(controlMessage, " ") 110 | for i, ipport := range strArr { 111 | if i == 0 { 112 | //skip preamble 113 | } else if i ==1 { //set actual port for the peer sending this message 114 | peer.port = ipport 115 | }else if !isSelf(ipport) { //skip preamble 116 | connectToIpPort(ipport, peerList) 117 | } 118 | } 119 | } 120 | 121 | /** 122 | ask for a connection from a node via ipport 123 | */ 124 | func connectToIpPort(ipport string, peerList *list.List) { 125 | if strings.Contains(ipport, "nil"){ 126 | return 127 | } 128 | if len(strings.Trim(ipport, " ")) == 0{ 129 | return 130 | } 131 | 132 | if isAlreadyconnected(ipport, peerList){ 133 | return 134 | } 135 | 136 | mutexPeerList.Lock() 137 | conn, err := net.Dial("tcp", ipport) 138 | if err != nil { 139 | fmt.Println("Error connecting to:", ipport, err.Error()) 140 | mutexPeerList.Unlock() 141 | return 142 | 143 | } 144 | peer := &Peer{conn, "nilport", getIP(conn)} 145 | 146 | //peerList.PushBack(peer) 147 | addToList(*peer, peerList) 148 | mutexPeerList.Unlock() 149 | 150 | go handlePeer(peer, peerList) 151 | runtime.Gosched() 152 | } 153 | 154 | 155 | /** 156 | read access to channel list 157 | */ 158 | func chatSay(peerList *list.List) { 159 | reader := bufio.NewReader(os.Stdin) //get teh reader to read lines from standard input 160 | 161 | //conn, err := net.Dial("tcp", serverIP+":"+SERVER_PORT) 162 | 163 | for !stop { //keep reading inputs forever 164 | fmt.Print("user@Home[\\ ") 165 | str, _ := reader.ReadString('\n') 166 | 167 | mutexPeerList.Lock() 168 | for e := peerList.Front(); e != nil; e = e.Next() { 169 | conn := e.Value.(*Peer).conn 170 | _, err := conn.Write([]byte(str)) //transmit string as byte array 171 | if err != nil { 172 | fmt.Println("Error sending reply:", err.Error()) 173 | } 174 | } 175 | mutexPeerList.Unlock() 176 | } 177 | } 178 | 179 | /** 180 | Accept new clients. 181 | */ 182 | func acceptPeers(port string, peerList *list.List) { 183 | //fmt.Println("Listenning to port", port) 184 | ln, err := net.Listen("tcp", ":"+port) 185 | if err != nil { 186 | fmt.Println("Error listenning to port ", port) 187 | stop = true 188 | } 189 | for !stop { 190 | conn, err := ln.Accept() 191 | if err != nil { 192 | fmt.Println("Error in accepting connection.") 193 | stop = true 194 | continue 195 | } 196 | 197 | mutexPeerList.Lock() 198 | peer := &Peer{conn, "nilport", getIP(conn)} 199 | peerList.PushBack(peer) 200 | mutexPeerList.Unlock() 201 | 202 | go handlePeer(peer, peerList) 203 | runtime.Gosched() 204 | } 205 | } 206 | 207 | /** 208 | Receive message from client. 209 | Listen and wait for content from client. the write to 210 | client will be performed when the current user enters an input 211 | */ 212 | func handlePeer(peer *Peer, peerList *list.List) { 213 | stopConn := false 214 | fmt.Println("New node: ", peer.conn.RemoteAddr()) 215 | 216 | 217 | //send current peer list 218 | str := peerListToStr(peerList) 219 | _, err := peer.conn.Write([]byte(CONTROL_MESSAGE_PREAMBLE + " " + port + " " + str)) //transmit string as byte array 220 | if err != nil { 221 | fmt.Println("Error sending reply:", err.Error()) 222 | } 223 | 224 | //Listen for the peer messages 225 | buffer := make([]byte, 1024) 226 | 227 | for !stopConn { 228 | bytesRead, err := peer.conn.Read(buffer) 229 | if err != nil { //stop for loop, remove peer from list 230 | 231 | stopConn = true 232 | fmt.Println("Error in reading from connection", peer.conn.RemoteAddr()) 233 | mutexPeerList.Lock() 234 | el := getListElement(*peer, peerList) 235 | if el != nil { 236 | peerList.Remove(el) 237 | } 238 | mutexPeerList.Unlock() 239 | 240 | } else { 241 | messageStr := string(buffer[0:bytesRead]) 242 | 243 | 244 | 245 | if strings.Contains(messageStr, CONTROL_MESSAGE_PREAMBLE) { 246 | //pass peer itself to set actual port 247 | sArr := strings.Split(messageStr, " ") 248 | fmt.Println("port isSSSSSS: ", sArr[1]) 249 | 250 | 251 | el := getListElement(*peer, peerList) 252 | if el != nil { 253 | p := el.Value.(*Peer) 254 | p.port = sArr[1] 255 | //peer.port = sArr[1] 256 | fmt.Println("setted port to", p.port) 257 | setPort(*peer, peerList, sArr[1]) 258 | 259 | connectToPeers(*peer, messageStr, peerList) 260 | printlist(peerList) 261 | } 262 | fmt.Println(peer.ipport(), " says: ", messageStr) 263 | }else{ 264 | printlist(peerList) 265 | fmt.Println(peer.ipport(), " says: ", messageStr) 266 | } 267 | } 268 | } 269 | fmt.Println("Closing ", peer.conn.RemoteAddr()) 270 | peer.conn.Close() 271 | } 272 | 273 | /** 274 | When the peer sends the port of its TCP listener for new peers we need to set 275 | it in our Peer struct and later on use it for forwarding this port to other peers 276 | */ 277 | func setPort(peer Peer, l *list.List, port string) *list.Element { 278 | for e := l.Front(); e != nil; e = e.Next() { 279 | temp := e.Value.(*Peer) 280 | 281 | if peer.conn.RemoteAddr() == temp.conn.RemoteAddr() { 282 | fmt.Println("found connection.") 283 | temp.port = port 284 | return e 285 | } 286 | } 287 | return nil 288 | } 289 | 290 | /** 291 | return the element of the list that represents the same peer as the arguemnt 292 | */ 293 | func getListElement(peer Peer, l *list.List) *list.Element { 294 | for e := l.Front(); e != nil; e = e.Next() { 295 | temp := e.Value.(*Peer) 296 | 297 | if peer.conn.RemoteAddr() == temp.conn.RemoteAddr() { 298 | fmt.Println("found connection.") 299 | return e 300 | } 301 | } 302 | return nil 303 | } 304 | 305 | 306 | 307 | /** 308 | Avoid adding redundant peers to list, shall be already locked by mutex 309 | */ 310 | func addToList(peer Peer, l *list.List) { 311 | if ! isAlreadyconnected(peer.ipport(), l){ 312 | l.PushBack(&peer) 313 | } 314 | return 315 | } 316 | 317 | /** 318 | check if the ipport combination is already being conneted to 319 | */ 320 | func isAlreadyconnected(ipport string, l *list.List)bool{ 321 | for e := l.Front(); e != nil; e = e.Next() { 322 | temp := e.Value.(*Peer) 323 | if ipport == temp.ipport() { 324 | return true 325 | } 326 | } 327 | return false 328 | } 329 | 330 | 331 | /** 332 | Get a string of the peer list as ip:port 333 | */ 334 | func peerListToStr(l *list.List) string { 335 | if l == nil { 336 | return "" 337 | } 338 | s := "" 339 | mutexPeerList.Lock() 340 | for e := l.Front(); e != nil; e = e.Next() { 341 | peer := e.Value.(*Peer) 342 | if peer.port != "nilport"{ 343 | s = s + peer.ip + ":" + peer.port + " " 344 | } 345 | } 346 | //s = s + getLocalIP()[0] + ":" + port 347 | mutexPeerList.Unlock() 348 | return strings.Trim(s, " ") 349 | } 350 | 351 | /** 352 | print ipport combination of the current peer list 353 | */ 354 | func printlist(l *list.List) { 355 | fmt.Print("\nPeer List: [") 356 | fmt.Print(peerListToStr(l)) 357 | fmt.Println("]") 358 | } 359 | 360 | /** 361 | struct function to return the ipport combination to be used for comparisons 362 | */ 363 | func (p *Peer) ipport() string{ 364 | return p.ip + ":" + p.port 365 | } 366 | 367 | /** 368 | Checks to see if the ipport combination is the current node itself. 369 | */ 370 | func isSelf(ipport string) bool { 371 | ipArr := getLocalIP() 372 | 373 | for _, ip := range ipArr { 374 | if ipport == ip+":"+port { 375 | return true 376 | } 377 | } 378 | if ipport == "127.0.0.1"+":"+port || ipport == "localhost"+":"+port { 379 | return true 380 | } 381 | return false 382 | } 383 | 384 | /** 385 | Generate a port number 386 | */ 387 | func generatePortNo() string { 388 | rand.Seed(time.Now().Unix()) 389 | return strconv.Itoa(rand.Intn(5000) + 5000) //generate a valid port 390 | } 391 | 392 | /** 393 | return the ip address of a tcp connection 394 | */ 395 | func getIP(conn net.Conn) string{ 396 | s := conn.RemoteAddr().String() 397 | s = strings.Split(s, ":")[0] 398 | s = strings.Trim(s, ":") 399 | return s 400 | } 401 | 402 | 403 | /** 404 | Determine the local IP addresses 405 | */ 406 | func getLocalIP() []string { 407 | name, err := os.Hostname() 408 | if err != nil { 409 | fmt.Printf("Oops: %v\n", err) 410 | return []string{} 411 | } 412 | //fmt.Print("Local Hostname: " + name) 413 | 414 | addrs, err := net.LookupHost(name) 415 | if err != nil { 416 | fmt.Printf("Oops: %v\n", err) 417 | return []string{} 418 | } 419 | // fmt.Print("\t\tLocal IP Addresses: ", addrs) 420 | 421 | return addrs 422 | } 423 | --------------------------------------------------------------------------------