Initial commit

This commit is contained in:
Denis-Cosmin Nutiu 2017-10-20 18:08:25 +03:00
commit 9757016561
5 changed files with 223 additions and 0 deletions

27
server/main.go Normal file
View file

@ -0,0 +1,27 @@
package main
import (
"net"
"log"
"github.com/metonimie/simpleFTP/server/server"
)
func main() {
listener, err := net.Listen("tcp", "localhost:8080")
if err != nil {
log.Fatal(err)
}
log.Println("Hello world!")
log.Println("Running on:", "localhost", "port", "8080")
for {
conn, err := listener.Accept()
if err != nil {
log.Print(err)
continue
}
go server.HandleConnection(conn)
}
}

73
server/server/commands.go Normal file
View file

@ -0,0 +1,73 @@
package server
import (
"net"
"strings"
"os"
"log"
"io/ioutil"
"bytes"
"strconv"
)
// PATH is the constant which should contain the fixed path where the simpleFTP server will run
// This will act like a root cage.
const PATH = "/Users/denis/GoglandProjects/golangBook/GoRoutines/"
// SendFile sends the file to the client and returns true if it succeeds and false otherwise.
func SendFile(c net.Conn, path string) (int, error) {
var fileName string
// Make sure the user can't request any files on the system.
lastForwardSlash := strings.LastIndex(path, "/")
if lastForwardSlash != -1 {
// Eliminate the last forward slash i.e ../../asdas will become asdas
fileName = path[lastForwardSlash + 1:]
} else {
fileName = path
}
file, err := os.Open(PATH + fileName)
if err != nil {
// Open file failed.
log.Println(err)
return 0, err
}
defer file.Close() // Closing the fd when the function has exited.
data, err := ioutil.ReadAll(file)
n, err := c.Write(data)
if err != nil {
log.Println(err)
return 0, err
}
// How is this even possible?
if n == 0 {
log.Println("0 bits written for:", path)
return 0, nil
}
return n, nil
}
// ListFiles list the files from path and sends them to the connection
func ListFiles(c net.Conn) error {
files, err := ioutil.ReadDir(PATH)
if err != nil {
return err;
}
buffer := bytes.NewBufferString("Directory Mode Size LastModified Name\n")
for _, f := range files {
buffer.WriteString(strconv.FormatBool(f.IsDir()) + " " + string(f.Mode().String()) + " " +
strconv.FormatInt(f.Size(), 10) + " " + f.ModTime().String() + " " + string(f.Name()) + " " + "\n")
}
_, err = c.Write(buffer.Bytes())
if err != nil {
return err
}
return nil
}

View file

@ -0,0 +1,30 @@
package server
import (
"net"
"io"
"log"
"bufio"
)
func HandleConnection(c net.Conn) {
defer c.Close()
io.WriteString(c, "Hello and welcome to simple ftp\n")
log.Println(c.RemoteAddr(), "has connected.")
// Process input
input := bufio.NewScanner(c)
for input.Scan() {
log.Println(c.RemoteAddr(), ":", input.Text())
err := ProcessInput(c, input.Text())
if err != nil {
log.Println(err)
io.WriteString(c, err.Error()+"\n")
}
}
// Client has left.
log.Println(c.RemoteAddr(), "has disconnected.")
}

19
server/server/errors.go Normal file
View file

@ -0,0 +1,19 @@
package server
import "errors"
// InputError will be raised when the input is not right.
type InputError struct {
// The operation that caused the error.
Op string
// The error that occurred during the operation.
Err error
}
func (e *InputError) Error() string { return "Error: " + e.Op + ": " + e.Err.Error() }
var (
InvalidCommand = errors.New("Invalid command.")
TooManyArguments = errors.New("Too many arguments.")
TooFewArguments = errors.New("Too few arguments.")
)

74
server/server/parser.go Normal file
View file

@ -0,0 +1,74 @@
package server
import (
"net"
"strings"
)
// checkArgumentsLength returns an error if length is not equal to expected.
func checkArgumentsLength(length int, expected int) error {
if length > expected {
return TooManyArguments
} else if length < expected {
return TooFewArguments
}
return nil
}
func ProcessInput(c net.Conn, text string) error {
commands := strings.Fields(text)
commandsLen := len(commands)
// Possibly empty input, just go on.
if commandsLen == 0 {
return nil
}
switch commands[0] {
case "get":
// Check arguments
err := checkArgumentsLength(commandsLen, 2)
if err != nil {
return &InputError{commands[0], err}
}
// Get the file
_, err = SendFile(c, commands[1])
if err != nil {
return &InputError{"SendFile", err}
}
case "ls":
// Check arguments
err := checkArgumentsLength(commandsLen, 1)
if err != nil {
return &InputError{commands[0], err}
}
err = ListFiles(c)
if err != nil {
return &InputError{commands[0], err}
}
case "clear":
// Check arguments
err := checkArgumentsLength(commandsLen, 1)
if err != nil {
return &InputError{commands[0], err}
}
// Ansi clear: 1b 5b 48 1b 5b 4a
// clear | hexdump -C
var b []byte = []byte{0x1b, 0x5b, 0x48, 0x1b, 0x5b, 0x4a}
c.Write(b)
case "exit":
err := checkArgumentsLength(commandsLen, 1)
if err != nil {
return &InputError{commands[0], err}
}
c.Close()
default:
return &InputError{commands[0], InvalidCommand}
}
return nil
}