Merge pull request #87 from Akilan1999/NAT-traversal

NAT Traversal with FRP and IPTables resolved
This commit is contained in:
Akilan Selvacoumar
2023-01-25 01:18:43 +00:00
committed by GitHub
20 changed files with 1285 additions and 413 deletions

View File

@@ -3,7 +3,6 @@ package client
import (
"encoding/json"
"fmt"
"git.sr.ht/~akilan1999/p2p-rendering-computation/p2p"
"git.sr.ht/~akilan1999/p2p-rendering-computation/server"
"io/ioutil"
"net/http"
@@ -12,30 +11,30 @@ import (
// GetSpecs Gets Specs from the server such CPU, GPU usage
// and other basic information which helps set a
// cluster of computer
func GetSpecs(IP string)(*server.SysInfo,error) {
func GetSpecs(IP string) (*server.SysInfo, error) {
var URL string
version := p2p.Ip4or6(IP)
//version := p2p.Ip4or6(IP)
//Get port number of the server
serverPort, err := GetServerPort(IP)
if err != nil {
return nil, err
}
//serverPort, err := GetServerPort(IP)
//if err != nil {
// return nil, err
//}
if version == "version 6" {
URL = "http://[" + IP + "]:" + serverPort + "/server_info"
} else {
URL = "http://" + IP + ":" + serverPort + "/server_info"
}
//if version == "version 6" {
URL = "http://" + IP + "/server_info"
//} else {
// URL = "http://" + IP + ":" + serverPort + "/server_info"
//}
resp, err := http.Get(URL)
if err != nil {
return nil,err
return nil, err
}
// Convert response to byte value
byteValue, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil,err
return nil, err
}
// Create variable for result response type
@@ -44,7 +43,7 @@ func GetSpecs(IP string)(*server.SysInfo,error) {
// Adds byte value to docker.DockerVM struct
json.Unmarshal(byteValue, &serverSpecsResult)
if err != nil {
return nil,err
return nil, err
}
return &serverSpecsResult, nil
@@ -61,4 +60,4 @@ func PrettyPrint(data interface{}) {
return
}
fmt.Printf("%s \n", p)
}
}

View File

@@ -1,4 +1,4 @@
package client
package clientIPTable
import (
"encoding/json"
@@ -22,17 +22,16 @@ func UpdateIpTable(IpAddress string, serverPort string) error {
client := http.Client{}
var resp []byte
version := p2p.Ip4or6(IpAddress)
if version == "version 6" {
resp, err = UploadMultipartFile(client,"http://[" + IpAddress + "]:" + serverPort + "/IpTable","json",config.IPTable)
if err != nil {
return err
}
resp, err = UploadMultipartFile(client, "http://["+IpAddress+"]:"+serverPort+"/IpTable", "json", config.IPTable)
if err != nil {
return err
}
} else {
resp, err = UploadMultipartFile(client,"http://" + IpAddress + ":" + serverPort + "/IpTable","json",config.IPTable)
resp, err = UploadMultipartFile(client, "http://"+IpAddress+":"+serverPort+"/IpTable", "json", config.IPTable)
if err != nil {
return err
}
@@ -65,13 +64,17 @@ func UpdateIpTable(IpAddress string, serverPort string) error {
return nil
}
// UpdateIpTableListClient updates IP tables (Default 3 hops) based on server information available
//on the ip tables
// on the ip tables
func UpdateIpTableListClient() error {
// Get config information
Config, err := config.ConfigInit()
if err != nil {
return err
}
// Ensure that the IP Table has Node pingable
err := p2p.LocalSpeedTestIpTable()
err = p2p.LocalSpeedTestIpTable()
if err != nil {
return err
}
@@ -80,52 +83,53 @@ func UpdateIpTableListClient() error {
// duplication
Addresses, err := p2p.ReadIpTable()
//var DoNotRead p2p.IpAddresses
var DoNotRead p2p.IpAddresses
// Run loop 3 times
for i := 0; i < 3; i++ {
currentIPV4, err := p2p.CurrentPublicIP()
if err != nil {
return err
}
// Run loop 2 times
for i := 0; i < 2; i++ {
// Gets information from IP table
//Addresses, err = p2p.ReadIpTable()
//if err != nil {
// return err
//}
//
Addresses, err = p2p.ReadIpTable()
if err != nil {
return err
}
//DoNotRead.IpAddress = append(DoNotRead.IpAddress, PublicIP)
// Updates IP table based on server IP table
for j := range Addresses.IpAddress {
//Exists := false
//
//if PublicIP.Ipv4 == Addresses.IpAddress[j].Ipv4 || (PublicIP.Ipv6 != "" && Addresses.IpAddress[j].Ipv6 == PublicIP.Ipv6){
// Exists = true
//}
//
//// Check if IP addresses is there in the struct DoNotRead
//for k := range DoNotRead.IpAddress {
// if DoNotRead.IpAddress[k].Ipv4 == Addresses.IpAddress[j].Ipv4 || (DoNotRead.IpAddress[k].Ipv6 != "" && Addresses.IpAddress[j].Ipv6 == DoNotRead.IpAddress[k].Ipv6) {
// Exists = true
// break
// }
//}
//
//// If the struct exists then continues
//if Exists {
// continue
//}
if Addresses.IpAddress[j].Ipv6 != "" {
err = UpdateIpTable(Addresses.IpAddress[j].Ipv6, Addresses.IpAddress[j].ServerPort)
} else {
err = UpdateIpTable(Addresses.IpAddress[j].Ipv4, Addresses.IpAddress[j].ServerPort)
Exists := false
// If the address is local then add to the local list
if currentIPV4 == Addresses.IpAddress[j].Ipv4 && Addresses.IpAddress[j].ServerPort == Config.ServerPort {
Exists = true
}
if err != nil {
return err
// Check if IP addresses is there in the struct DoNotRead
for k := range DoNotRead.IpAddress {
if (DoNotRead.IpAddress[k].Ipv4 == Addresses.IpAddress[j].Ipv4 && DoNotRead.IpAddress[k].ServerPort == Addresses.IpAddress[j].ServerPort) || (DoNotRead.IpAddress[k].Ipv6 != "" && Addresses.IpAddress[j].Ipv6 == DoNotRead.IpAddress[k].Ipv6) {
Exists = true
break
}
}
// If the struct exists then continues
if Exists {
continue
}
if Addresses.IpAddress[j].Ipv6 != "" {
go UpdateIpTable(Addresses.IpAddress[j].Ipv6, Addresses.IpAddress[j].ServerPort)
} else if Addresses.IpAddress[j].Ipv4 != currentIPV4 {
go UpdateIpTable(Addresses.IpAddress[j].Ipv4, Addresses.IpAddress[j].ServerPort)
}
//Appends server1 IP address to variable DoNotRead
//DoNotRead.IpAddress = append(DoNotRead.IpAddress, Addresses.IpAddress[j])
DoNotRead.IpAddress = append(DoNotRead.IpAddress, Addresses.IpAddress[j])
}
}
@@ -234,4 +238,3 @@ func UploadMultipartFile(client http.Client, uri, key, path string) ([]byte, err
return content, nil
}

View File

@@ -1,4 +1,4 @@
package client
package clientIPTable
import (
"testing"
@@ -11,4 +11,3 @@ func TestUpdateIpTableListClient(t *testing.T) {
t.Error(err)
}
}

View File

@@ -12,39 +12,39 @@ import (
var (
serverPort = "8088"
client = http.Client{}
client = http.Client{}
)
// StartContainer Start container using REST api Implementation
// From the selected server IP address
// TODO: Test cases for this function
//Calls URL ex: http://0.0.0.0:8088/startcontainer?ports=0&GPU=false&ContainerName=docker-ubuntu-sshd
func StartContainer(IP string, NumPorts int, GPU bool, ContainerName string) (*docker.DockerVM ,error) {
// Calls URL ex: http://0.0.0.0:8088/startcontainer?ports=0&GPU=false&ContainerName=docker-ubuntu-sshd
func StartContainer(IP string, NumPorts int, GPU bool, ContainerName string) (*docker.DockerVM, error) {
// Passes URL with number of TCP ports to allocated and to give GPU access to the docker container
var URL string
version := p2p.Ip4or6(IP)
//version := p2p.Ip4or6(IP)
//
////Get port number of the server
//serverPort, err := GetServerPort(IP)
//if err != nil {
// return nil, err
//}
//Get port number of the server
serverPort, err := GetServerPort(IP)
if err != nil {
return nil, err
}
if version == "version 6" {
URL = "http://[" + IP + "]:" + serverPort + "/startcontainer?ports=" + fmt.Sprint(NumPorts) + "&GPU=" + strconv.FormatBool(GPU) + "&ContainerName=" + ContainerName
} else {
URL = "http://" + IP + ":" + serverPort + "/startcontainer?ports=" + fmt.Sprint(NumPorts) + "&GPU=" + strconv.FormatBool(GPU) + "&ContainerName=" + ContainerName
}
//if version == "version 6" {
// URL = "http://[" + IP + "]:" + serverPort + "/startcontainer?ports=" + fmt.Sprint(NumPorts) + "&GPU=" + strconv.FormatBool(GPU) + "&ContainerName=" + ContainerName
//} else {
URL = "http://" + IP + "/startcontainer?ports=" + fmt.Sprint(NumPorts) + "&GPU=" + strconv.FormatBool(GPU) + "&ContainerName=" + ContainerName
//}
resp, err := http.Get(URL)
if err != nil {
return nil,err
return nil, err
}
// Convert response to byte value
byteValue, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil,err
return nil, err
}
// Create variable for result response type
@@ -53,7 +53,7 @@ func StartContainer(IP string, NumPorts int, GPU bool, ContainerName string) (*d
// Adds byte value to docker.DockerVM struct
json.Unmarshal(byteValue, &dockerResult)
if err != nil {
return nil,err
return nil, err
}
// Adds the container to the tracked list
@@ -66,21 +66,21 @@ func StartContainer(IP string, NumPorts int, GPU bool, ContainerName string) (*d
}
// RemoveContianer Stops and removes container from the server
func RemoveContianer(IP string,ID string) error {
func RemoveContianer(IP string, ID string) error {
var URL string
version := p2p.Ip4or6(IP)
//version := p2p.Ip4or6(IP)
//
////Get port number of the server
//serverPort, err := GetServerPort(IP)
//if err != nil {
// return err
//}
//Get port number of the server
serverPort, err := GetServerPort(IP)
if err != nil {
return err
}
if version == "version 6" {
URL = "http://[" + IP + "]:" + serverPort + "/RemoveContainer?id=" + ID
} else {
URL = "http://" + IP + ":" + serverPort + "/RemoveContainer?id=" + ID
}
//if version == "version 6" {
// URL = "http://[" + IP + "]:" + serverPort + "/RemoveContainer?id=" + ID
//} else {
URL = "http://" + IP + "/RemoveContainer?id=" + ID
//}
resp, err := http.Get(URL)
if err != nil {
return err
@@ -102,7 +102,7 @@ func RemoveContianer(IP string,ID string) error {
if err != nil {
return err
}
// Remove container created from the tracked list
// Remove container created from the tracked list
err = RemoveTrackedContainer(ID)
if err != nil {
return err
@@ -112,31 +112,31 @@ func RemoveContianer(IP string,ID string) error {
}
// ViewContainers This function displays all containers available on server side
func ViewContainers(IP string)(*docker.DockerContainers, error){
func ViewContainers(IP string) (*docker.DockerContainers, error) {
// Passes URL with route /ShowImages
var URL string
version := p2p.Ip4or6(IP)
//version := p2p.Ip4or6(IP)
//
////Get port number of the server
//serverPort, err := GetServerPort(IP)
//if err != nil {
// return nil, err
//}
//Get port number of the server
serverPort, err := GetServerPort(IP)
if err != nil {
return nil, err
}
if version == "version 6" {
URL = "http://[" + IP + "]:" + serverPort + "/ShowImages"
} else {
URL = "http://" + IP + ":" + serverPort + "/ShowImages"
}
//if version == "version 6" {
// URL = "http://[" + IP + "]:" + serverPort + "/ShowImages"
//} else {
URL = "http://" + IP + "/ShowImages"
//}
resp, err := http.Get(URL)
if err != nil {
return nil,err
return nil, err
}
// Convert response to byte value
byteValue, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil,err
return nil, err
}
// Create variable for result response type
@@ -145,18 +145,18 @@ func ViewContainers(IP string)(*docker.DockerContainers, error){
// Adds byte value to docker.DockerContainers struct
json.Unmarshal(byteValue, &Result)
if err != nil {
return nil,err
return nil, err
}
return &Result, nil
}
// GetServerPort Helper function to do find out server port information
func GetServerPort(IpAddress string) (string,error) {
func GetServerPort(IpAddress string) (string, error) {
// Getting information from the clients ip table
ipTable, err := p2p.ReadIpTable()
if err != nil {
return "",err
return "", err
}
// Iterate thorough ip table struct and find
@@ -170,7 +170,7 @@ func GetServerPort(IpAddress string) (string,error) {
}
// We return default port
return "8088",nil
return "8088", nil
}
// PrintStartContainer Prints results Generated container
@@ -187,7 +187,6 @@ func GetServerPort(IpAddress string) (string,error) {
// }
//}
// TODO implementation using RPC calls
//func StartContainer(Ip string) (*docker.DockerVM,error){
// client, err := rpc.DialHTTP("tcp",Ip + ":" + serverPort)

View File

@@ -3,6 +3,7 @@ package cmd
import (
"fmt"
"git.sr.ht/~akilan1999/p2p-rendering-computation/client"
"git.sr.ht/~akilan1999/p2p-rendering-computation/client/clientIPTable"
"git.sr.ht/~akilan1999/p2p-rendering-computation/config"
"git.sr.ht/~akilan1999/p2p-rendering-computation/generate"
"git.sr.ht/~akilan1999/p2p-rendering-computation/p2p"
@@ -13,14 +14,16 @@ import (
var CliAction = func(ctx *cli.Context) error {
if Server {
// TODO: with RPC calls
server.Server()
err := server.Server()
if err != nil {
fmt.Print(err)
}
//server.Rpc()
}
//Listing servers and also updates IP tables (Default 3 hops)
if UpdateServerList {
err := client.UpdateIpTableListClient()
err := clientIPTable.UpdateIpTableListClient()
if err != nil {
fmt.Print(err)
}
@@ -77,7 +80,6 @@ var CliAction = func(ctx *cli.Context) error {
// Adds the new server IP to the iptable
res.WriteIpTable()
}
// Displays all images available on the server side
@@ -91,8 +93,8 @@ var CliAction = func(ctx *cli.Context) error {
}
// Function called to stop and remove server from Docker
if RemoveVM != "" && ID != "" {
err := client.RemoveContianer(RemoveVM,ID)
if RemoveVM != "" && ID != "" {
err := client.RemoveContianer(RemoveVM, ID)
if err != nil {
fmt.Print(err)
}
@@ -109,7 +111,7 @@ var CliAction = func(ctx *cli.Context) error {
}
// Calls function to do Api call to start the container on the server side
imageRes, err := client.StartContainer(CreateVM,PortsInt,GPU,ContainerName)
imageRes, err := client.StartContainer(CreateVM, PortsInt, GPU, ContainerName)
if err != nil {
fmt.Print(err)
@@ -146,9 +148,9 @@ var CliAction = func(ctx *cli.Context) error {
}
// If the view plugin flag is called then display all
// plugins available
// plugins available
if ViewPlugin {
plugins ,err := plugin.DetectPlugins()
plugins, err := plugin.DetectPlugins()
if err != nil {
fmt.Print(err)
}
@@ -205,9 +207,9 @@ var CliAction = func(ctx *cli.Context) error {
} else {
client.PrettyPrint(group)
}
} else if ID != "" { // Add container to group based on group ID provided
} else if ID != "" { // Add container to group based on group ID provided
// --id <Container ID>
group, err := client.AddContainerToGroup(ID,Group)
group, err := client.AddContainerToGroup(ID, Group)
if err != nil {
fmt.Println(err)
} else {
@@ -244,6 +246,16 @@ var CliAction = func(ctx *cli.Context) error {
client.PrettyPrint(groups)
}
}
// Starts server as a reverse proxy so that
// nodes can connect to each other behind NAT
//if FRPProxy {
// err := frp.StartFRPProxyFromRandom()
// if err != nil {
// fmt.Println(err)
// }
//}
// -- REMOVE ON REGULAR RELEASE --
// when flag --gen is called an extension
// of the project is created to repurpose
@@ -252,9 +264,9 @@ var CliAction = func(ctx *cli.Context) error {
var err error
// If the module name is provided
if Modulename != "" {
err = generate.GenerateNewProject(Generate,Modulename)
err = generate.GenerateNewProject(Generate, Modulename)
} else {
err = generate.GenerateNewProject(Generate,Generate)
err = generate.GenerateNewProject(Generate, Generate)
}
if err != nil {
fmt.Println(err)
@@ -288,7 +300,5 @@ var CliAction = func(ctx *cli.Context) error {
}
}
return nil
}

View File

@@ -6,223 +6,231 @@ import (
// Variables declared for CLI
var (
AddServer string
ViewImages string
CreateVM string
ContainerName string
Ports string
Server bool
RemoveVM string
ID string
Specs string
GPU bool
UpdateServerList bool
ServerList bool
SetDefaultConfig bool
NetworkInterface bool
ViewPlugin bool
TrackedContainers bool
ExecutePlugin string
CreateGroup bool
Group string
AddServer string
ViewImages string
CreateVM string
ContainerName string
Ports string
Server bool
RemoveVM string
ID string
Specs string
GPU bool
UpdateServerList bool
ServerList bool
SetDefaultConfig bool
NetworkInterface bool
ViewPlugin bool
TrackedContainers bool
ExecutePlugin string
CreateGroup bool
Group string
Groups bool
RemoveContainerGroup bool
RemoveGroup string
RemoveGroup string
//FRPProxy bool
// Generate only allowed in dev release
// -- REMOVE ON REGULAR RELEASE --
Generate string
Modulename string
Generate string
Modulename string
//--------------------------------
PullPlugin string
RemovePlugin string
PullPlugin string
RemovePlugin string
)
var AppConfigFlags = []cli.Flag{
// Deprecated to be implemented using GRPC
&cli.BoolFlag{
Name: "Server",
Aliases: []string{"s"},
Aliases: []string{"s"},
Usage: "Starts server",
EnvVars: []string{"SERVER"},
EnvVars: []string{"SERVER"},
Destination: &Server,
},
&cli.BoolFlag{
Name: "UpdateServerList",
Aliases: []string{"us"},
Aliases: []string{"us"},
Usage: "Update List of Server available based on servers iptables",
EnvVars: []string{"UPDATE_SERVER_LIST"},
EnvVars: []string{"UPDATE_SERVER_LIST"},
Destination: &UpdateServerList,
},
&cli.BoolFlag{
Name: "ListServers",
Aliases: []string{"ls"},
Aliases: []string{"ls"},
Usage: "List servers which can render tasks",
EnvVars: []string{"LIST_SERVERS"},
EnvVars: []string{"LIST_SERVERS"},
Destination: &ServerList,
},
&cli.StringFlag{
Name: "AddServer",
Aliases: []string{"as"},
Aliases: []string{"as"},
Usage: "Adds server IP address to iptables",
EnvVars: []string{"ADD_SERVER"},
EnvVars: []string{"ADD_SERVER"},
Destination: &AddServer,
},
&cli.StringFlag{
Name: "ViewImages",
Aliases: []string{"vi"},
Aliases: []string{"vi"},
Usage: "View images available on the server IP address",
EnvVars: []string{"VIEW_IMAGES"},
EnvVars: []string{"VIEW_IMAGES"},
Destination: &ViewImages,
},
&cli.StringFlag{
Name: "CreateVM",
Aliases: []string{"touch"},
Aliases: []string{"touch"},
Usage: "Creates Docker container on the selected server",
EnvVars: []string{"CREATE_VM"},
EnvVars: []string{"CREATE_VM"},
Destination: &CreateVM,
},
&cli.StringFlag{
Name: "ContainerName",
Aliases: []string{"cn"},
Aliases: []string{"cn"},
Usage: "Specifying the container run on the server side",
EnvVars: []string{"CONTAINER_NAME"},
EnvVars: []string{"CONTAINER_NAME"},
Destination: &ContainerName,
},
&cli.StringFlag{
Name: "RemoveVM",
Aliases: []string{"rm"},
Aliases: []string{"rm"},
Usage: "Stop and Remove Docker container",
EnvVars: []string{"REMOVE_VM"},
EnvVars: []string{"REMOVE_VM"},
Destination: &RemoveVM,
},
&cli.StringFlag{
Name: "ID",
Aliases: []string{"id"},
Aliases: []string{"id"},
Usage: "Docker Container ID",
EnvVars: []string{"ID"},
EnvVars: []string{"ID"},
Destination: &ID,
},
&cli.StringFlag{
Name: "Ports",
Aliases: []string{"p"},
Aliases: []string{"p"},
Usage: "Number of ports to open for the Docker Container",
EnvVars: []string{"NUM_PORTS"},
EnvVars: []string{"NUM_PORTS"},
Destination: &Ports,
},
&cli.BoolFlag{
Name: "GPU",
Aliases: []string{"gpu"},
Aliases: []string{"gpu"},
Usage: "Create Docker Containers to access GPU",
EnvVars: []string{"USE_GPU"},
EnvVars: []string{"USE_GPU"},
Destination: &GPU,
},
&cli.StringFlag{
Name: "Specification",
Aliases: []string{"specs"},
Aliases: []string{"specs"},
Usage: "Specs of the server node",
EnvVars: []string{"SPECS"},
EnvVars: []string{"SPECS"},
Destination: &Specs,
},
&cli.BoolFlag{
Name: "SetDefaultConfig",
Aliases: []string{"dc"},
Aliases: []string{"dc"},
Usage: "Sets a default configuration file",
EnvVars: []string{"SET_DEFAULT_CONFIG"},
EnvVars: []string{"SET_DEFAULT_CONFIG"},
Destination: &SetDefaultConfig,
},
&cli.BoolFlag{
Name: "NetworkInterfaces",
Aliases: []string{"ni"},
Aliases: []string{"ni"},
Usage: "Shows the network interface in your computer",
EnvVars: []string{"NETWORK_INTERFACE"},
EnvVars: []string{"NETWORK_INTERFACE"},
Destination: &NetworkInterface,
},
&cli.BoolFlag{
Name: "ViewPlugins",
Aliases: []string{"vp"},
Aliases: []string{"vp"},
Usage: "Shows plugins available to be executed",
EnvVars: []string{"VIEW_PLUGIN"},
EnvVars: []string{"VIEW_PLUGIN"},
Destination: &ViewPlugin,
},
&cli.BoolFlag{
Name: "TrackedContainers",
Name: "TrackedContainers",
Aliases: []string{"tc"},
Usage: "View containers which have " +
"been created from the client side ",
EnvVars: []string{"TRACKED_CONTAINERS"},
Usage: "View containers which have " +
"been created from the client side ",
EnvVars: []string{"TRACKED_CONTAINERS"},
Destination: &TrackedContainers,
},
&cli.StringFlag{
Name: "ExecutePlugin",
Aliases: []string{"plugin"},
Aliases: []string{"plugin"},
Usage: "Plugin which needs to be executed",
EnvVars: []string{"EXECUTE_PLUGIN"},
EnvVars: []string{"EXECUTE_PLUGIN"},
Destination: &ExecutePlugin,
},
&cli.BoolFlag{
Name: "CreateGroup",
Aliases: []string{"cgroup"},
Aliases: []string{"cgroup"},
Usage: "Creates a new group",
EnvVars: []string{"CREATE_GROUP"},
EnvVars: []string{"CREATE_GROUP"},
Destination: &CreateGroup,
},
&cli.StringFlag{
Name: "Group",
Aliases: []string{"group"},
Aliases: []string{"group"},
Usage: "group flag with argument group ID",
EnvVars: []string{"GROUP"},
EnvVars: []string{"GROUP"},
Destination: &Group,
},
&cli.BoolFlag{
Name: "Groups",
Aliases: []string{"groups"},
Aliases: []string{"groups"},
Usage: "View all groups",
EnvVars: []string{"GROUPS"},
EnvVars: []string{"GROUPS"},
Destination: &Groups,
},
&cli.BoolFlag{
Name: "RemoveContainerGroup",
Aliases: []string{"rmcgroup"},
Aliases: []string{"rmcgroup"},
Usage: "Remove specific container in the group",
EnvVars: []string{"REMOVE_CONTAINER_GROUP"},
EnvVars: []string{"REMOVE_CONTAINER_GROUP"},
Destination: &RemoveContainerGroup,
},
&cli.StringFlag{
Name: "RemoveGroup",
Aliases: []string{"rmgroup"},
Aliases: []string{"rmgroup"},
Usage: "Removes the entire group",
EnvVars: []string{"REMOVE_GROUP"},
EnvVars: []string{"REMOVE_GROUP"},
Destination: &RemoveGroup,
},
// Generate only allowed in dev release
// -- REMOVE ON REGULAR RELEASE --
&cli.StringFlag{
Name: "Generate",
Aliases: []string{"gen"},
Aliases: []string{"gen"},
Usage: "Generates a new copy of P2PRC which can be modified based on your needs",
EnvVars: []string{"GENERATE"},
EnvVars: []string{"GENERATE"},
Destination: &Generate,
},
&cli.StringFlag{
Name: "ModuleName",
Aliases: []string{"mod"},
Aliases: []string{"mod"},
Usage: "New go project module name",
EnvVars: []string{"MODULENAME"},
EnvVars: []string{"MODULENAME"},
Destination: &Modulename,
},
//&cli.BoolFlag{
// Name: "FRPServerProxy",
// Aliases: []string{"proxy"},
// Usage: "Starts proxy for server",
// EnvVars: []string{"FRPSERVERPROXY"},
// Destination: &FRPProxy,
//},
//--------------------------------
&cli.StringFlag{
Name: "PullPlugin",
Aliases: []string{"pp"},
Aliases: []string{"pp"},
Usage: "Pulls plugin from git repos",
EnvVars: []string{"PULLPLUGIN"},
EnvVars: []string{"PULLPLUGIN"},
Destination: &PullPlugin,
},
&cli.StringFlag{
Name: "RemovePlugin",
Aliases: []string{"rp"},
Aliases: []string{"rp"},
Usage: "Removes plugin",
EnvVars: []string{"REMOVEPLUGIN"},
EnvVars: []string{"REMOVEPLUGIN"},
Destination: &RemovePlugin,
},
}
}

View File

@@ -7,25 +7,28 @@ import (
)
var (
defaultPath string
defaults = map[string]interface{}{}
configName = "config"
configType = "json"
configFile = "config.json"
configPaths []string
defaultPath string
defaults = map[string]interface{}{}
configName = "config"
configType = "json"
configFile = "config.json"
configPaths []string
defaultEnvName = "P2PRC"
)
type Config struct {
IPTable string
DockerContainers string
DefaultDockerFile string
SpeedTestFile string
IPV6Address string
PluginPath string
TrackContainersPath string
ServerPort string
MachineName string
IPTable string
DockerContainers string
DefaultDockerFile string
SpeedTestFile string
IPV6Address string
PluginPath string
TrackContainersPath string
ServerPort string
GroupTrackContainersPath string
FRPServerPort string
BehindNAT string
//NetworkInterface string
//NetworkInterfaceIPV6Index int
}
@@ -64,7 +67,7 @@ func Copy(src, dst string) error {
}
// GetPathP2PRC Getting P2PRC Directory from environment variable
func GetPathP2PRC()(string,error) {
func GetPathP2PRC() (string, error) {
curDir := os.Getenv(defaultEnvName)
return curDir + "/", nil
}
@@ -80,40 +83,38 @@ func SetEnvName(EnvName string) error {
}
// GetCurrentPath Getting P2PRC Directory from environment variable
func GetCurrentPath()(string,error) {
func GetCurrentPath() (string, error) {
curDir := os.Getenv("PWD")
return curDir + "/", nil
}
// SetDefaults This function to be called only during a
// make install
func SetDefaults() error {
//Setting current directory to default path
defaultPath, err := GetPathP2PRC()
if err != nil{
if err != nil {
return err
}
//Creates ip_table.json in the json directory
err = Copy("p2p/ip_table.json","p2p/iptable/ip_table.json")
err = Copy("p2p/ip_table.json", "p2p/iptable/ip_table.json")
if err != nil {
return err
}
//Creates a copy of trackcontainers.json in the appropriate directory
err = Copy("client/trackcontainers.json","client/trackcontainers/trackcontainers.json")
err = Copy("client/trackcontainers.json", "client/trackcontainers/trackcontainers.json")
if err != nil {
return err
}
//Creates a copy of trackcontainers.json in the appropriate directory
err = Copy("client/grouptrackcontainers.json","client/trackcontainers/grouptrackcontainers.json")
err = Copy("client/grouptrackcontainers.json", "client/trackcontainers/grouptrackcontainers.json")
if err != nil {
return err
}
//Setting default paths for the config file
defaults["IPTable"] = defaultPath + "p2p/iptable/ip_table.json"
defaults["DefaultDockerFile"] = defaultPath + "server/docker/containers/docker-ubuntu-sshd/"
@@ -124,6 +125,15 @@ func SetDefaults() error {
defaults["TrackContainersPath"] = defaultPath + "client/trackcontainers/trackcontainers.json"
defaults["GroupTrackContainersPath"] = defaultPath + "client/trackcontainers/grouptrackcontainers.json"
defaults["ServerPort"] = "8088"
defaults["FRPServerPort"] = "0"
defaults["BehindNAT"] = "True"
// Random name generator
hostname, err := os.Hostname()
if err != nil {
return err
}
defaults["MachineName"] = hostname
//defaults["NetworkInterface"] = "wlp0s20f3"
//defaults["NetworkInterfaceIPV6Index"] = "2"
@@ -145,18 +155,18 @@ func SetDefaults() error {
return nil
}
func ConfigInit()(*Config,error) {
func ConfigInit() (*Config, error) {
//Setting current directory to default path
defaultPath, err := GetPathP2PRC()
if err != nil{
if err != nil {
return nil, err
}
//Paths to search for config file
configPaths = append(configPaths, defaultPath)
//Add all possible configurations paths
for _,v := range configPaths {
for _, v := range configPaths {
viper.AddConfigPath(v)
}
@@ -164,23 +174,23 @@ func ConfigInit()(*Config,error) {
if err := viper.ReadInConfig(); err != nil {
// If the error thrown is config file not found
//Sets default configuration to viper
for k,v := range defaults {
viper.SetDefault(k,v)
for k, v := range defaults {
viper.SetDefault(k, v)
}
viper.SetConfigName(configName)
viper.SetConfigFile(configFile)
viper.SetConfigType(configType)
if err = viper.WriteConfig(); err != nil {
return nil,err
return nil, err
}
}
// Adds configuration to the struct
var config Config
if err := viper.Unmarshal(&config); err != nil {
return nil,err
return nil, err
}
return &config,nil
return &config, nil
}

12
go.mod
View File

@@ -8,10 +8,11 @@ require (
github.com/containerd/continuity v0.0.0-20210315143101-93e15499afd5 // indirect
github.com/docker/docker v20.10.0-beta1.0.20201113105859-b6bfff2a628f+incompatible
github.com/docker/go-connections v0.4.0
github.com/fatedier/frp v0.45.0
github.com/gin-gonic/gin v1.6.3
github.com/go-git/go-git/v5 v5.4.2
github.com/google/uuid v1.1.2
github.com/gorilla/mux v1.8.0 // indirect
github.com/google/uuid v1.3.0
github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e
github.com/lithammer/shortuuid v3.0.0+incompatible
github.com/moby/sys/mount v0.2.0 // indirect
github.com/moby/term v0.0.0-20201110203204-bea5bbe245bf // indirect
@@ -19,14 +20,11 @@ require (
github.com/otiai10/copy v1.6.0
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2
github.com/shirou/gopsutil/v3 v3.22.10
github.com/spf13/viper v1.4.0
github.com/spf13/viper v1.7.0
github.com/urfave/cli/v2 v2.3.0
gitlab.com/NebulousLabs/fastrand v0.0.0-20181126182046-603482d69e40 // indirect
gitlab.com/NebulousLabs/go-upnp v0.0.0-20181011194642-3a71999ed0d3
golang.org/x/mod v0.3.0
golang.org/x/text v0.3.5 // indirect
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
google.golang.org/grpc v1.35.0 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4
gopkg.in/yaml.v2 v2.4.0
gotest.tools/v3 v3.0.3 // indirect
)

485
go.sum

File diff suppressed because it is too large Load Diff

165
p2p/frp/client.go Normal file
View File

@@ -0,0 +1,165 @@
package frp
import (
"fmt"
"git.sr.ht/~akilan1999/p2p-rendering-computation/server/docker"
"github.com/fatedier/frp/client"
"github.com/fatedier/frp/pkg/config"
"github.com/phayes/freeport"
"math/rand"
"strconv"
"time"
)
// Client This struct stores
// client information with server
// proxy connected
type Client struct {
Name string
Server *Server
ClientMappings []ClientMapping
}
// ClientMapping Stores client mapping ports
// to proxy server
type ClientMapping struct {
LocalIP string
LocalPort int
RemotePort int
}
// StartFRPClientForServer Starts Server using FRP server
// returns back a port
func StartFRPClientForServer(ipaddress string, port string, localport string) (string, error) {
// Setup server information
var s Server
s.address = ipaddress
// convert port to int
portInt, err := strconv.Atoi(port)
if err != nil {
return "", err
}
s.port = portInt
// Setup client information
var c Client
c.Name = "ServerPort"
c.Server = &s
// converts localport to int
portInt, err = strconv.Atoi(localport)
if err != nil {
return "", err
}
//random port
//randPort := rangeIn(10000, 99999)
OpenPorts, err := freeport.GetFreePorts(1)
if err != nil {
return "", err
}
c.ClientMappings = []ClientMapping{
{
LocalIP: "localhost",
LocalPort: portInt,
RemotePort: OpenPorts[0],
},
}
// Start client server
go c.StartFRPClient()
return strconv.Itoa(OpenPorts[0]), nil
}
func StartFRPCDockerContainer(ipaddress string, port string, Docker *docker.DockerVM) (*docker.DockerVM, error) {
// setting new docker variable
//var DockerFRP docker.DockerVM
//DockerFRP = *Docker
//DockerFRP.Ports.PortSet = []docker.Port{}
// Setup server information
var s Server
s.address = ipaddress
// convert port to int
portInt, err := strconv.Atoi(port)
if err != nil {
return nil, err
}
s.port = portInt
// Setup client information
var c Client
c.Name = "ServerPort"
c.Server = &s
// set client mapping
//var clientMappings []ClientMapping
fmt.Println(len(Docker.Ports.PortSet))
for i, _ := range Docker.Ports.PortSet {
portMap := Docker.Ports.PortSet[i].ExternalPort
serverPort, err := GetFRPServerPort("http://" + ipaddress + ":" + port)
if err != nil {
return nil, err
}
//delay to allow the FRP server to start
time.Sleep(1 * time.Second)
proxyPort, err := StartFRPClientForServer(ipaddress, serverPort, strconv.Itoa(portMap))
if err != nil {
return nil, err
}
portInt, err = strconv.Atoi(proxyPort)
if err != nil {
return nil, err
}
Docker.Ports.PortSet[i].ExternalPort = portInt
}
return Docker, nil
}
// StartFRPClient Starts FRP client
func (c *Client) StartFRPClient() error {
cfg := config.GetDefaultClientConf()
var proxyConfs map[string]config.ProxyConf
var visitorCfgs map[string]config.VisitorConf
proxyConfs = make(map[string]config.ProxyConf)
cfg.ServerAddr = c.Server.address
cfg.ServerPort = c.Server.port
for i, _ := range c.ClientMappings {
var tcpcnf config.TCPProxyConf
tcpcnf.LocalIP = c.ClientMappings[i].LocalIP
tcpcnf.LocalPort = c.ClientMappings[i].LocalPort
tcpcnf.RemotePort = c.ClientMappings[i].RemotePort
proxyConfs[tcpcnf.ProxyName] = &tcpcnf
}
cli, err := client.NewService(cfg, proxyConfs, visitorCfgs, "")
if err != nil {
return err
}
cli.Run()
return nil
}
// helper function to generate random
// number in a certain range
func rangeIn(low, hi int) int {
return low + rand.Intn(hi-low)
}

81
p2p/frp/server.go Normal file
View File

@@ -0,0 +1,81 @@
package frp
import (
"github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/server"
"github.com/phayes/freeport"
"io/ioutil"
"net/http"
)
type Server struct {
address string
port int
}
// StartFRPProxyFromRandom starts
// reverse proxy server based on
// a random port generated
func StartFRPProxyFromRandom() (int, error) {
// gets current configuration
//config, err := configP2PRC.ConfigInit()
//if err != nil {
// return err
//}
var s Server
s.address = "0.0.0.0"
// use random port
OpenPorts, err := freeport.GetFreePorts(1)
if err != nil {
return 0, err
}
s.port = OpenPorts[0]
// start FRP server
go s.StartFRPServer()
return OpenPorts[0], nil
}
// StartFRPServer The initial plan is only support reverse proxy
// for TCP ports
// This function starts a server that can act as a reverse
// proxy for nodes behind NAT.
func (s *Server) StartFRPServer() error {
baseConfig := config.GetDefaultServerConf()
baseConfig.BindAddr = s.address
baseConfig.BindPort = s.port
service, err := server.NewService(baseConfig)
if err != nil {
return err
}
service.Run()
return nil
}
// GetFRPServerPort Gets the port no from the FRPServer to establish
// the FRP connection needed.
func GetFRPServerPort(host string) (string, error) {
resp, err := http.Get(host + "/FRPPort")
if err != nil {
return "", err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
return string(body), nil
}

46
p2p/frp/server_test.go Normal file
View File

@@ -0,0 +1,46 @@
package frp
import (
"fmt"
"testing"
"time"
)
// Testing scenario FRPServer
func TestStartFRPServer(t *testing.T) {
var s Server
s.address = "127.0.0.1"
s.port = 8808
err := s.StartFRPServer()
if err != nil {
fmt.Println(err)
t.Fail()
}
}
// Testing scenario FRPServer and FRPClient connection
func TestStartFRPClient(t *testing.T) {
var s Server
s.address = "127.0.0.1"
s.port = 8808
go s.StartFRPServer()
time.Sleep(3 * time.Second)
// Sample test client
var c Client
c.Server = &s
c.ClientMappings = []ClientMapping{
{
LocalIP: "127.0.0.1",
LocalPort: 22,
RemotePort: 3301,
},
}
err := c.StartFRPClient()
if err != nil {
fmt.Println(err)
t.Fail()
}
}

View File

@@ -1,12 +1,13 @@
{
"ip_address": [
{
"ipv4": "139.162.246.221",
"ipv6": "",
"latency": 0,
"download": 0,
"upload": 0,
"serverport": "8088"
"Name": "Node1",
"IPV4": "64.227.168.102",
"IPV6": "",
"Latency": 0,
"ServerPort": "8088",
"NAT": "False",
"EscapeImplementation": "None"
}
]
}
}

View File

@@ -18,12 +18,15 @@ type IpAddresses struct {
}
type IpAddress struct {
Ipv4 string `json:"ipv4"`
Ipv6 string `json:"ipv6"`
Latency time.Duration `json:"latency"`
Download float64 `json:"download"`
Upload float64 `json:"upload"`
ServerPort string `json:"serverport"`
Name string `json:"Name"`
Ipv4 string `json:"IPV4"`
Ipv6 string `json:"IPV6"`
Latency time.Duration `json:"Latency"`
Download float64 `json:"Download"`
Upload float64 `json:"Upload"`
ServerPort string `json:"ServerPort"`
NAT string `json:"NAT"`
EscapeImplementation string `json:"EscapeImplementation"`
}
type IP struct {
@@ -31,19 +34,18 @@ type IP struct {
}
// ReadIpTable Read data from Ip tables from json file
func ReadIpTable()(*IpAddresses ,error){
// Get Path from config
func ReadIpTable() (*IpAddresses, error) {
// Get Path from config
config, err := config.ConfigInit()
if err != nil {
return nil,err
return nil, err
}
jsonFile, err := os.Open(config.IPTable)
// if we os.Open returns an error then handle it
if err != nil {
return nil,err
return nil, err
}
// defer the closing of our jsonFile so that we can parse it later on
defer jsonFile.Close()
@@ -71,6 +73,9 @@ func ReadIpTable()(*IpAddresses ,error){
PublicIP.Ipv4 = ip
PublicIP.Ipv6 = ipv6
PublicIP.ServerPort = config.ServerPort
PublicIP.Name = config.MachineName
PublicIP.NAT = config.BehindNAT
PublicIP.EscapeImplementation = "None"
// Updates current machine IP address to the IP table
ipAddresses.IpAddress = append(ipAddresses.IpAddress, PublicIP)
@@ -80,7 +85,7 @@ func ReadIpTable()(*IpAddresses ,error){
return nil, err
}
return &ipAddresses, nil
return &ipAddresses, nil
}
// WriteIpTable Write to IP table json file
@@ -118,27 +123,38 @@ func PrintIpTable() error {
}
for i := 0; i < len(table.IpAddress); i++ {
fmt.Printf("\nIP Address: %s\nIPV6: %s\nLatency: %s\nServerPort: %s\n-----------" +
"-----------------\n",table.IpAddress[i].Ipv4,table.IpAddress[i].Ipv6,
table.IpAddress[i].Latency, table.IpAddress[i].ServerPort)
fmt.Printf("\nMachine Name: %s\nIP Address: %s\nIPV6: %s\nLatency: %s\nServerPort: %s\nbehindNAT: %s\nEscapeImplementation: %s\n-----------"+
"-----------------\n", table.IpAddress[i].Name, table.IpAddress[i].Ipv4, table.IpAddress[i].Ipv6,
table.IpAddress[i].Latency, table.IpAddress[i].ServerPort, table.IpAddress[i].NAT, table.IpAddress[i].EscapeImplementation)
}
//PrettyPrint(table)
return nil
}
// RemoveDuplicates This is a temporary fix current functions failing to remove
// Duplicate IP addresses from local IP table
func (table *IpAddresses)RemoveDuplicates() error {
func (table *IpAddresses) RemoveDuplicates() error {
var NoDuplicates IpAddresses
for i, _:= range table.IpAddress {
for i, _ := range table.IpAddress {
Exists := false
for k := range NoDuplicates.IpAddress {
if (NoDuplicates.IpAddress[k].Ipv4 != "" && NoDuplicates.IpAddress[k].Ipv4 == table.IpAddress[i].Ipv4) || (NoDuplicates.IpAddress[k].Ipv6 != "" && NoDuplicates.IpAddress[k].Ipv6 == table.IpAddress[i].Ipv6) {
// Statements checked for
// - duplicate IPV4 addresses [<IPV4>:<Port No>]
// - duplicate IPV6 addresses [<IPV6>]
// - Node is behind NAT and no escape implementation provided
if (NoDuplicates.IpAddress[k].Ipv4 != "" && NoDuplicates.IpAddress[k].Ipv4 == table.IpAddress[i].Ipv4 &&
NoDuplicates.IpAddress[k].ServerPort == table.IpAddress[i].ServerPort) ||
(NoDuplicates.IpAddress[k].Ipv6 != "" && NoDuplicates.IpAddress[k].Ipv6 == table.IpAddress[i].Ipv6) {
Exists = true
break
}
}
if table.IpAddress[i].NAT == "True" && table.IpAddress[i].EscapeImplementation == "None" {
Exists = true
}
if Exists {
continue
}
@@ -151,16 +167,16 @@ func (table *IpAddresses)RemoveDuplicates() error {
}
// CurrentPublicIP Get Current Public IP address
func CurrentPublicIP() (string,error) {
func CurrentPublicIP() (string, error) {
req, err := http.Get("http://ip-api.com/json/")
if err != nil {
return "",err
return "", err
}
defer req.Body.Close()
body, err := ioutil.ReadAll(req.Body)
if err != nil {
return "",err
return "", err
}
var ip IP
@@ -171,10 +187,10 @@ func CurrentPublicIP() (string,error) {
// GetCurrentIPV6 gets the current IPV6 address based on the interface
// specified in the config file
func GetCurrentIPV6()(string,error){
func GetCurrentIPV6() (string, error) {
Config, err := config.ConfigInit()
if err != nil {
return "",err
return "", err
}
// Fix in future release
@@ -223,7 +239,7 @@ func ViewNetworkInterface() error {
}
// Ip4or6 Helper function to check if the IP address is IPV4 or
//IPV6 (https://socketloop.com/tutorials/golang-check-if-ip-address-is-version-4-or-6)
// IPV6 (https://socketloop.com/tutorials/golang-check-if-ip-address-is-version-4-or-6)
func Ip4or6(s string) string {
for i := 0; i < len(s); i++ {
switch s[i] {
@@ -235,4 +251,15 @@ func Ip4or6(s string) string {
}
return "version 6"
}
}
//func PrettyPrint(data interface{}) {
// var p []byte
// // var err := error
// p, err := json.MarshalIndent(data, "", "\t")
// if err != nil {
// fmt.Println(err)
// return
// }
// fmt.Printf("%s \n", p)
//}

View File

@@ -1,12 +1,12 @@
package p2p
// SpeedTest Runs a speed test and does updates IP tables accordingly
func (ip *IpAddresses)SpeedTest() error{
func (ip *IpAddresses) SpeedTest() error {
//temp variable to store elements IP addresses and other information
// of IP addresses that are pingable
var ActiveIP IpAddresses
// Index to remove from struct
for _, value := range ip.IpAddress {
@@ -36,7 +36,6 @@ func (ip *IpAddresses)SpeedTest() error{
//Set value to the list
ActiveIP.IpAddress = append(ActiveIP.IpAddress, value)
}
ip.IpAddress = ActiveIP.IpAddress
@@ -50,7 +49,7 @@ func (ip *IpAddresses)SpeedTest() error{
}
// SpeedTestUpdatedIPTable Called when ip tables from httpclient/server is also passed on
func (ip *IpAddresses)SpeedTestUpdatedIPTable() error{
func (ip *IpAddresses) SpeedTestUpdatedIPTable() error {
targets, err := ReadIpTable()
if err != nil {
return err
@@ -59,24 +58,24 @@ func (ip *IpAddresses)SpeedTestUpdatedIPTable() error{
// To ensure struct has no duplicates IP addresses
//DoNotRead := targets
// Appends all IP addresses
// Appends all IP addresses
for i, _ := range targets.IpAddress {
// To ensure that there are no duplicate IP addresses
//Exists := false
//for k := range ip.IpAddress {
// // Checks if both the IPV4 addresses are the same or the IPV6 address is not
// // an empty string and IPV6 address are the same
// if ip.IpAddress[k].Ipv4 == targets.IpAddress[i].Ipv4 || (targets.IpAddress[i].Ipv6 != "" && ip.IpAddress[k].Ipv6 == targets.IpAddress[i].Ipv6) {
// Exists = true
// break
// }
//}
//
//// If the struct exists then continues
//if Exists {
// continue
//}
//To ensure that there are no duplicate IP addresses
Exists := false
for k := range ip.IpAddress {
// Checks if both the IPV4 addresses are the same or the IPV6 address is not
// an empty string and IPV6 address are the same
if (ip.IpAddress[k].Ipv4 == targets.IpAddress[i].Ipv4 && targets.IpAddress[i].NAT == "True") || (targets.IpAddress[i].Ipv6 != "" && ip.IpAddress[k].Ipv6 == targets.IpAddress[i].Ipv6) {
Exists = true
break
}
}
// If the struct exists then continues
if Exists {
continue
}
ip.IpAddress = append(ip.IpAddress, targets.IpAddress[i])
}
@@ -105,7 +104,6 @@ func LocalSpeedTestIpTable() error {
return nil
}
// Helper function to remove element from an array of a struct
//func remove(s []IpAddress, i int) []IpAddress {
// s[len(s)-1], s[i] = s[i], s[len(s)-1]

View File

@@ -2,6 +2,7 @@ package p2p
import (
"bytes"
"errors"
"git.sr.ht/~akilan1999/p2p-rendering-computation/config"
"io"
"io/ioutil"
@@ -12,8 +13,8 @@ import (
"time"
)
//var dlSizes = [...]int{350, 500, 750, 1000, 1500, 2000, 2500, 3000, 3500, 4000}
//var ulSizes = [...]int{100, 300, 500, 800, 1000, 1500, 2500, 3000, 3500, 4000} //kB
// var dlSizes = [...]int{350, 500, 750, 1000, 1500, 2000, 2500, 3000, 3500, 4000}
// var ulSizes = [...]int{100, 300, 500, 800, 1000, 1500, 2500, 3000, 3500, 4000} //kB
var httpclient = http.Client{}
// DownloadTest executes the test to measure download speed
@@ -78,7 +79,7 @@ var httpclient = http.Client{}
//}
// Download Speed
func (s *IpAddress)DownloadSpeed() error {
func (s *IpAddress) DownloadSpeed() error {
start := time.Now()
resp, err := httpclient.Get("http://" + s.Ipv4 + ":8088/50")
if err != nil {
@@ -89,11 +90,11 @@ func (s *IpAddress)DownloadSpeed() error {
t := time.Since(start)
//fmt.Println(s.Seconds())
// size * time (seconds)
s.Download = (50/t.Seconds())*8
return nil
s.Download = (50 / t.Seconds()) * 8
return nil
}
func (s *IpAddress)UploadSpeed() error {
func (s *IpAddress) UploadSpeed() error {
start := time.Now()
// Get upload file path from config file
@@ -103,9 +104,9 @@ func (s *IpAddress)UploadSpeed() error {
return err
}
b, w := createMultipartFormData("file",config.SpeedTestFile)
b, w := createMultipartFormData("file", config.SpeedTestFile)
req, err := http.NewRequest("GET", "http://" + s.Ipv4 + ":" + s.ServerPort + "/upload", &b)
req, err := http.NewRequest("GET", "http://"+s.Ipv4+":"+s.ServerPort+"/upload", &b)
if err != nil {
return err
}
@@ -116,12 +117,12 @@ func (s *IpAddress)UploadSpeed() error {
t := time.Since(start)
//fmt.Println(s.Seconds())
// size * time (seconds)
s.Upload = (50/t.Seconds())*8
s.Upload = (50 / t.Seconds()) * 8
return nil
}
//Upload helper function for uploading
//(https://stackoverflow.com/questions/20205796/post-data-using-the-content-type-multipart-form-data
// Upload helper function for uploading
// (https://stackoverflow.com/questions/20205796/post-data-using-the-content-type-multipart-form-data
func createMultipartFormData(fieldName, fileName string) (bytes.Buffer, *multipart.Writer) {
var b bytes.Buffer
var err error
@@ -142,7 +143,7 @@ func createMultipartFormData(fieldName, fileName string) (bytes.Buffer, *multipa
func mustOpen(f string) *os.File {
r, err := os.Open(f)
if err != nil {
log.Fatalf("Error with mustOpen: %v",err)
log.Fatalf("Error with mustOpen: %v", err)
}
return r
}
@@ -163,8 +164,8 @@ func (s *IpAddress) PingTest() error {
sTime := time.Now()
resp, err := http.Get(pingURL)
fTime := time.Now()
if err != nil {
return err
if err != nil || resp.StatusCode != 200 {
return errors.New("Node not found")
}
if fTime.Sub(sTime) < l {
l = fTime.Sub(sTime)
@@ -176,4 +177,3 @@ func (s *IpAddress) PingTest() error {
return nil
}

View File

@@ -1,76 +1,74 @@
package p2p
import (
"fmt"
"fmt"
"gitlab.com/NebulousLabs/go-upnp"
)
// Port forwarding to the router
func ForwardPort(port int) error{
// connect to router
d, err := upnp.Discover()
if err != nil {
return err
}
func ForwardPort(port int) error {
// connect to router
d, err := upnp.Discover()
if err != nil {
return err
}
// discover external IP
ip, err := d.ExternalIP()
if err != nil {
return err
}
fmt.Println("Your external IP is:", ip)
// discover external IP
ip, err := d.ExternalIP()
if err != nil {
return err
}
fmt.Println("Your external IP is:", ip)
// forward a port
err = d.Forward(50498, "upnp test")
if err != nil {
return err
}
// forward a port
err = d.Forward(50498, "upnp test")
if err != nil {
return err
}
// record router's location
loc := d.Location()
// record router's location
loc := d.Location()
// connect to router directly
d, err = upnp.Load(loc)
if err != nil {
return err
}
// connect to router directly
d, err = upnp.Load(loc)
if err != nil {
return err
}
return nil
return nil
}
// unForwardPort from router
func UnForwardPort(port int) error{
// connect to router
d, err := upnp.Discover()
if err != nil {
return err
}
// UnForwardPort from router
func UnForwardPort(port int) error {
// connect to router
d, err := upnp.Discover()
if err != nil {
return err
}
// discover external IP
ip, err := d.ExternalIP()
if err != nil {
return err
}
// discover external IP
ip, err := d.ExternalIP()
if err != nil {
return err
}
fmt.Println("Your external IP is:", ip)
fmt.Println("Your external IP is:", ip)
// un-forward a port
err = d.Clear(50498)
if err != nil {
return err
}
// record router's location
loc := d.Location()
// un-forward a port
err = d.Clear(50498)
if err != nil {
return err
}
// connect to router directly
d, err = upnp.Load(loc)
if err != nil {
return err
}
// record router's location
loc := d.Location()
// connect to router directly
d, err = upnp.Load(loc)
if err != nil {
return err
}
return nil
return nil
}

15
p2p/upnp_test.go Normal file
View File

@@ -0,0 +1,15 @@
package p2p
import (
"fmt"
"testing"
)
// Tests if the current has UPNP support
func TestForwardUPNPPort(t *testing.T) {
err := ForwardPort(6586)
if err != nil {
fmt.Println(err)
t.Fail()
}
}

Binary file not shown.

View File

@@ -3,29 +3,39 @@ package server
import (
"encoding/json"
"fmt"
"git.sr.ht/~akilan1999/p2p-rendering-computation/client/clientIPTable"
"git.sr.ht/~akilan1999/p2p-rendering-computation/config"
"git.sr.ht/~akilan1999/p2p-rendering-computation/p2p"
"git.sr.ht/~akilan1999/p2p-rendering-computation/p2p/frp"
"git.sr.ht/~akilan1999/p2p-rendering-computation/server/docker"
"github.com/gin-gonic/gin"
"io/ioutil"
"net/http"
"strconv"
"time"
)
func Server() error{
func Server() error {
r := gin.Default()
//Get Server port based on the config file
config, err := config.ConfigInit()
if err != nil {
return err
}
// update IPTable with new port and ip address and update ip table
var ProxyIpAddr p2p.IpAddress
var lowestLatencyIpAddress p2p.IpAddress
// Gets default information of the server
r.GET("/server_info", func(c *gin.Context) {
c.JSON(http.StatusOK, ServerInfo())
})
// Speed test with 50 mbps
r.GET("/50", func(c *gin.Context){
r.GET("/50", func(c *gin.Context) {
// Get Path from config
config, err := config.ConfigInit()
if err != nil {
c.String(http.StatusOK, fmt.Sprint(err))
}
c.File(config.SpeedTestFile)
})
@@ -71,7 +81,7 @@ func Server() error{
c.String(http.StatusOK, fmt.Sprint(err))
}
json.Unmarshal(file,&IPTable)
json.Unmarshal(file, &IPTable)
//Add Client IP address to IPTable struct
IPTable.IpAddress = append(IPTable.IpAddress, ClientHost)
@@ -83,7 +93,7 @@ func Server() error{
}
// Reads IP addresses from ip table
IpAddresses,err := p2p.ReadIpTable()
IpAddresses, err := p2p.ReadIpTable()
if err != nil {
c.String(http.StatusOK, fmt.Sprint(err))
}
@@ -91,31 +101,40 @@ func Server() error{
c.JSON(http.StatusOK, IpAddresses)
})
// Starts docker container in server
// Starts docker container in server
r.GET("/startcontainer", func(c *gin.Context) {
// Get Number of ports to open and whether to use GPU or not
Ports := c.DefaultQuery("ports","0")
GPU := c.DefaultQuery("GPU","false")
ContainerName := c.DefaultQuery("ContainerName","")
var PortsInt int
Ports := c.DefaultQuery("ports", "0")
GPU := c.DefaultQuery("GPU", "false")
ContainerName := c.DefaultQuery("ContainerName", "")
var PortsInt int
// Convert Get Request value to int
fmt.Sscanf(Ports, "%d", &PortsInt)
// Creates container and returns-back result to
// access container
resp, err := docker.BuildRunContainer(PortsInt,GPU,ContainerName)
resp, err := docker.BuildRunContainer(PortsInt, GPU, ContainerName)
if err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
}
// Ensures that FRP is triggered only if a proxy address is provided
if ProxyIpAddr.Ipv4 != "" && c.Request.Host != "localhost:"+config.ServerPort && c.Request.Host != "0.0.0.0:"+config.ServerPort {
resp, err = frp.StartFRPCDockerContainer(ProxyIpAddr.Ipv4, lowestLatencyIpAddress.ServerPort, resp)
if err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
}
fmt.Println(resp)
}
c.JSON(http.StatusOK, resp)
})
//Remove container
r.GET("/RemoveContainer", func(c *gin.Context) {
ID := c.DefaultQuery("id","0")
ID := c.DefaultQuery("id", "0")
if err := docker.StopAndRemoveContainer(ID); err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
}
@@ -131,10 +150,73 @@ func Server() error{
c.JSON(http.StatusOK, resp)
})
//Get Server port based on the config file
config, err := config.ConfigInit()
if err != nil {
return err
// Request for port no from Server with address
r.GET("/FRPPort", func(c *gin.Context) {
port, err := frp.StartFRPProxyFromRandom()
if err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
}
c.String(http.StatusOK, strconv.Itoa(port))
})
// If there is a proxy port specified
// then starts the FRP server
//if config.FRPServerPort != "0" {
// go frp.StartFRPProxyFromRandom()
//}
// TODO check if IPV6 or Proxy port is specified
// if not update current entry as proxy address
// with appropriate port on IP Table
if config.BehindNAT == "True" {
table, err := p2p.ReadIpTable()
if err != nil {
return err
}
var lowestLatency int64
// random large number
lowestLatency = 10000000
for i, _ := range table.IpAddress {
// Checks if the ping is the lowest and if the following node is acting as a proxy
//if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && table.IpAddress[i].ProxyPort != "" {
if table.IpAddress[i].Latency.Milliseconds() < lowestLatency {
lowestLatency = table.IpAddress[i].Latency.Milliseconds()
lowestLatencyIpAddress = table.IpAddress[i]
}
}
// If there is an identified node
if lowestLatency != 10000000 {
serverPort, err := frp.GetFRPServerPort("http://" + lowestLatencyIpAddress.Ipv4 + ":" + lowestLatencyIpAddress.ServerPort)
if err != nil {
return err
}
// Create 3 second delay to allow FRP server to start
time.Sleep(1 * time.Second)
// Starts FRP as a client with
proxyPort, err := frp.StartFRPClientForServer(lowestLatencyIpAddress.Ipv4, serverPort, config.ServerPort)
if err != nil {
return err
}
// updating with the current proxy address
ProxyIpAddr.Ipv4 = lowestLatencyIpAddress.Ipv4
ProxyIpAddr.ServerPort = proxyPort
ProxyIpAddr.Name = config.MachineName
ProxyIpAddr.NAT = "False"
ProxyIpAddr.EscapeImplementation = "FRP"
// append the following to the ip table
table.IpAddress = append(table.IpAddress, ProxyIpAddr)
// write information back to the IP Table
table.WriteIpTable()
// update ip table
go clientIPTable.UpdateIpTableListClient()
}
}
// Run gin server on the specified port