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