tuyau

Client/server for transfering files (like cp)
git clone https://noulin.net/git/tuyau.git
Log | Files | Refs | README

commit 631cd83280c0dbd6766bae1f8675b88af631c0c2
parent 2c08011fa094be52c4d95d950ac72c267764bd4f
Author: Remy Noulin <loader2x@gmail.com>
Date:   Sun, 14 Aug 2022 10:37:00 -0400

add comments

NOTES.md     | 14 +++++++++++-
README.md    |  3 +++
makeHeader.c | 25 +++++++++++++++++++++
sclient.c    | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
sserver.c    | 39 +++++++++++++++++++++++++++++++--
5 files changed, 146 insertions(+), 6 deletions(-)

Diffstat:
MNOTES.md | 14+++++++++++++-
MREADME.md | 3+++
MmakeHeader.c | 25+++++++++++++++++++++++++
Msclient.c | 71++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Msserver.c | 39+++++++++++++++++++++++++++++++++++++--
5 files changed, 146 insertions(+), 6 deletions(-)

diff --git a/NOTES.md b/NOTES.md @@ -1,7 +1,19 @@ +- create packages +- tls +- reduce repeated code: create macros and functions +- check inputs, add limits +- add rate limiter, ban wrong token for 15minutes +- create tests +- send errors from server to client +- make daemon + + +Speed (no tls) 158MB tuyau 2.744s scp 3.896s + # to root path x./sclient.c NOTES.md dev x./sclient.c ~/notes.txt dev @@ -65,7 +77,7 @@ port 1032 token: QE123123 root: /home/rlp/tmp/ port: 1022 -serverConfig.yml +~/.tuyau/serverConfig.yml --- port: 1023 // optional user: diff --git a/README.md b/README.md @@ -8,3 +8,6 @@ Commits: 2 - send files and directories recursively 3 - receive a single file 4 - receive files and directories recursively + +The send code in the client is similar to the send code in the server. +The receive code in the server is similar to the receive code in the client. diff --git a/makeHeader.c b/makeHeader.c @@ -1,6 +1,31 @@ #include "libsheepyObject.h" #include "shpPackages/short/short.h" +/* +packet structures: +0 - send file + u8 command = 0 + u8 token[8] + u16 filenameLength + <filename> + u16 filemode + u16 pathLength + <path> + u64 filesize + <filedata> +1 - mkdir + u8 command = 0 + u8 token[8] + u16 filemode + u16 pathLength + <path> +2 - download/receive files + u8 command = 0 + u8 token[8] + u16 pathLength + <path> +*/ + void makeHeader(u8 *buf, u32 *bufip, u8 command, smallDictt *svrInfo, char *sendFile, char *destPath, u64 **filesize) { // command diff --git a/sclient.c b/sclient.c @@ -1,7 +1,27 @@ #! /usr/bin/env sheepy /* or direct path to sheepy: #! /usr/local/bin/sheepy */ - /* Libsheepy documentation: https://spartatek.se/libsheepy/ */ + +/* +usage +- create server config +- start server +- create client config +- run client + +Upload files: +./sclient.c files serverName +./sclient.c files serverName:path/ +./sclient.c file serverName:path/newfilename + +Downdload files: +./sclient.c serverName:path/files + >> downloads to current directory +./sclient.c serverName:path/files path/ +./sclient.c serverName:path/file path/newfilename + +*/ + #include "libsheepyObject.h" #include <netdb.h> #include <netinet/in.h> @@ -20,6 +40,10 @@ #define CONFIG "~/.tuyau/config.yml" +/* enable/disable logging */ +/* #undef pLog */ +/* #define pLog(...) */ + bool saveReceivedData(void *receiveB, size_t sz, void *context); int main(int ARGC, char** ARGV) { @@ -27,6 +51,17 @@ int main(int ARGC, char** ARGV) { initLibsheepy(ARGV[0]); setLogMode(LOG_FUNC); + // Steps + // + // load configuration + // check if there is a server name in argv 1 + // search for server name in last argument + // if receive and 2 args, arg 2 must be a valid path in client + // open connection to server + // receive files in receivePath + // send files + + // load configuration cleanCharP(config) = expandHome(CONFIG); cleanAllocateSmallJson(cfg); readFileG(cfg, config); @@ -36,6 +71,13 @@ int main(int ARGC, char** ARGV) { ret 1; } + // check if there is a server name in argv 1 + // if yes, the user wants to receive data from the server + // destPath is the path in the server to download from + // set server name + // if no, the user wants to upload to the server + + // send or receive data to/from server bool isReceive = no; const char *serverName = null; char *destPath = null; @@ -52,6 +94,7 @@ int main(int ARGC, char** ARGV) { } if (not isReceive) { + // search for server name in last argument if (ARGC == 2) { logE("Missing arguments"); ret 1; @@ -81,7 +124,7 @@ int main(int ARGC, char** ARGV) { } // not isReceive elif (ARGC > 2) { // receive - // arg 2 must be a path in client + // arg 2 must be a valid path in client receivePath = ARGV[2]; cleanCharP(localPath) = normalizePathG(ARGV[2]); if (not isEmptyG(localPath)/*ignore "." -> ""*/) { @@ -109,6 +152,7 @@ int main(int ARGC, char** ARGV) { lv(svrInfo); + // open connection to server int sock; struct sockaddr_in server; struct hostent *hp; @@ -140,6 +184,7 @@ int main(int ARGC, char** ARGV) { XFailure; } + // buffer for network packets u8 buf[1024*1024] = init0Var; if (isReceive) { @@ -161,6 +206,7 @@ int main(int ARGC, char** ARGV) { cleanAllocateSmallArray(pathToSend); + // verify that paths in client are valid rangeFrom(i, 1, ARGC-1) { if (not isPath(ARGV[i])) { logE("Incorrect path: "BLD YLW"%s"RST,ARGV[i]); @@ -171,10 +217,14 @@ int main(int ARGC, char** ARGV) { cleanAllocateSmallDict(recusive); + // send files in command line arguments + iter(pathToSend, P) { castS(p, P); char *sendFile = ssGet(P); + // create local directory in server + // add files from local directory to recusive dict, the last element is the local path if (isDirG(p)) { logD("mkdir in server"); @@ -190,6 +240,7 @@ int main(int ARGC, char** ARGV) { var dir = readDirAllG(rtSmallArrayt, p); //lv(dir); if (not isEmptyG(dir)) { + // save local path in last element pushG(dir, ssGet(p)); setNFreeG(recusive, dirname, dir); } @@ -203,11 +254,13 @@ int main(int ARGC, char** ARGV) { makeHeader(buf, &bufi, 0 /* command */, svrInfo, sendFile, destPath, &filesize); if (*filesize < (sizeof(buf) - bufi)) { + // the file is smaller than the network buffer, send all in one go pError0(bReadFile(sendFile, buf + bufi)); o(netframe,send , sock, buf, bufi + *filesize); } else { logD("big file"); + // loop to send big file in chunks u64 szToSend = *filesize; u8 *b = buf + bufi; u64 bSz = sizeof(buf) - bufi; @@ -234,7 +287,10 @@ int main(int ARGC, char** ARGV) { } // loop on arguments - // Send files recursively + // send files recursively + // each key is a path in server corresponding to a local directory + // the element is the list of files in the directory + // it is similar to the iter(pathToSend, P) loop iter(recusive, A) { cast(smallArrayt*,a,A); @@ -244,6 +300,8 @@ int main(int ARGC, char** ARGV) { castS(p, P); char *sendFile = ssGet(P); + // create local directory in server + // add files from local directory to recusive dict, the last element is the local path cleanCharP(localp) = catS(localPath, "/", ssGet(p)); if (isDirG(localp)) { logD("mkdir in server"); @@ -259,6 +317,7 @@ int main(int ARGC, char** ARGV) { var dir = readDirAllG(rtSmallArrayt, localp); lv(dir); if (not isEmptyG(dir)) { + // save local path in last element pushG(dir, localp); setNFreeG(recusive, dirname, dir); } @@ -274,11 +333,13 @@ int main(int ARGC, char** ARGV) { makeHeader(buf, &bufi, 0 /* command */, svrInfo, localp, dest, &filesize); if (*filesize < (sizeof(buf) - bufi)) { + // the file is smaller than the network buffer, send all in one go pError0(bReadFile(localp, buf + bufi)); o(netframe,send , sock, buf, bufi + *filesize); } else { logD("big file"); + // loop to send big file in chunks u64 szToSend = *filesize; u8 *b = buf + bufi; u64 bSz = sizeof(buf) - bufi; @@ -323,6 +384,7 @@ u64 transferSz = 0; bool saveReceivedData(void *receiveB, size_t sz, void *context) { logVarG(sz); if (packetCount == 0) { + // receive a new command // header u8 *command = (u8*) receiveB; @@ -354,6 +416,7 @@ bool saveReceivedData(void *receiveB, size_t sz, void *context) { logD("bufi %d fsz %d + %d, filename %s, root %s, destPath %s",bufi, *filesize, bufi + *filesize, filename, root,destPath); + // local filename cleanCharP(path) = null; if (not root) { @@ -377,11 +440,13 @@ bool saveReceivedData(void *receiveB, size_t sz, void *context) { lv(path); if (*filesize <= sz - bufi) { + // the file is smaller than the network buffer, the complete file is already here pError0(writeFile(path, receiveB + bufi, *filesize)); pError0(fileChmod(path, *filemode)); } else { logD("open fd"); + // increase packetCount to receive big file in chunks inc packetCount; fd = open(path, O_WRONLY | O_CREAT, *filemode); if (fd == -1) { diff --git a/sserver.c b/sserver.c @@ -29,6 +29,10 @@ int mysock = 0; smallJsont *tokens = null; +/* enable/disable logging */ +/* #undef pLog */ +/* #define pLog(...) */ + void saveReceivedData(void *receiveB, size_t sz); bool cb(void *buf, size_t size, void *context) { @@ -41,10 +45,18 @@ int main(int ARGC, char** ARGV) { initLibsheepy(ARGV[0]); setLogMode(LOG_FUNC); + // Steps + // load configuration + // create tokens dict + // open listen socket + // start event loop + + // load configuration cleanCharP(config) = expandHome(CONFIG); cleanAllocateSmallJson(cfg); readFileG(cfg, config); + // create tokens dict tokens = allocG(rtSmallJsont); iter(cfg, D) { @@ -54,6 +66,7 @@ int main(int ARGC, char** ARGV) { lv(tokens); + // open listen socket int sock; struct sockaddr_in server; int rval; @@ -66,7 +79,7 @@ int main(int ARGC, char** ARGV) { server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; - server.sin_port = htons(1032); + server.sin_port = htons(1032); // TODO allow changing port if (bind(sock, (struct sockaddr *) &server, sizeof(server))){ perror("bind failed"); @@ -77,6 +90,7 @@ int main(int ARGC, char** ARGV) { o(netframe, setCallback, cb, NULL /*context*/); + // start event loop listen(sock, 5); forever { mysock = accept(sock, (struct sockaddr *)0, 0); @@ -94,6 +108,7 @@ int main(int ARGC, char** ARGV) { void saveReceivedData(void *receiveB, size_t sz) { logVarG(sz); if (packetCount == 0) { + // receive a new command // header u8 *command = (u8*) receiveB; u8 *token = (u8*) (receiveB + 1); @@ -133,11 +148,13 @@ void saveReceivedData(void *receiveB, size_t sz) { logD("bufi %d fsz %d + %d, filename %s, destPath %s",bufi, *filesize, bufi + *filesize, filename, destPath); + // local filename char *path = catS(root, "/", nS(destPath)); pErrorNULL(normalizePathG(&path)); pErrorNULL(trimG(&path)); cleanCharP(nroot) = normalizePathG(root); //lv(path); + // make sure path is inside root if (not startsWithG(path, nroot)) { logE("Incorrect path"); ret; @@ -164,11 +181,13 @@ void saveReceivedData(void *receiveB, size_t sz) { lv(path); if (*filesize <= sz - bufi) { + // the file is smaller than the network buffer, the complete file is already here pError0(writeFile(path, receiveB + bufi, *filesize)); pError0(fileChmod(path, *filemode)); } else { logD("open fd"); + // increase packetCount to receive big file in chunks inc packetCount; fd = open(path, O_WRONLY | O_CREAT, *filemode); if (fd == -1) { @@ -216,6 +235,8 @@ void saveReceivedData(void *receiveB, size_t sz) { ret; } + // send a file or glob + cleanAllocateSmallArray(pathToSend); if (isPath(sendFile)) { @@ -237,6 +258,7 @@ void saveReceivedData(void *receiveB, size_t sz) { cleanAllocateNetFrame(netframe); + // network buffer u8 buf[1024*1024] = init0Var; cleanAllocateSmallDict(recusive); @@ -245,6 +267,8 @@ void saveReceivedData(void *receiveB, size_t sz) { castS(p, P); char *sendFile = ssGet(P); + // create local directory in client + // add files from local directory to recusive dict, the last element is the local path if (isDirG(p)) { logD("mkdir in client"); @@ -259,6 +283,7 @@ void saveReceivedData(void *receiveB, size_t sz) { var dir = readDirAllG(rtSmallArrayt, p); //lv(dir); if (not isEmptyG(dir)) { + // save local path in last element pushG(dir, ssGet(p)); setNFreeG(recusive, dirname, dir); } @@ -272,11 +297,13 @@ void saveReceivedData(void *receiveB, size_t sz) { makeHeader(buf, &bufi, 0 /* command */, null/*svrInfo no need to authenticate the client*/, sendFile, null/*destPath is already selected in client*/, &filesize); if (*filesize < (sizeof(buf) - bufi)) { + // the file is smaller than the network buffer, send all in one go pError0(bReadFile(sendFile, buf + bufi)); o(netframe,send , mysock, buf, bufi + *filesize); } else { logD("big file"); + // loop to send big file in chunks u64 szToSend = *filesize; u8 *b = buf + bufi; u64 bSz = sizeof(buf) - bufi; @@ -302,7 +329,10 @@ void saveReceivedData(void *receiveB, size_t sz) { } } // sendFile or globbing - // Send files recursively + // send files recursively + // each key is a path in server corresponding to a local directory + // the element is the list of files in the directory + // it is similar to the iter(pathToSend, P) loop iter(recusive, A) { cast(smallArrayt*,a,A); @@ -312,6 +342,8 @@ void saveReceivedData(void *receiveB, size_t sz) { castS(p, P); char *sendFile = ssGet(P); + // create local directory in server + // add files from local directory to recusive dict, the last element is the local path cleanCharP(localp) = catS(localPath, "/", ssGet(p)); if (isDirG(localp)) { logD("mkdir in client"); @@ -326,6 +358,7 @@ void saveReceivedData(void *receiveB, size_t sz) { var dir = readDirAllG(rtSmallArrayt, localp); lv(dir); if (not isEmptyG(dir)) { + // save local path in last element pushG(dir, localp); setNFreeG(recusive, dirname, dir); } @@ -340,11 +373,13 @@ void saveReceivedData(void *receiveB, size_t sz) { makeHeader(buf, &bufi, 0 /* command */, null/*svrInfo no need to authenticate the client*/, localp, (char*)iK(recusive) /*dest*/, &filesize); if (*filesize < (sizeof(buf) - bufi)) { + // the file is smaller than the network buffer, send all in one go pError0(bReadFile(localp, buf + bufi)); o(netframe,send , mysock, buf, bufi + *filesize); } else { logD("big file"); + // loop to send big file in chunks u64 szToSend = *filesize; u8 *b = buf + bufi; u64 bSz = sizeof(buf) - bufi;