-
Notifications
You must be signed in to change notification settings - Fork 9
/
tcp.go
140 lines (126 loc) · 3 KB
/
tcp.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package utils
import (
"context"
"fmt"
"io"
"net"
"os"
"strconv"
"strings"
"sync"
files "github.com/ipfs/go-ipfs-files"
)
//Define the size of how big the chunks of data will be send each time
const BUFFERSIZE = 1024
// TCPServer structure
type TCPServer struct {
quit chan interface{}
listener net.Listener
file files.Node
Addr string
wg sync.WaitGroup
}
// SpawnTCPServer Spawns a TCP server that serves a specific file.
func SpawnTCPServer(ctx context.Context, tmpFile files.Node) (*TCPServer, error) {
//Create a TCP istener on localhost with porth 27001
listener, err := net.Listen("tcp", "0.0.0.0:0")
fmt.Println("listening at: ", listener.Addr().String())
if err != nil {
fmt.Println("Error listetning: ", err)
return nil, err
}
//Spawn a new goroutine whenever a lient connects
s := &TCPServer{
quit: make(chan interface{}),
listener: listener,
file: tmpFile,
Addr: listener.Addr().String(),
}
s.wg.Add(1)
go s.Start()
return s, nil
}
// Start listening for conections.
func (s *TCPServer) Start() {
// Start listening routine
defer s.wg.Done()
for {
connection, err := s.listener.Accept()
if err != nil {
select {
case <-s.quit:
return
default:
fmt.Println("Accept error", err)
}
} else {
s.wg.Add(1)
go s.sendFileToClient(connection)
s.wg.Done()
}
}
}
// Close the TCP Server.
func (s *TCPServer) Close() {
close(s.quit)
s.listener.Close()
s.wg.Wait()
fmt.Println("Successfully closed TCP server")
}
// Format for fileSize
func fillString(retunString string, toLength int) string {
for {
lengtString := len(retunString)
if lengtString < toLength {
retunString = retunString + ":"
continue
}
break
}
return retunString
}
// Sends file to client.
func (s *TCPServer) sendFileToClient(connection net.Conn) {
defer connection.Close()
sendBuffer := make([]byte, BUFFERSIZE)
size, _ := s.file.Size()
// The first buffer is to notify the size.
fileSize := fillString(strconv.FormatInt(size, 10), 10)
connection.Write([]byte(fileSize))
for {
_, err := files.ToFile(s.file).Read(sendBuffer)
if err == io.EOF {
break
}
connection.Write(sendBuffer)
}
return
}
// FetchFileTCP fetchs the file server in an address by a TCP server.
func FetchFileTCP(addr string) {
connection, err := net.Dial("tcp", addr)
if err != nil {
panic(err)
}
defer connection.Close()
bufferFileSize := make([]byte, 10)
connection.Read(bufferFileSize)
fileSize, _ := strconv.ParseInt(strings.Trim(string(bufferFileSize), ":"), 10, 64)
newFile, err := os.OpenFile("/dev/null", os.O_WRONLY, 0)
if err != nil {
panic(err)
}
defer newFile.Close()
var receivedBytes int64
for {
if (fileSize - receivedBytes) < BUFFERSIZE {
io.CopyN(newFile, connection, (fileSize - receivedBytes))
connection.Read(make([]byte, (receivedBytes+BUFFERSIZE)-fileSize))
receivedBytes = fileSize - receivedBytes
break
}
io.CopyN(newFile, connection, BUFFERSIZE)
receivedBytes += BUFFERSIZE
}
fmt.Println("Finished fetch..")
}