1
0
mirror of https://github.com/schollz/croc.git synced 2024-12-18 11:11:29 +03:00
croc/relay.go

196 lines
4.4 KiB
Go
Raw Normal View History

2017-10-17 20:12:03 +03:00
package main
import (
"net"
"strconv"
"strings"
"sync"
2017-10-17 21:03:03 +03:00
"time"
2017-10-17 20:12:03 +03:00
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
)
2017-10-17 20:32:08 +03:00
type connectionMap struct {
reciever map[string]net.Conn
sender map[string]net.Conn
sync.RWMutex
}
var connections connectionMap
func init() {
connections.Lock()
connections.reciever = make(map[string]net.Conn)
connections.sender = make(map[string]net.Conn)
connections.Unlock()
}
2017-10-17 20:12:03 +03:00
func runServer() {
logger := log.WithFields(log.Fields{
"function": "main",
})
2017-10-18 03:39:50 +03:00
logger.Debug("Initializing")
2017-10-17 20:12:03 +03:00
var wg sync.WaitGroup
wg.Add(numberConnections)
for id := 0; id < numberConnections; id++ {
go listenerThread(id, &wg)
}
wg.Wait()
}
func listenerThread(id int, wg *sync.WaitGroup) {
logger := log.WithFields(log.Fields{
2017-10-18 05:33:27 +03:00
"function": "listenerThread:" + strconv.Itoa(27000+id),
2017-10-17 20:12:03 +03:00
})
defer wg.Done()
err := listener(id)
if err != nil {
logger.Error(err)
}
}
func listener(id int) (err error) {
port := strconv.Itoa(27001 + id)
logger := log.WithFields(log.Fields{
2017-10-18 05:33:27 +03:00
"function": "listener" + ":" + port,
2017-10-17 20:12:03 +03:00
})
2017-10-18 05:33:27 +03:00
server, err := net.Listen("tcp", "0.0.0.0:"+port)
2017-10-17 20:12:03 +03:00
if err != nil {
2017-10-18 05:33:27 +03:00
return errors.Wrap(err, "Error listening on "+":"+port)
2017-10-17 20:12:03 +03:00
}
defer server.Close()
2017-10-18 03:39:50 +03:00
logger.Debug("waiting for connections")
2017-10-17 20:12:03 +03:00
//Spawn a new goroutine whenever a client connects
for {
connection, err := server.Accept()
if err != nil {
return errors.Wrap(err, "problem accepting connection")
}
2017-10-18 03:39:50 +03:00
logger.Debugf("Client %s connected", connection.RemoteAddr().String())
2017-10-17 20:12:03 +03:00
go clientCommuncation(id, connection)
}
}
func clientCommuncation(id int, connection net.Conn) {
sendMessage("who?", connection)
message := receiveMessage(connection)
2017-10-17 20:32:08 +03:00
connectionType := strings.Split(message, ".")[0]
2017-10-18 03:39:50 +03:00
codePhrase := strings.Split(message, ".")[1] + "-" + strconv.Itoa(id)
logger := log.WithFields(log.Fields{
"id": id,
"codePhrase": codePhrase,
})
2017-10-17 20:32:08 +03:00
if connectionType == "s" {
2017-10-18 03:39:50 +03:00
logger.Debug("got sender")
2017-10-17 21:03:03 +03:00
connections.Lock()
connections.sender[codePhrase] = connection
connections.Unlock()
for {
connections.RLock()
if _, ok := connections.reciever[codePhrase]; ok {
2017-10-18 03:39:50 +03:00
logger.Debug("got reciever")
connections.RUnlock()
2017-10-17 21:03:03 +03:00
break
}
connections.RUnlock()
time.Sleep(100 * time.Millisecond)
}
2017-10-18 03:39:50 +03:00
logger.Debug("telling sender ok")
2017-10-17 21:03:03 +03:00
sendMessage("ok", connection)
2017-10-18 03:39:50 +03:00
logger.Debug("preparing pipe")
connections.Lock()
con1 := connections.sender[codePhrase]
con2 := connections.reciever[codePhrase]
connections.Unlock()
2017-10-18 03:39:50 +03:00
logger.Debug("piping connections")
Pipe(con1, con2)
2017-10-18 03:39:50 +03:00
logger.Debug("done piping")
connections.Lock()
delete(connections.sender, codePhrase)
delete(connections.reciever, codePhrase)
connections.Unlock()
2017-10-18 03:39:50 +03:00
logger.Debug("deleted sender and receiver")
2017-10-17 21:03:03 +03:00
} else {
2017-10-18 03:39:50 +03:00
logger.Debug("got reciever")
2017-10-17 21:03:03 +03:00
connections.Lock()
connections.reciever[codePhrase] = connection
connections.Unlock()
2017-10-17 20:32:08 +03:00
}
2017-10-17 20:12:03 +03:00
return
}
func sendMessage(message string, connection net.Conn) {
2017-10-17 21:03:03 +03:00
message = fillString(message, BUFFERSIZE)
2017-10-17 20:12:03 +03:00
connection.Write([]byte(message))
}
func receiveMessage(connection net.Conn) string {
2017-10-17 21:03:03 +03:00
messageByte := make([]byte, BUFFERSIZE)
2017-10-18 03:39:50 +03:00
connection.Read(messageByte)
2017-10-17 20:12:03 +03:00
return strings.Replace(string(messageByte), ":", "", -1)
}
func fillString(retunString string, toLength int) string {
for {
lengthString := len(retunString)
if lengthString < toLength {
retunString = retunString + ":"
continue
}
break
}
return retunString
}
2017-10-18 02:50:20 +03:00
// chanFromConn creates a channel from a Conn object, and sends everything it
// Read()s from the socket to the channel.
func chanFromConn(conn net.Conn) chan []byte {
c := make(chan []byte)
go func() {
b := make([]byte, BUFFERSIZE)
for {
n, err := conn.Read(b)
if n > 0 {
res := make([]byte, n)
// Copy the buffer so it doesn't get changed while read by the recipient.
copy(res, b[:n])
c <- res
}
if err != nil {
c <- nil
break
}
}
}()
return c
}
// Pipe creates a full-duplex pipe between the two sockets and transfers data from one to the other.
func Pipe(conn1 net.Conn, conn2 net.Conn) {
chan1 := chanFromConn(conn1)
chan2 := chanFromConn(conn2)
for {
select {
case b1 := <-chan1:
if b1 == nil {
return
} else {
conn2.Write(b1)
}
case b2 := <-chan2:
if b2 == nil {
return
} else {
conn1.Write(b2)
}
}
}
}