diff --git a/.gitignore b/.gitignore
index 1c6283f8e4841cd471b0ed9fc11985f052ab6e73..809a03352956e45112fe7a17d704cf2d27f05445 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
 *.o
 cacoclient
-cacoserver
\ No newline at end of file
+cacoserver
+*.txt
diff --git a/Makefile b/Makefile
index b76d9812bd4615d9d6eea2e56b60bb0da1ae0947..b1472c1b95180a8194dd7905b9906560cafc7b13 100644
--- a/Makefile
+++ b/Makefile
@@ -1,13 +1,15 @@
-CFLAGS= -g -Wall -O2
+CXXFLAGS= -w -g -Wall -O2 -std=c++11
 CC=g++
 
-OBJ=Protocol.o
+OBJ=Protocol.o Message.o
+
+all: cacoclient cacoserver
 
 %.o: %.cpp
-	$(CC) $(CFLAGS) $^ -c -o $@
+	$(CC) $(CXXFLAGS) $^ -c -o $@
 cacoclient: client.cpp $(OBJ)
-	$(CC) $(CFLAGS) $^ -o $@
-# cacoserver: $(OBJ) client.cpp
-# 	$(CC) $(CFLAGS) $^ -o $@
+	$(CC) $(CXXFLAGS) $^ -o $@
+cacoserver: server.cpp $(OBJ)
+	$(CC) $(CXXFLAGS) $^ -o $@
 clean:
 	rm -f *.o caco*
diff --git a/Message.cpp b/Message.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4a303edb96d9f40995dc6010a581c85729ae49bb
--- /dev/null
+++ b/Message.cpp
@@ -0,0 +1,91 @@
+#include "Message.h"
+#include "definitions.h"
+
+BYTE Message::calcParity() {
+    BYTE parity = 0x00;
+    vector<BYTE> m = getMessage();
+    //Begin and parity bytes are not taken in account in parity
+    for(int i=1; i < m.size()-1; ++i) {
+        parity = parity^m[i];
+    }
+    this->parity = parity;
+    return parity;
+}
+
+bool Message::checkParity() {
+    BYTE parity = this->calcParity();
+    return (parity == this->parity.to_ulong());
+}
+
+void Message::setBitFields(BYTE begin, BYTE sizeSeq, BYTE seqType, BYTE parity){
+    //if the size of val passed in the bitset constructor is greater than the bitset size,
+    // only the least significant bits of val are taken into consideration.
+    // cout << "Input:\t" << bitset<8>(sizeSeq) << "\t" << bitset<8>(seqType);
+    // cout << "Set bitFields:\t";
+    this->begin = bitset<BEGIN_S>(begin);
+    this->size = bitset<SIZE_S>(sizeSeq >> 2);
+    // cout << size << "\t";
+    this->sequence = bitset<SEQUENCE_S>((sizeSeq << 4) | (seqType >> 4));
+    // cout << sequence << "\t";
+    this->type = bitset<TYPE_S>(seqType);
+    // cout << type << endl;
+    this->parity = bitset<PARITY_S>(parity);
+}
+
+vector<BYTE> Message::getBitFieldsAsBytes(){
+    vector<BYTE> bitFields;
+    bitFields.push_back((BYTE)begin.to_ulong());
+    // bitFields.push_back((BYTE)size.to_ulong());
+    // bitFields.push_back((BYTE)sequence.to_ulong());
+    // bitFields.push_back((BYTE)type.to_ulong());
+    string str = size.to_string();
+    str += sequence.to_string();
+    str += type.to_string();
+    // cout << "str:" << str << "\t" << (BYTE)bitset<8>(str.substr(8,8)).to_ulong() << endl;
+    bitFields.push_back((BYTE)bitset<8>(str.substr(0,8)).to_ulong());
+    bitFields.push_back((BYTE)bitset<8>(str.substr(8,8)).to_ulong());
+    bitFields.push_back((BYTE)parity.to_ulong());
+    return bitFields;
+}
+
+vector<BYTE> Message::getMessage(){
+    vector<BYTE> msg = getBitFieldsAsBytes();
+    msg.insert(msg.end()-1, data.begin(), data.end());
+    // cout << "getMessage:\n";
+    // for(int i=0; i < msg.size(); ++i) {
+    //     cout << bitset<8>(msg[i]);
+    // }
+    // cout<<endl;
+    return msg;
+}
+
+char* Message::getMessageAsCharPointer(){
+    return reinterpret_cast<char*> (getMessage().data());
+}
+
+int Message::getMessageSize(){
+    return size.to_ulong() < MINSIZE ? MINSIZE+4 : size.to_ulong()+4;
+}
+
+int Message::dataToInt() {
+    string str(data.begin(), data.end());
+    return stoi(str);
+}
+
+string Message::getDataAsString() {
+    string str(data.begin(), data.end());
+    return str;
+}
+
+ostream& operator<<(ostream& os, const Message& msg){
+    os << '|' << msg.begin << '|' << msg.size << '|' << msg.sequence << '|' << msg.type << '|';
+    for(int i=0; i<msg.data.size(); ++i){
+        os << bitset<8>(msg.data[i]);
+    }
+    os << '|' << msg.parity << '|';
+    return os;
+}
+
+Message::Message() {
+    this->begin = bitset<BEGIN_S>(BEGIN);
+}
diff --git a/Message.h b/Message.h
new file mode 100644
index 0000000000000000000000000000000000000000..6056953d4633ff2bbac5bbf5170d04767767a87e
--- /dev/null
+++ b/Message.h
@@ -0,0 +1,28 @@
+#ifndef __MESSAGE__
+#define __MESSAGE__
+#include "definitions.h"
+
+class Message {
+
+public:
+    bitset<BEGIN_S> begin;
+    bitset<SIZE_S> size;
+    bitset<SEQUENCE_S> sequence;
+    bitset<TYPE_S> type;
+    bitset<PARITY_S> parity;
+    vector<BYTE> data;
+
+    BYTE calcParity();
+    bool checkParity();
+    void setBitFields(BYTE begin, BYTE sizeSeq, BYTE seqType, BYTE parity);
+    vector<BYTE> getBitFieldsAsBytes();
+    vector<BYTE> getMessage();
+    char* getMessageAsCharPointer();
+    int getMessageSize();
+    int dataToInt();
+    string getDataAsString();
+
+    Message();
+};
+ostream& operator<<(ostream& os, const Message& msg);
+#endif
diff --git a/Protocol.cpp b/Protocol.cpp
index 146b712f302a1343e162fa56aad749db12eb3daf..93f1f4a768fb6ce6630e58a2069cf1ae4d2e2d3a 100644
--- a/Protocol.cpp
+++ b/Protocol.cpp
@@ -1,14 +1,258 @@
+#include <sys/socket.h>
+#include <sys/time.h>
 #include "Protocol.h"
 #include "definitions.h"
 
-Message Protocol::getMessage(){
-    return message;
+typedef struct{
+    int index;
+    bool sent;
+}FrameItem;
+
+double timestamp(void) {
+    struct timeval tp;
+    gettimeofday(&tp, NULL);
+    return ((double)(tp.tv_sec + tp.tv_usec/1000000.0));
+}
+
+void printErrors(char error){
+	if(error == DIR_ERR){
+		cout << "Arquivo ou diretório inexistente."<<endl;
+	}else if(error == PERM_ERR){
+		cout << "Você não tem permissão."<<endl;
+	}else if(error == SPACE_ERR){
+		cout << "Espaço insuficiente no disco."<<endl;
+	}
+}
+
+vector<Message> Protocol::getMessages(){
+    return messages;
+}
+
+void Protocol::setMessages(vector<Message> messages){
+    this->messages = messages;
+}
+
+bool Protocol::sendMessages(int socket) {
+    bool success = true;
+    for(int i=0; i < messages.size(); ++i) {
+        int status = sendMessage(socket, i);
+        if(status < 0) {
+            success = false;
+        }
+    }
+    return success;
+}
+
+bool Protocol::sendMessage(int socket, int index) {
+    // cout << "message sent: " << messages[index] << endl;
+    vector<BYTE> message = messages[index].getMessage();
+    unsigned char* msg = reinterpret_cast<unsigned char*> (message.data());
+    int status = send(socket, msg, messages[index].getMessageSize(), 0);
+    return (status >= 0);
+}
+
+vector<BYTE> Protocol::getData(){
+    vector<BYTE> fullData;
+    for (int i=0; i < messages.size(); ++i){
+        fullData.insert(fullData.end(), messages[i].data.begin(), messages[i].data.end());
+    }
+    return fullData;
+}
+
+string Protocol::getDataAsString(){
+    vector<BYTE> fullData = getData();
+    string str(fullData.begin(), fullData.end());
+    return str;
 }
 
-void Protocol::setMessage(Message message){
-    this->message = message;
+int Protocol::setData(vector<BYTE> data, int type){
+    vector<BYTE>::const_iterator first, last;
+    int i;
+    for (i=0; i <= ((int)data.size())-MAXSIZE; i+=MAXSIZE){
+        Message msg = Message();
+        msg.size = bitset<SIZE_S>(MAXSIZE);
+        msg.sequence = bitset<SEQUENCE_S>(messages.size()%(MAXSIZE+1));
+        msg.type = bitset<TYPE_S>(type);
+        first = data.begin()+i;
+        last = data.begin()+i+MAXSIZE+1;
+        vector<BYTE> subvector(first, last);
+        msg.data = subvector;
+        msg.calcParity();
+        messages.push_back(msg);
+    }
+    if(i < data.size()){
+        Message msg = Message();
+        msg.sequence = bitset<SEQUENCE_S>(messages.size()%(MAXSIZE+1));
+        msg.type = bitset<TYPE_S>(type);
+        int size = ((int)data.size())-i;
+        first = data.begin()+i;
+        last = data.begin()+i+size+1;
+        vector<BYTE> subvector(first, last);
+        msg.data = subvector;
+        msg.size = bitset<SIZE_S>(size);
+        msg.calcParity();
+        if(size < MINSIZE){
+            BYTE zero = 0x00;
+            msg.data.insert(msg.data.end(), MINSIZE-size, zero);
+        }
+        msg.size = bitset<SIZE_S>(size);
+        msg.calcParity();
+        messages.push_back(msg);
+    }
+    return messages.size();
+}
+
+int Protocol::recvMessage(int sockt){
+    BYTE dataRec[MAXSIZE+4];
+    int r = recv(sockt, dataRec, MAXSIZE+4, 0);
+    // cout << "begin: "<< bitset<8>(dataRec[0]) <<endl;
+    // cout << "recv response: " << r << endl;
+    if(dataRec[0] != BEGIN){
+        return NOISE;
+    }
+    Message msg = Message();
+    int size = (int)(dataRec[1]>>2);
+    // cout << "Tamanho:" << size << "\t";
+    int dataSize = size < MINSIZE ? MINSIZE : size;
+    msg.setBitFields(dataRec[0], dataRec[1], dataRec[2], dataRec[dataSize+3]);
+    // cout << "Sequence:" << msg.sequence.to_ulong() << "\t";
+    BYTE msgData[size];
+    memcpy(msgData,dataRec+3,size);
+    msg.data.insert(msg.data.end(), msgData, msgData+size);
+
+    messages.push_back(msg);
+    // cout << "Tipo:" << (int)msg.type.to_ulong() << endl;
+
+    // cout <<"message received: "<< msg<<endl;
+    if(!msg.checkParity()){
+        return INCONSISTENT;
+    }
+    return (int)msg.type.to_ulong();
+}
+
+void Protocol::transmit(int sockt, int window){
+    int status;
+    vector<FrameItem> frame;
+    int lastFramed = -1;
+    setData(vector<BYTE>(1, 0), ENDTX);
+    int messagesLeft = messages.size();
+    Protocol response;
+    double t0 = 0.0;
+    bool timeout = false;
+    while(messagesLeft > 0){
+        cout << "Restantes: " << messagesLeft << endl;
+        for(int j=0; j < window; ++j) {
+            if(frame.size() < window && frame.size() < messagesLeft) {
+                // cout << "frame size: " << frame.size() << endl;
+                FrameItem fi = {.index = ++lastFramed, .sent=false};
+                // cout << "lastFramed: " << fi.index << endl;
+                frame.push_back(fi);
+            }
+            if(!frame[j].sent || timeout){
+                sendMessage(sockt, frame[j].index);
+                frame[j].sent = true;
+                t0 = timestamp();
+            }
+        }
+        // TODO: timeout
+        status = response.recvMessage(sockt);
+        // cout << "transmit status:" << status << endl;
+        if(status == NACK){
+            // printf("nstoi %i\n", response.getMessages().back().getDataAsString()[0]);
+            int nackIndex = response.getMessages().back().getDataAsString()[0];
+            for(int j=0; j < window;) {
+                if(frame[j].index < nackIndex) {
+                    frame.erase(frame.begin() + j);
+                    --messagesLeft;
+                } else if(frame[j].index == nackIndex) {
+                    frame[j].sent = false;
+                } else ++j;
+            }
+            response.reset();
+            t0 = timestamp();
+
+        }else if(status == ACK){
+            // printf("astoi %i\n", response.getMessages().back().getDataAsString()[0]);
+            int ackIndex = response.getMessages().back().getDataAsString()[0];
+            for(int j=0; j < frame.size();) {
+                // cout << "ackIndex: " << ackIndex << "frame[j].index: " << frame[j].index << endl;
+                if(ackIndex == 0) {
+                    if((frame[j].index % (MAXSIZE+1)) == 62 || (frame[j].index % (MAXSIZE+1)) == 63 || (frame[j].index % (MAXSIZE+1)) == 0) {
+                        frame.erase(frame.begin() + j);
+                        --messagesLeft;
+                    } else ++j;
+                } else if((frame[j].index % (MAXSIZE+1)) <= ackIndex) {
+                    frame.erase(frame.begin() + j);
+                    --messagesLeft;
+                } else ++j;
+            }
+            response.reset();
+            t0 = timestamp();
+        } else {
+            //TODO: treat error
+        }
+        timeout = ((timestamp() - t0) > 2.0);
+        if(timeout) cout << "TIMEOUT!\n";
+    }
+    reset();
+}
+
+int Protocol::receive(int sockt, int type, int window, bool dataEndable){
+    int status, nextSequence = 0;
+    vector<int> frame;
+    Protocol response;
+    bool shouldSend = false;
+    int end = ((dataEndable)? ENDTX : type);
+    do{
+        if(shouldSend){
+            response.sendMessages(sockt);
+            response.reset();
+            shouldSend = false;
+        }
+        status = recvMessage(sockt);
+        // cout << "receive status:" << status << endl;
+        // cout << "sequence: "<<messages.back().sequence.to_ulong()<<" next: "<<nextSequence<<endl;
+        if(status == NOISE){
+            continue;
+        } else if(status == type) {
+            if(!messages.empty() && (messages.back().sequence.to_ulong() != nextSequence)){
+                messages.pop_back();
+                response.reset();
+                vector<BYTE> val(1,(BYTE)nextSequence);
+                response.setData(val, NACK);
+                shouldSend = true;
+            } else {
+                if(window == WAIT_STOP || ((nextSequence % SLIDING) == 0)) {
+                    response.reset();
+                    vector<BYTE> val(1,(BYTE)messages.back().sequence.to_ulong());
+                    response.setData(val, ACK);
+                    shouldSend = true;
+                }
+                nextSequence = (messages.back().sequence.to_ulong()+1)%(MAXSIZE+1);
+            }
+        } else if(status == ERROR) {
+            cout << "ERROR: ";
+            printErrors(messages.back().data[0]);
+            return -1;
+        }
+    }while(status != end);
+    if(dataEndable){
+        response.reset();
+        vector<BYTE> val(1,(BYTE)messages.back().sequence.to_ulong());
+        response.setData(val, ACK);
+        response.sendMessages(sockt);
+        messages.pop_back();
+    }
+    return 0;
+}
+
+void Protocol::addMessage(Message msg) {
+    messages.push_back(msg);
+}
+
+void Protocol::reset(){
+    messages.clear();
 }
 
 Protocol::Protocol(){
-    message.begin = 0x7E;
-}
\ No newline at end of file
+}
diff --git a/Protocol.h b/Protocol.h
index e361922f0e2f21ab896e7b90b6d3738fa6be00f1..fba73fb378af1e9ea6cb50c272430898a55eb5c1 100644
--- a/Protocol.h
+++ b/Protocol.h
@@ -1,17 +1,26 @@
 #ifndef __PROTOCOL__
 #define __PROTOCOL__
 #include "definitions.h"
+#include "Message.h"
 
 class Protocol{
 
 private:
-    Message message;
-    vector<char> data;
+    vector<Message> messages;
 public:
-
-    Message getMessage();
-    void setMessage(Message message);
+    bool sendMessages(int socket);
+    bool sendMessage(int socket, int index);
+    vector<Message> getMessages();
+    void setMessages(vector<Message> messages);
+    vector<BYTE> getData();
+    int setData(vector<BYTE> data, int type);
+    string getDataAsString();
+    int recvMessage(int sockt);
+    void addMessage(Message msg);
+    void transmit(int sockt, int window);
+    int receive(int sockt, int type, int window, bool dataEndable);
+    void reset();
 
     Protocol();
 };
-#endif
\ No newline at end of file
+#endif
diff --git a/client.cpp b/client.cpp
index febcc73f0af06f7951e6da9e6bce9af3bf26fc53..4fb1167842f7048c367e3ab25329cd30ceddcba0 100644
--- a/client.cpp
+++ b/client.cpp
@@ -1,32 +1,122 @@
+#include <stdexcept>
 #include "definitions.h"
 #include "dirFunctions.h"
 #include "ConexaoRawSocket.c"
+#include "Protocol.h"
 
-int main(){
+void printCommandsList();
 
-    int socket = ConexaoRawSocket(DEVICE);
-    
+int main(){
+    int pos, sockt = ConexaoRawSocket(DEVICE);
+    string line, command, args;
+    Protocol receiveProtocol, sendProtocol;
+    printCommandsList();
     while(true){
-        string command, path;
         cout << endl << "Entre com o comando:" << endl;
-        cin >> command;
-        if(command == "quit"){
-            break;
+        getline(cin,line);
+        pos = line.find_first_of(" ");
+        if(pos == string::npos){
+            pos = line.size();
         }
-        cin >> path;
-        if(command == "cd"){
-            cd(path);
-        }else if(command == "ls"){
-            ls(path);
-        }else if(command == "cdr"){
-            //TODO
-        }else if(command == "lsr"){
-            //TODO
-        }else if(command == "put"){
-            //TODO
-        }else if(command == "get"){
-            //TODO
+        command = line.substr(0,pos);
+        try{
+            if(command == "quit"){
+                break;
+            }
+            if(command == "cd"){
+                args = line.substr(pos+1, line.size());
+                cd(args);
+            }else if(command == "ls"){
+                cout << ls(line);
+            }else if(command == "cdr"){
+                args = line.substr(pos+1, line.size());
+                sendProtocol.setData(vector<BYTE>(args.begin(), args.end()), CD);
+                sendProtocol.sendMessage(sockt, 0);
+                receiveProtocol.receive(sockt, OK, WAIT_STOP, false);
+                cout << "Diretório remoto: " << args;
+            }else if(command == "lsr"){
+                line.replace(line.find("lsr"), string("lsr").length(), "ls");
+                sendProtocol.setData(vector<BYTE>(line.begin(), line.end()), LS);
+                sendProtocol.sendMessage(sockt,0);
+                cout << "Remoto:\n";
+                receiveProtocol.receive(sockt, OUTPUT, WAIT_STOP, true);
+                cout << receiveProtocol.getDataAsString() << endl;
+            }else if(command == "put"){
+                args = line.substr(pos+1, line.size());
+                if(fexists(args)) {
+                    string size = to_string(filesize(args));
+                    // cout << "ARQUIVO: " << args << "|\tTAMANHO:" << size << endl;
+                    sendProtocol.setData(vector<BYTE>(args.begin(), args.end()), PUT);
+                    sendProtocol.sendMessage(sockt, 0);
+                    int error = receiveProtocol.receive(sockt, OK, WAIT_STOP, false);
+                    if(error < 0) continue;
+                    sendProtocol.reset();
+                    sendProtocol.setData(vector<BYTE>(size.begin(), size.end()), SIZE);
+                    sendProtocol.sendMessage(sockt, 0);
+                    error = receiveProtocol.receive(sockt, OK, WAIT_STOP, false);
+                    if(error < 0) continue;
+                    sendProtocol.reset();
+                    ifstream putFile (args);
+                    stringstream buffer;
+                    buffer << putFile.rdbuf();
+                    string data = buffer.str();
+                    sendProtocol.setData(vector<BYTE>(data.begin(), data.end()), DATA);
+                    sendProtocol.transmit(sockt, SLIDING);
+                } else {
+                    cout << "ERROR: arquivo não existe\n";
+                }
+                sendProtocol.reset();
+                receiveProtocol.reset();
+            }else if(command == "get"){
+                args = line.substr(pos+1, line.size());
+                sendProtocol.setData(vector<BYTE>(args.begin(), args.end()), GET);
+                sendProtocol.sendMessage(sockt, 0);
+                int error = receiveProtocol.receive(sockt, SIZE, WAIT_STOP, false);
+                if(error < 0) continue;
+                string s_size = receiveProtocol.getDataAsString();
+                cout << s_size << endl;
+                unsigned int fileSize = stoi(s_size);
+                // cout << "Tamanho: " << fileSize << endl;
+                sendProtocol.reset();
+                if(hasEnoughSpace(fileSize)) {
+                    sendProtocol.setData(vector<BYTE>(1,(BYTE)0), OK);
+                    sendProtocol.sendMessage(sockt,0);
+                } else {
+                    cout << "ERROR: não há espaço disponível\n";
+                    sendProtocol.setData(vector<BYTE>(1,(BYTE)SPACE_ERR), ERROR);
+                    sendProtocol.sendMessage(sockt,0);
+                    continue;
+                }
+                receiveProtocol.reset();
+                receiveProtocol.receive(sockt,DATA,SLIDING,true);
+                writeFile(getWorkingPath()+"/"+args,receiveProtocol.getData());
+                sendProtocol.reset();
+                receiveProtocol.reset();
+            }else if(command == "help"){
+                printCommandsList();
+            }else{
+                cout << "Comando inexistente." << endl;
+                printCommandsList();
+            }
+        }catch(char const* strException){
+            cerr<<"Error: "<< strException << endl;
+        }catch(out_of_range e){
+            cerr<<"Error: Esse comando requer argumentos."<<endl;
         }
+        sendProtocol.reset();
+        receiveProtocol.reset();
     }
     return 0;
-}
\ No newline at end of file
+}
+
+void printCommandsList(){
+    cout << "Os comandos suportados são:"<< endl;
+    cout << "cd - Mudar de diretório local"<< endl;
+    cout << "ls - Visualizar arquivos no diretório local"<< endl;
+    cout << "cdr - Mudar de diretório remoto"<< endl;
+    cout << "lsr - Visualizar arquivos no diretório remoto"<< endl;
+    cout << "put - Enviar arquivo para diretório remoto"<< endl;
+    cout << "get - Pegar arquivo do diretório remoto"<< endl;
+    cout << "help - Lista de comandos"<< endl;
+    cout << "quit - Sair"<< endl;
+}
diff --git a/definitions.h b/definitions.h
index 41172491abff370859092b839caa2404ced9e754..cad4cec6598d72b040bf6f0a02390e0fadba1445 100644
--- a/definitions.h
+++ b/definitions.h
@@ -4,10 +4,22 @@
 #include <iostream>
 #include <string.h>
 #include <vector>
+#include <bitset>
+#include <cstdlib>
+#include <fstream>
+#include <sstream>
 
 using namespace std;
 
-#define DEVICE "lo"
+//Maximum and minimum of bytes in data field
+#define MAXSIZE 63
+#define MINSIZE 60
+
+//Delimiter indicating beginning of a message
+#define BEGIN 0x7E
+//Socket device
+#define DEVICE "eth0"
+//Message types
 #define NACK 0
 #define ACK 1
 #define CD 3
@@ -15,27 +27,35 @@ using namespace std;
 #define PUT 5
 #define GET 6
 #define OK 8
-#define TAM 9
-#define TELA 10
-#define ERRO 14
-#define FIM 15
-
-typedef struct{
-	int begin   : 8,
-        size    : 6,
-        sequence: 6,
-        type    : 4,
-        parity  : 8;
-}i_Control;
-
-typedef struct{
-	char begin,size,seqType,parity;
-}c_Control;
-
-typedef union {
-	c_Control c_ctrl;
-    i_Control i_ctrl;
-}Message;
-
-
-#endif
\ No newline at end of file
+#define SIZE 9
+#define OUTPUT 10
+#define DATA 13
+#define ERROR 14
+#define ENDTX 15
+
+//Windows
+#define WAIT_STOP 1
+#define SLIDING 3
+
+//Values of data for ERROR messages
+#define DIR_ERR '0' //Nonexistent Directory
+#define PERM_ERR '1' //Permission denied
+#define SPACE_ERR '2' //File size bigger than disk free space size
+
+//recvMessage errors
+#define NOISE -1
+#define SEQ_MISS -2
+#define INCONSISTENT -3
+
+//Bit fields size
+#define BEGIN_S 8
+#define SIZE_S 6
+#define SEQUENCE_S 6
+#define TYPE_S 4
+#define PARITY_S 8
+
+//Data types
+#define BYTE unsigned char
+
+
+#endif
diff --git a/dirFunctions.cpp b/dirFunctions.cpp
index 078e39c86c8e4134e08d493d9a79043593ddaba9..b028dda409416c18417424273f33534318be0ef5 100644
--- a/dirFunctions.cpp
+++ b/dirFunctions.cpp
@@ -1,8 +1,13 @@
 #include <iostream>
+#include <fstream>
 #include <errno.h>
 #include <unistd.h>
-#include <dirent.h>
 #include <string.h>
+#include <vector>
+#include <stdio.h> //popen
+#include <sys/stat.h>
+#include <fstream>
+#include <sys/statvfs.h>
 
 using namespace std;
 
@@ -13,16 +18,53 @@ void cd(string path){
     }
 }
 
-void ls(string path){
-    //TODO: #1
-    struct dirent *entry;
-    DIR *dir = opendir(path.c_str());
-    if(dir != NULL){
-        while((entry=readdir(dir)) != NULL){
-           cout << entry->d_name << endl;
-        }
-        closedir(dir);
-    }else{
-        cout<<"Error: could not open directory."<<endl;
+string ls(string args){
+    string output;
+    args += " 2>&1";
+    FILE *lsOut = popen(args.c_str(), "r");
+    if(!lsOut){
+        throw "Couldn't execute ls";
     }
-}
\ No newline at end of file
+    char buffer[1024];
+    while(fgets(buffer, sizeof(buffer), lsOut)!=NULL){
+        output += buffer;
+    }
+    pclose(lsOut);
+    return output;
+}
+
+string getWorkingPath(){
+   char temp[1024];
+   return (getcwd(temp, 1024) ? string(temp) : string(""));
+}
+
+bool fexists(string path) {
+    struct stat buffer;
+    return (stat(path.c_str(), &buffer) == 0);
+}
+
+int filesize(string path) {
+    ifstream in(path, ifstream::ate | ifstream::binary);
+    return in.tellg();
+}
+
+bool hasEnoughSpace(int size){
+    struct statvfs fsData;
+    string path = getWorkingPath();
+    statvfs(path.c_str(), &fsData);
+    long long freeSpace = fsData.f_bsize * fsData.f_bfree;
+    // cout << "freeSpace: " << freeSpace << "fsData: " << fsData.f_bsize << "\t" << fsData.f_bfree     << endl;
+    return (freeSpace > size);
+}
+
+
+void writeFile(string path, vector<BYTE>data){
+    // cout << "path: "<< path<<endl;
+    string strData(data.begin(), data.end());
+    ofstream file(path);
+    if (file.is_open()){
+        file << strData;
+        file.close();
+    }
+    else cout << "Unable to open file";
+}
diff --git a/dirFunctions.h b/dirFunctions.h
index 1cb22424a70c1b679ffde53db571a39f89c614b8..3b83f837ff3265baf90a27475bb4a56cac4e754d 100644
--- a/dirFunctions.h
+++ b/dirFunctions.h
@@ -7,6 +7,16 @@ using namespace std;
 
 void cd(string path);
 
-void ls(string path);
+string ls(string path);
 
-#endif
\ No newline at end of file
+bool fexists(string path);
+
+int filesize(string path);
+
+bool hasEnoughSpace(int size);
+
+string getWorkingPath();
+
+void writeFile(string path, vector<BYTE>data);
+
+#endif
diff --git a/server.cpp b/server.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..771c713592602b2845a84e507bd653132559338f
--- /dev/null
+++ b/server.cpp
@@ -0,0 +1,95 @@
+#include "definitions.h"
+#include "Protocol.h"
+#include "dirFunctions.h"
+#include "ConexaoRawSocket.c"
+
+int main(){
+    int sockt = ConexaoRawSocket(DEVICE);
+    Protocol receiveProtocol, sendProtocol;
+    cout << "Você está rodando o servidor Caco\n";
+    while(true){
+        int status = receiveProtocol.recvMessage(sockt);
+        // cout << "status: " << status << endl;
+        // cout << protocol.getDataAsString() << endl;
+        try{
+            if(status == NOISE){
+                continue;
+            }
+            if(status == CD){
+                cout << "Recebeu CD\n";
+                // cout << "CD: " << receiveProtocol.getDataAsString() << endl;
+                cd(receiveProtocol.getDataAsString());
+                sendProtocol.setData(vector<BYTE>(1,(BYTE)0), OK);
+                sendProtocol.sendMessage(sockt,0);
+            }else if(status == LS){
+                cout << "Recebeu LS\n";
+                // cout << "protocol data: " << receiveProtocol.getDataAsString() << endl;
+                // cout << "message data: " << receiveProtocol.getMessages().back().getDataAsString() << endl;
+                string output = ls(receiveProtocol.getMessages().back().getDataAsString());
+                // cout << "LS: " << output << endl;
+                sendProtocol.setData(vector<BYTE>(output.begin(), output.end()), OUTPUT);
+                sendProtocol.transmit(sockt, WAIT_STOP);
+                // cout << "finished transmit" << endl;
+            }else if(status == PUT){
+                cout << "Recebeu PUT\n";
+                string fileName = receiveProtocol.getDataAsString();
+                // cout << "fileName: " << fileName <<endl;
+                sendProtocol.setData(vector<BYTE>(1,(BYTE)0), OK);
+                sendProtocol.sendMessage(sockt,0);
+                receiveProtocol.reset();
+                receiveProtocol.receive(sockt,SIZE,WAIT_STOP,false);
+                // cout << "fileSize: " << receiveProtocol.getDataAsString() <<endl;
+                unsigned long long fileSize = stoi(receiveProtocol.getDataAsString());
+                sendProtocol.reset();
+                if(hasEnoughSpace(fileSize)){
+                    sendProtocol.setData(vector<BYTE>(1,(BYTE)0), OK);
+                    sendProtocol.sendMessage(sockt,0);
+                }else{
+                    sendProtocol.setData(vector<BYTE>(1,(BYTE)SPACE_ERR), ERROR);
+                    sendProtocol.sendMessage(sockt,0);
+                    continue;
+                }
+                receiveProtocol.reset();
+                receiveProtocol.receive(sockt,DATA,SLIDING,true);
+                // cout <<"conteudo: "<< receiveProtocol.getDataAsString()<<endl;
+                writeFile(getWorkingPath()+"/"+fileName,receiveProtocol.getData());
+
+            }else if(status == GET){
+                cout << "Recebeu GET\n";
+                string filePath = getWorkingPath()+"/"+receiveProtocol.getDataAsString();
+                if(fexists(filePath)) {
+                    string size = to_string(filesize(filePath));
+                    // cout << "ARQUIVO: " << filePath << "|" << size << endl;
+                    sendProtocol.setData(vector<BYTE>(size.begin(), size.end()), SIZE);
+                    sendProtocol.sendMessage(sockt, 0);
+                    int error = receiveProtocol.receive(sockt, OK, WAIT_STOP, false);
+                    if(error < 0) continue;
+                    sendProtocol.reset();
+                    ifstream putFile (filePath);
+                    stringstream buffer;
+                    buffer << putFile.rdbuf();
+                    string data = buffer.str();
+                    sendProtocol.setData(vector<BYTE>(data.begin(), data.end()), DATA);
+                    sendProtocol.transmit(sockt, SLIDING);
+                } else {
+                    sendProtocol.setData(vector<BYTE>(1,(BYTE)DIR_ERR), ERROR);
+                    sendProtocol.sendMessage(sockt,0);
+                    continue;
+                }
+            }else if(status == ENDTX){
+                sendProtocol.reset();
+                vector<BYTE> val(1,(BYTE)receiveProtocol.getMessages().back().sequence.to_ulong());
+                sendProtocol.setData(val, ACK);
+                sendProtocol.sendMessages(sockt);
+            }else if(status < 0 && status != NOISE){
+                sendProtocol.setData(vector<BYTE>(1,(BYTE)NACK), ERROR);
+                sendProtocol.sendMessage(sockt,0);
+            }
+        }catch(char const* strException){
+            cout << "Erro:" <<strException <<endl;
+        }
+        sendProtocol.reset();
+        receiveProtocol.reset();
+    }
+    return 0;
+}
diff --git a/test.sh b/test.sh
new file mode 100755
index 0000000000000000000000000000000000000000..7364b6d98efda0d483d79604dd54b26c2136459c
--- /dev/null
+++ b/test.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+rm 10.txt 100.txt 1000.txt
+
+for i in {1..10}
+do
+    echo -e "$i\n">>10.txt
+done
+
+for i in {1..100}
+do
+    echo -e "$i\n">>100.txt
+done
+
+for i in {1..1000};
+do
+    echo -e "$i\n">>1000.txt
+done