croc/src/tcp/tcp.go

212 lines
4.2 KiB
Go
Raw Normal View History

2018-09-23 21:34:29 +02:00
package tcp
import (
"net"
"sync"
"time"
log "github.com/cihub/seelog"
"github.com/pkg/errors"
"github.com/schollz/croc/src/comm"
"github.com/schollz/croc/src/logger"
)
const TCP_BUFFER_SIZE = 1024 * 64
2018-09-23 21:34:29 +02:00
type roomInfo struct {
2019-04-29 22:06:18 +02:00
first *comm.Comm
second *comm.Comm
2019-04-27 18:20:03 +02:00
opened time.Time
full bool
2018-09-23 21:34:29 +02:00
}
type roomMap struct {
rooms map[string]roomInfo
sync.Mutex
}
var rooms roomMap
// Run starts a tcp listener, run async
func Run(debugLevel, port string) {
logger.SetLogLevel(debugLevel)
rooms.Lock()
rooms.rooms = make(map[string]roomInfo)
rooms.Unlock()
2018-10-13 15:13:50 +02:00
// delete old rooms
go func() {
for {
time.Sleep(10 * time.Minute)
rooms.Lock()
for room := range rooms.rooms {
if time.Since(rooms.rooms[room].opened) > 3*time.Hour {
delete(rooms.rooms, room)
}
}
rooms.Unlock()
}
}()
2018-09-23 21:34:29 +02:00
err := run(port)
if err != nil {
log.Error(err)
}
}
func run(port string) (err error) {
log.Debugf("starting TCP server on " + port)
2018-09-26 23:31:45 +02:00
server, err := net.Listen("tcp", "0.0.0.0:"+port)
2018-09-23 21:34:29 +02:00
if err != nil {
return errors.Wrap(err, "Error listening on :"+port)
}
defer server.Close()
// spawn a new goroutine whenever a client connects
for {
2018-09-26 19:43:38 +02:00
connection, err := server.Accept()
2018-09-23 21:34:29 +02:00
if err != nil {
return errors.Wrap(err, "problem accepting connection")
}
log.Debugf("client %s connected", connection.RemoteAddr().String())
2018-09-26 19:43:38 +02:00
go func(port string, connection net.Conn) {
2018-09-23 21:34:29 +02:00
errCommunication := clientCommuncation(port, comm.New(connection))
if errCommunication != nil {
log.Warnf("relay-%s: %s", connection.RemoteAddr().String(), errCommunication.Error())
}
}(port, connection)
}
}
2019-04-29 22:06:18 +02:00
func clientCommuncation(port string, c *comm.Comm) (err error) {
2018-09-23 21:34:29 +02:00
// send ok to tell client they are connected
2018-10-13 15:09:55 +02:00
log.Debug("sending ok")
2019-04-27 18:20:03 +02:00
err = c.Send([]byte("ok"))
2018-09-23 21:34:29 +02:00
if err != nil {
return
}
// wait for client to tell me which room they want
2018-10-13 15:09:55 +02:00
log.Debug("waiting for answer")
2019-04-27 18:20:03 +02:00
roomBytes, err := c.Receive()
2018-09-23 21:34:29 +02:00
if err != nil {
return
}
2019-04-27 18:20:03 +02:00
room := string(roomBytes)
2018-09-23 21:34:29 +02:00
rooms.Lock()
2019-04-27 18:20:03 +02:00
// create the room if it is new
2018-09-23 21:34:29 +02:00
if _, ok := rooms.rooms[room]; !ok {
rooms.rooms[room] = roomInfo{
2019-04-27 18:20:03 +02:00
first: c,
opened: time.Now(),
2018-09-23 21:34:29 +02:00
}
rooms.Unlock()
// tell the client that they got the room
2019-04-27 18:20:03 +02:00
err = c.Send([]byte("ok"))
2018-09-23 21:34:29 +02:00
if err != nil {
2018-10-13 15:09:55 +02:00
log.Error(err)
2018-09-23 21:34:29 +02:00
return
}
2019-04-27 18:20:03 +02:00
log.Debugf("room %s has 1", room)
2018-09-23 21:34:29 +02:00
return nil
}
2019-04-27 18:20:03 +02:00
if rooms.rooms[room].full {
rooms.Unlock()
err = c.Send([]byte("room full"))
if err != nil {
log.Error(err)
return
}
return nil
}
log.Debugf("room %s has 2", room)
rooms.rooms[room] = roomInfo{
first: rooms.rooms[room].first,
second: c,
opened: rooms.rooms[room].opened,
full: true,
}
otherConnection := rooms.rooms[room].first
2018-09-23 21:34:29 +02:00
rooms.Unlock()
// second connection is the sender, time to staple connections
var wg sync.WaitGroup
wg.Add(1)
// start piping
2019-04-29 22:06:18 +02:00
go func(com1, com2 *comm.Comm, wg *sync.WaitGroup) {
2018-09-23 21:34:29 +02:00
log.Debug("starting pipes")
pipe(com1.Connection(), com2.Connection())
wg.Done()
log.Debug("done piping")
2019-04-27 18:20:03 +02:00
}(otherConnection, c, &wg)
2018-09-23 21:34:29 +02:00
// tell the sender everything is ready
2019-04-27 18:20:03 +02:00
err = c.Send([]byte("ok"))
2018-09-23 21:34:29 +02:00
if err != nil {
return
}
wg.Wait()
// delete room
rooms.Lock()
log.Debugf("deleting room: %s", room)
2019-04-27 18:20:03 +02:00
rooms.rooms[room].first.Close()
rooms.rooms[room].second.Close()
2019-04-29 22:06:18 +02:00
rooms.rooms[room] = roomInfo{first: nil, second: nil}
2018-09-23 21:34:29 +02:00
delete(rooms.rooms, room)
rooms.Unlock()
return nil
}
// chanFromConn creates a channel from a Conn object, and sends everything it
// Read()s from the socket to the channel.
2018-09-26 19:43:38 +02:00
func chanFromConn(conn net.Conn) chan []byte {
2019-04-29 23:46:40 +02:00
c := make(chan []byte, 1)
2018-09-23 21:34:29 +02:00
go func() {
b := make([]byte, TCP_BUFFER_SIZE)
2018-09-26 23:31:45 +02:00
2018-09-23 21:34:29 +02:00
for {
2018-09-26 18:55:14 +02:00
n, err := conn.Read(b)
2018-09-26 15:36:47 +02:00
if n > 0 {
2018-09-26 18:14:24 +02:00
res := make([]byte, n)
// Copy the buffer so it doesn't get changed while read by the recipient.
copy(res, b[:n])
c <- res
2018-09-26 15:36:47 +02:00
}
2018-09-23 21:34:29 +02:00
if err != nil {
2018-10-13 15:09:55 +02:00
log.Debug(err)
2018-09-23 21:34:29 +02:00
c <- nil
break
}
}
2019-04-29 23:46:40 +02:00
log.Debug("exiting")
2018-09-23 21:34:29 +02:00
}()
return c
}
// pipe creates a full-duplex pipe between the two sockets and
// transfers data from one to the other.
2018-09-26 19:43:38 +02:00
func pipe(conn1 net.Conn, conn2 net.Conn) {
2018-09-23 21:34:29 +02:00
chan1 := chanFromConn(conn1)
2018-09-26 23:31:45 +02:00
chan2 := chanFromConn(conn2)
2018-09-23 21:34:29 +02:00
for {
2018-09-26 23:31:45 +02:00
select {
case b1 := <-chan1:
if b1 == nil {
return
}
conn2.Write(b1)
2018-09-26 18:41:12 +02:00
2018-09-26 23:31:45 +02:00
case b2 := <-chan2:
if b2 == nil {
return
}
conn1.Write(b2)
}
2018-09-23 21:34:29 +02:00
}
}