commit 664248a9da8c2e92a073b561c7310798a5f4fb5f
Author: Remy Noulin <loader2x@gmail.com>
Date: Fri, 12 Aug 2022 06:17:08 -0400
simple client to a single file to server
implemented in sclient and sserver
no responses
.gitignore | 63 +++++++++
NOTES.md | 50 +++++++
netFrame.c | 310 ++++++++++++++++++++++++++++++++++++++++++
netFrame.h | 207 ++++++++++++++++++++++++++++
netFrameInternal.h | 7 +
package.yml | 37 +++++
sclient.c | 205 ++++++++++++++++++++++++++++
shpPackages/short/main.c | 29 ++++
shpPackages/short/package.yml | 15 ++
shpPackages/short/short.h | 15 ++
sserver.c | 196 ++++++++++++++++++++++++++
tuyau.c | 26 ++++
12 files changed, 1160 insertions(+)
Diffstat:
12 files changed, 1163 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,63 @@
+# Vim
+*.sw*
+
+# Debug
+.gdb_history
+
+# Coverage
+*.gcov
+*.gcda
+*.gcno
+
+# Prerequisites
+*.d
+
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Linker output
+*.ilk
+*.map
+*.exp
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
+*.su
+*.idb
+*.pdb
+
+# Kernel Module Compile Results
+*.mod*
+*.cmd
+.tmp_versions/
+modules.order
+Module.symvers
+Mkfile.old
+dkms.conf
diff --git a/NOTES.md b/NOTES.md
@@ -0,0 +1,50 @@
+# to root path
+x./sclient.c NOTES.md dev
+x./sclient.c ~/notes.txt dev
+# to path
+x./sclient.c NOTES.md dev:tuyauTest/
+# new name
+x./sclient.c NOTES.md dev:tuyauTest/ger.md
+
+./sclient.c dev:NOTES.md
+./sclient.c dev:NOTES.md ../
+
+cp file tuyau://ip/path
+
+>> ADD FILE MODE
+frame:
+1 byte command
+8 bytes token
+2 bytes file name length
+<filename>
+2 bytes path length
+<path>
+- optional
+8 bytes data size
+<data>
+
+> client/server requests
+client > command
+ reponse < server 1 byte - 0 ok/1 error
+ <data>
+
+port 1032
+
+- config home ~/.tuyau/config.yml
+---
+ alias:
+ hostname: ip
+ token: QE123123
+ root: /home/rlp/tmp/
+ port: 1022
+serverConfig.yml
+---
+ port: 1023 // optional
+ user:
+ token: QE123123
+ root: /home/rlp/tmp/
+- send files with glob, recursive
+- received files, glob, recursive
+- list files in path
+- token, home directory
+- server name ip port in config
diff --git a/netFrame.c b/netFrame.c
@@ -0,0 +1,310 @@
+
+
+/* Libsheepy documentation: https://spartatek.se/libsheepy/ */
+
+#include "libsheepyObject.h"
+#include "netFrame.h"
+#include "netFrameInternal.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+
+void initiateNetFrame(netFramet *self);
+void registerMethodsNetFrame(netFrameFunctionst *f);
+void initiateAllocateNetFrame(netFramet **self);
+void finalizeNetFrame(void);
+netFramet* allocNetFrame(void);
+local void freeNetFrame(netFramet *self);
+local void terminateNetFrame(netFramet **self);
+local char* toStringNetFrame(netFramet *self);
+local netFramet* duplicateNetFrame(netFramet *self);
+local void smashNetFrame(netFramet **self);
+local void finishNetFrame(netFramet **self);
+local const char* helpNetFrame(netFramet *self);
+local void setCallbackNetFrame(netFramet *self, callBackNetFramet callback, void* context);
+local bool sendNetFrame(netFramet *self, int sock, void* buf, size_t size);
+local bool receiveNetFrame(netFramet *self, int sock);
+local bool receiveOneNetFrame(netFramet *self, int sock);
+local bool endNetFrame(netFramet *self, int sock);
+
+/* enable/disable logging */
+/* #undef pLog */
+/* #define pLog(...) */
+
+bool checkLibsheepyVersionNetFrame(const char *currentLibsheepyVersion) {
+ return eqG(currentLibsheepyVersion, LIBSHEEPY_VERSION);
+}
+
+void initiateNetFrame(netFramet *self) {
+
+ self->type = "netFrame";
+ if (!netFrameF) {
+ netFrameF = malloc(sizeof(netFrameFunctionst));
+ registerMethodsNetFrame(netFrameF);
+ pErrorNot0(atexit(finalizeNetFrame));
+ }
+ self->f = netFrameF;
+
+ self->callback = null;
+ self->context = null;
+}
+
+void registerMethodsNetFrame(netFrameFunctionst *f) {
+
+ f->free = freeNetFrame;
+ f->terminate = terminateNetFrame;
+ f->toString = toStringNetFrame;
+ f->duplicate = duplicateNetFrame;
+ f->smash = smashNetFrame;
+ f->finish = finishNetFrame;
+ f->help = helpNetFrame;
+ f->setCallback = setCallbackNetFrame;
+ f->send = sendNetFrame;
+ f->receive = receiveNetFrame;
+ f->receiveOne = receiveOneNetFrame;
+ f->end = endNetFrame;
+}
+
+void initiateAllocateNetFrame(netFramet **self) {
+
+ if (self) {
+ (*self) = malloc(sizeof(netFramet));
+ if (*self) {
+ initiateNetFrame(*self);
+ }
+ }
+}
+
+void finalizeNetFrame(void) {
+
+ if (netFrameF) {
+ freen(netFrameF);
+ }
+}
+
+netFramet* allocNetFrame(void) {
+ netFramet *r = NULL;
+
+ initiateAllocateNetFrame(&r);
+ ret r;
+}
+
+
+void cleanUpNetFrameTerminateG(netFramet **val) {
+ terminateO(*val);
+}
+
+void cleanUpNetFrameFreeG(netFramet *val) {
+ freeO(val);
+}
+
+void cleanUpNetFrameFinishG(netFramet *val) {
+ finishO(val);
+}
+
+local void freeNetFrame(netFramet *self UNUSED) {
+}
+
+local void terminateNetFrame(netFramet **self) {
+
+ freeNetFrame(*self);
+ finishNetFrame(self);
+}
+
+
+local char* toStringNetFrame(netFramet *self UNUSED) {
+
+ ret strdup("TODO - netFrame");
+}
+
+local netFramet* duplicateNetFrame(netFramet *self UNUSED) {
+
+ createAllocateNetFrame(dup);
+ ret dup;
+}
+
+local void smashNetFrame(netFramet **self) {
+
+ finishNetFrame(self);
+}
+
+#if NFreeStackCheck
+local void finishNetFrame(netFramet **self) {
+
+ register u64 rsp asm("rsp");
+ if ((u64)*self > rsp) {
+ logW("Probably trying to free a smallArray on stack: "BLD"%p"RST" sp: "BLD"%p"RST, *self, rsp);
+ logBtrace;
+ }
+ else {
+ freen(*self);
+ }
+}
+#else
+// #if NFreeStackCheck
+local void finishNetFrame(netFramet **self) {
+
+ freen(*self);
+}
+#endif
+// #if NFreeStackCheck
+
+local const char* helpNetFrame(netFramet UNUSED *self) {
+ ret "TODO - netFrame help";
+}
+
+
+local void setCallbackNetFrame(netFramet *self, callBackNetFramet callback, void* context) {
+ self->callback = callback;
+ self->context = context;
+}
+
+
+local bool sendNetFrame(netFramet *self UNUSED, int sock, void* buf, size_t size) {
+
+ ssize_t status; // for netsend
+
+ #define netsend(B,SZ,FLGS) procbegin\
+ UNIQVAR(retry):\
+ if ((status = send(sock, B, SZ, (FLGS) | MSG_NOSIGNAL)) < 0) {\
+ if (errno == EAGAIN or errno == EINTR) {\
+ /* TODO this happens when the socket is in nonblocking mode */\
+ /* in my tests, there are data losses when size is larger than 1MBytes */\
+ /* this is a simple solution equivalent to blocking */\
+ /* a better solution is to keep running in the event loop */\
+ /* for large transfers */\
+ /* When EINTR is received, the send call was interrupted by a signal */\
+ /* restart the send call when it happens */\
+ goto UNIQVAR(retry);\
+ }\
+ shPrintError;\
+ shperror("Netframe send socket error");\
+ ret no;\
+ }\
+ procend
+
+ if (size > 0) {
+ netsend(&size, sizeof(size), MSG_MORE);
+ }
+ else {
+ // size 0 is the last frame in this transaction
+ netsend(&size, sizeof(size), 0);
+ ret yes;
+ }
+
+ while(size > 0) {
+ netsend(buf, size, 0);
+ buf += status;
+ size -= status;
+ }
+
+ ret yes;
+}
+
+
+local bool receiveNetFrame(netFramet *self, int sock) {
+ if (!self->callback) ret no;
+
+ size_t size;
+ ssize_t status; // for netrecv
+ bool isFirstFrame = yes;
+
+ #define netrecv(B, SZ, FLGS, CHECK, ENOUGH, ERROR) procbegin\
+ UNIQVAR(retry):\
+ if ((status = recv(sock, B, SZ, FLGS)) < 0) {\
+ if (errno == EAGAIN or errno == EINTR) {\
+ /* TODO this happens when the socket is in nonblocking mode */\
+ /* this is a simple solution equivalent to blocking */\
+ /* a better solution is to keep running in the event loop */\
+ /* for large transfers */\
+ /* When EINTR is received, the recv call was interrupted by a signal */\
+ /* restart the recv call when it happens */\
+ goto UNIQVAR(retry);\
+ }\
+ shPrintError;\
+ shperror("Netframe recv socket error");\
+ ERROR;\
+ ret no;\
+ }\
+ elif (!status) {\
+ /* ending connection - stop receiving frames */\
+ CHECK;\
+ }\
+ procend
+
+ forever {
+ netrecv(&size, sizeof(size), MSG_WAITALL, logE("ending connection");ret no,,logE("recv frame size"));
+
+ if (size == 0) {
+ /* the last frame for this transaction is received, leave this loop */
+ if (isFirstFrame) {
+ /* the first frame has size 0, this is a request to close the connection */
+ logD("close socket");
+ close(sock);
+ }
+ break;
+ }
+
+ //logVarG(size);
+
+ cleanCharP(buf) = malloc(size);
+ if (!buf) ret no;
+
+ void *b = buf;
+ size_t sz = size;
+ while (sz > 0) {
+ netrecv(b, sz, MSG_WAITALL /*flags*/, logE("ending connection: received %i, expected %i, left to receive %i", size-sz, size, sz);ret no/*frame is incomplete*/,, logE("Received: %i, left to receive: %i", size-sz ,sz));
+ b += status;
+ sz -= status;
+ }
+
+ if (!self->callback(buf, size, self->context)) {
+ // TODO error
+ }
+ isFirstFrame = no;
+ }
+
+ ret yes;
+}
+
+local bool receiveOneNetFrame(netFramet *self, int sock) {
+ if (!self->callback) ret no;
+
+ size_t size;
+ ssize_t status; // for netrecv
+
+ netrecv(&size, sizeof(size), MSG_WAITALL, logI("ending connection");ret no/*frame is incomplete*/,,logE("recv size"));
+
+ //logVarG(size);
+
+ if (!size) {
+ // a frame size 0 is a request to close the connection
+ logD("close socket");
+ close(sock);
+ ret yes;
+ }
+
+ cleanCharP(buf) = malloc(size);
+ if (!buf) ret no;
+
+ void *b = buf;
+ size_t sz = size;
+ while (sz > 0) {
+ netrecv(b, sz, MSG_WAITALL /*flags*/, logI("ending connection");ret no/*frame is incomplete*/, logD("Received: %i, left to receive: %i", size-sz ,sz), logE("Received: %i, left to receive: %i", size-sz ,sz));
+ b += status;
+ sz -= status;
+ }
+
+ if (!self->callback(buf, size, self->context)) {
+ // TODO error
+ }
+ ret yes;
+}
+
+local bool endNetFrame(netFramet *self, int sock) {
+ ret sendNetFrame(self, sock, null, 0);
+}
+
+
+// vim: set expandtab ts=2 sw=2:
diff --git a/netFrame.h b/netFrame.h
@@ -0,0 +1,207 @@
+#pragma once
+
+/* Libsheepy documentation: https://spartatek.se/libsheepy/ */
+
+/**
+ * netFrame is client and server for sending and receiving data frames
+ * the sockets can remain open all the time
+ *
+ * A data frame is a buffer and a size.
+ *
+ * Frame:
+ * -------------- ------
+ * | size 8 bytes | data
+ * -------------- ------
+ *
+ * The client opens a socket and calls send with the buffer address and size:
+ *
+ * cleanAllocateNetFrame(netframe);
+ * Loop until all frames are sent:
+ * o(netframe,send , sock, buffer, size);
+ * Send a frame with size 0 with no data to signal the end of the transfer
+ * when a frame size 0 is received in the server, the callback is not called
+ * The socket can be kept open
+ *
+ * The server sets a callback before receiving connections
+ *
+ * cleanAllocateNetFrame(netframe);
+ * o(netframe, setCallback, cb, NULL context);
+ *
+ * The callback is executed after each frame is completely received.
+ * The callback prototype is:
+ *
+ * callBackNetFramet:
+ * bool cb(void *buf, size_t size, void *context);
+ *
+ * The provided buffer buf is freed in netFrame.
+ *
+ * In the event loop, the server accepts connections and call receive:
+ *
+ * var r = o(netframe,receive, mysock);
+ *
+ * receive waits for frames until a frame size 0 is received
+ */
+
+#include "libsheepyObject.h"
+
+/* Class netFrame */
+typ struct netFrame netFramet;
+
+#define isONetFrame(obj) isOType(obj, "netFrame")
+#define isONetFrametG isONetFrame
+
+/* for object inheriting netFrame, cast to netFrame to be able to use this class functions and generics*/
+#define cNetFrame(self) ( (netFramet*) self )
+
+typ void (*freeNetFrameFt) (netFramet *self);
+typ void (*terminateNetFrameFt) (netFramet **self);
+typ char* (*toStringNetFrameFt) (netFramet *self);
+typ netFramet* (*duplicateNetFrameFt) (netFramet *self);
+typ void (*smashNetFrameFt) (netFramet **self);
+
+/**
+ * free netFrame
+ */
+typ void (*finishNetFrameFt) (netFramet **self);
+
+typ const char* (*helpNetFrameFt) (netFramet *self);
+
+/**
+ * callback is a function called after each frame is received
+ *
+ * \param
+ * buf data from the network, netFrame frees the buffer
+ * \param
+ * size data szie from the network
+ * \param
+ * context callback context variable
+ */
+typ bool (*callBackNetFramet)(void *buf, size_t size, void *context);
+
+/**
+ * set callback called after each received frame in the receive function
+ * and context for the callback function
+ */
+typ void (*setCallbackNetFrameFt)(netFramet *self, callBackNetFramet callback, void* context);
+
+/**
+ * send buf, size 0 means end of transaction
+ */
+typ bool (*sendNetFrameFt)(netFramet *self, int sock, void* buf, size_t size);
+
+/**
+ * receive frames until the socket is closed by the client
+ */
+typ bool (*receiveNetFrameFt)(netFramet *self, int sock);
+
+/**
+ * receive one frame and return
+ */
+typ bool (*receiveOneNetFrameFt)(netFramet *self, int sock);
+
+/**
+ * end transaction or inform the server that the connection is going to be closed
+ * this function sends a frame of size 0
+ * when one frame is sent:
+ * - the function send sends the size and the buffer
+ * - sending a frame size 0 closes the connection
+ * when multiple frames are sent:
+ * - call send as many times as needed to send buffer of size not 0
+ * - when finished send a frame size 0 meaning end of transaction
+ * - to close the connection, send a frame size 0 again
+ */
+typ bool (*endNetFrameFt)(netFramet *self, int sock);
+
+/**
+ * class functions
+ * allocated once for all objects
+ *
+ * freed with finalizeNetFrame
+ */
+
+/**
+ * use this define in child classes and add the new function after this class functions
+ *
+ * in this define, add the methods after <finishNetFrameFt finish;>
+ *
+ * Example:
+ * #define RINGFUNCTIONST \n * NETFRAMEFUNCTIONST; \n * setSizeRingFt setSize
+ */
+#define NETFRAMEFUNCTIONST \
+ helpNetFrameFt help;\
+ setCallbackNetFrameFt setCallback;\
+ sendNetFrameFt send;\
+ receiveNetFrameFt receive;\
+ receiveOneNetFrameFt receiveOne;\
+ endNetFrameFt end
+
+typ struct {
+ freeNetFrameFt free;
+ terminateNetFrameFt terminate;
+ toStringNetFrameFt toString;
+ duplicateNetFrameFt duplicate;
+ smashNetFrameFt smash;
+ finishNetFrameFt finish;
+ NETFRAMEFUNCTIONST;
+} netFrameFunctionst;
+
+/**
+ * class
+ */
+struct netFrame {
+ const char *type;
+ netFrameFunctionst *f;
+
+ callBackNetFramet callback;
+ void *context;
+};
+
+/* netFrame */
+
+/** return true when this object file was compiled with current libsheepy version */
+#define isNetFrameCompiledWithCurrentLisheepyVersion checkLibsheepyVersionNetFrame(LIBSHEEPY_VERSION)
+bool checkLibsheepyVersionNetFrame(const char *currentLibsheepyVersion);
+
+#define createNetFrame(obj) ;netFramet obj; initiateNetFrame(&obj)
+#define createAllocateNetFrame(obj) ;netFramet *obj; initiateAllocateNetFrame(&obj)
+
+void initiateNetFrame(netFramet *self);
+void initiateAllocateNetFrame(netFramet **self);
+void finalizeNetFrame(void);
+
+/* initialize class methods, call registerMethodsNetFrame from classes inheriting this class */
+void registerMethodsNetFrame(netFrameFunctionst *f);
+
+netFramet* allocNetFrame(void);
+
+/* terminate netFramet val when it is out of scope */
+void cleanUpNetFrameTerminateG(netFramet **val);
+
+/* free netFramet val when it is out of scope */
+void cleanUpNetFrameFreeG(netFramet *val);
+
+/* finish netFramet val when it is out of scope */
+void cleanUpNetFrameFinishG(netFramet *val);
+
+/**
+ * declare pointer name with Type netFramet and terminate name when it is out of scope
+ */
+#define cleanNetFrameP(name) netFramet *name CLEANUP(cleanUpNetFrameTerminateG)
+
+/**
+ * allocate NetFrame (pointer) and clean up when it is out of scope
+ */
+#define cleanAllocateNetFrame(obj) ;cleanNetFrameP(obj); initiateAllocateNetFrame(&obj)
+
+/**
+ * declare local object name with Type netFramet and free name when it is out of scope
+ */
+#define cleanNetFrame(name) netFramet name CLEANUP(cleanUpNetFrameFreeG); initiateNetFrame(&name)
+
+/**
+ * declare pointer name with Type netFramet and finish name when it is out of scope
+ */
+#define cleanFinishNetFrameP(name) netFramet *name CLEANUP(cleanUpNetFrameFinishG)
+
+/* end class netFrame*/
+// vim: set expandtab ts=2 sw=2:
diff --git a/netFrameInternal.h b/netFrameInternal.h
@@ -0,0 +1,7 @@
+#pragma once
+
+static netFrameFunctionst *netFrameF = NULL;
+
+/* TODO declare structs for private data and add a void pointer to the private data in the class declaration */
+
+// vim: set expandtab ts=2 sw=2:+
\ No newline at end of file
diff --git a/package.yml b/package.yml
@@ -0,0 +1,37 @@
+---
+ name: tuyau
+ version: 0.0.1
+ description: "explanation"
+ bin: ./tuyau.c
+ #cflags: -DA -g3 -std=gnu11 -fPIC -pipe
+ #lflags: -lpcre
+ repository:
+ type: git
+ url: git+https://github.com/USER/tuyau.git
+ keywords:
+ #- utility
+ - command
+ author: Anonymous
+ license: MIT
+ bugs:
+ url: https://github.com/USER/tuyau/issues
+ homepage: https://github.com/USER/tuyau#readme
+ #compileHelp: # text displayed when there is a compilation error
+ #dependencies:
+ # md4c:
+ # Test configuration:
+ #testBin: ./testTuyau.c
+ #testCflags: -g3 -std=gnu11 -fPIC -pipe -fprofile-arcs -ftest-coverage -Wall -Wextra
+ #testLflags: -lcheck_pic -lrt -lm -lsubunit -fprofile-arcs -ftest-coverage -rdynamic
+ # Memcheck configuration (sheepy -m):
+ #memcheckBin: ./memcheckTuyau.c
+ #memcheckCmd: valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1
+ #memcheckCflags: -g3 -std=gnu11 -fPIC -pipe
+ #memcheckLflags: -rdynamic
+ # The asan* are the options for building the libsasan tests (sheepy -a):
+ #asanBin: ./asanTuyau.c
+ #asanCmd: env ASAN_OPTIONS="detect_leaks=1:detect_stack_use_after_return=1:halt_on_error=0:log_path=stdout:color=always:print_cmdline=1"
+ #asanCflags: -fsanitize=address -fno-omit-frame-pointer -fsanitize-recover=address # these flags are overriden by package.yml
+ #asanLflags: -rdynamic -fsanitize=address -lasan # these flags are overriden by package.yml
+ #documentationCmd: # command for generating the documentation with spm doc
+ private: false # true for private package+
\ No newline at end of file
diff --git a/sclient.c b/sclient.c
@@ -0,0 +1,205 @@
+#! /usr/bin/env sheepy
+/* or direct path to sheepy: #! /usr/local/bin/sheepy */
+
+/* Libsheepy documentation: https://spartatek.se/libsheepy/ */
+#include "libsheepyObject.h"
+#include <netdb.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+// open
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "netFrame.h"
+#include "shpPackages/short/short.h"
+
+#define CONFIG "~/.tuyau/config.yml"
+
+int main(int ARGC, char** ARGV) {
+
+ initLibsheepy(ARGV[0]);
+ setLogMode(LOG_FUNC);
+
+ cleanCharP(config) = expandHome(CONFIG);
+ cleanAllocateSmallJson(cfg);
+ readFileG(cfg, config);
+
+ if (ARGC < 2) {
+ logE("Missing arguments");
+ ret 1;
+ }
+
+ // check args
+ if (ARGC == 2) {
+ TODO("check that a server is selected");
+ }
+
+ if (ARGC < 3) {
+ logE("Missing arguments");
+ ret 1;
+ }
+
+ bool isReceive = no;
+ iter(cfg, D) {
+ cast(smallDictt*,d,D);
+ //lv(d);
+ if (startsWithG(ARGV[1], iK(cfg)) and ARGV[1][lenG(iK(cfg))] == ':' and ARGV[1][lenG(iK(cfg))+1] != 0) {
+ TODO("arg 2 must be a path in client");
+ isReceive = yes;
+ break;
+ }
+ }
+
+ char *sendFile = null;
+ const char *serverName = null;
+ char *destPath = null;
+ if (not isReceive) {
+ logD("path in client");
+ if (not isPath(ARGV[1])) {
+ logE("Incorrect path: "BLD YLW"%s"RST,ARGV[1]);
+ ret 1;
+ }
+ sendFile = ARGV[1];
+
+ // check last arg
+ bool foundDest = no;
+ iter(cfg, D) {
+ cast(smallDictt*,d,D);
+ //lv(d);
+ if (startsWithG(ARGV[ARGC-1], iK(cfg))) {
+ if (ARGV[ARGC-1][lenG(iK(cfg))] == 0) {
+ logD("no dest path");
+ serverName = iK(cfg);
+ foundDest = yes;
+ break;
+ }
+ elif (ARGV[ARGC-1][lenG(iK(cfg))] == ':' and ARGV[ARGC-1][lenG(iK(cfg))+1] != 0) {
+ logD("found destination");
+ serverName = iK(cfg);
+ destPath = ARGV[ARGC-1] + lenG(iK(cfg)) + 1;
+ foundDest = yes;
+ break;
+ }
+ }
+ }
+ } // not isReceive
+
+ if (not serverName) {
+ logE("server name not found");
+ ret 1;
+ }
+
+ cleanFinishSmallDictP(svrInfo) = getG(cfg, rtSmallDictt, serverName);
+
+ lv(svrInfo);
+
+ int sock;
+ struct sockaddr_in server;
+ struct hostent *hp;
+ int mysock;
+ int rval;
+
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock < 0){
+ perror("Failed to create socket");
+ }
+
+ server.sin_family = AF_INET;
+
+ hp = gethostbyname($(svrInfo, "hostname"));
+ if (hp==0) {
+ perror("gethostbyname failed");
+ close(sock);
+ XFailure;
+ }
+
+ memcpy(&server.sin_addr, hp->h_addr, hp->h_length);
+ server.sin_port = htons(u$(svrInfo, "port"));
+
+ if (connect(sock,(struct sockaddr *) &server, sizeof(server))){
+ perror("connect failed");
+ close(sock);
+ XFailure;
+ }
+
+ // send
+ // command 0
+ // token
+ // file name max 8k
+ // dest path 0
+
+ u8 buf[1024*1024] = init0Var;
+
+ // command
+ buf[0] = 0;
+ // token
+ memcpy(buf + 1, $(svrInfo, "token"), 8);
+ u16 *filenameLength = (u16*)(buf + 9);
+ char *filename = basename(sendFile);
+ *filenameLength = lenG(filename);
+ memcpy(buf + 11, filename, lenG(filename));
+ u32 bufi = 11 + lenG(filename);
+ u16 *filemode = (u16*)(buf + bufi);
+ struct stat st;
+ if(stat(sendFile, &st) != 0){
+ logE("Can't access %s", sendFile);
+ ret 1;
+ }
+ *filemode = st.st_mode & 0xFFF;
+ bufi += 2;
+ u16 *pathLength = (u16*)(buf + bufi);
+ *pathLength = lenG(destPath);
+ bufi += 2;
+ if (destPath) {
+ memcpy(buf + bufi, destPath, *pathLength);
+ bufi += *pathLength;
+ }
+ // file size
+ u64 *filesize = (u64*)(buf + bufi);
+ *filesize = fileSizeG(sendFile);
+ bufi += 8;
+
+ cleanAllocateNetFrame(netframe);
+
+ if (*filesize < (sizeof(buf) - bufi)) {
+ pError0(bReadFile(sendFile, buf + bufi));
+ o(netframe,send , sock, buf, bufi + *filesize);
+ }
+ else {
+ logD("big file");
+ u64 szToSend = *filesize;
+ u8 *b = buf + bufi;
+ u64 bSz = sizeof(buf) - bufi;
+ int fd = open(sendFile, O_RDONLY);
+ do {
+ if (szToSend <= bSz) {
+ read(fd, b, szToSend);
+ o(netframe,send , sock, b, szToSend);
+ szToSend = 0;
+ }
+ else {
+ read(fd, b, bSz);
+ if (szToSend == *filesize) {
+ o(netframe,send , sock, buf, bufi + bSz);
+ }
+ else {
+ o(netframe,send , sock, b, bSz);
+ }
+ szToSend -= bSz;
+ }
+ } while(szToSend);
+ close(fd);
+ }
+
+
+ // last frame size 0
+ o(netframe,end, sock);
+
+ close(sock);
+}
+// vim: set expandtab ts=2 sw=2:
diff --git a/shpPackages/short/main.c b/shpPackages/short/main.c
@@ -0,0 +1,29 @@
+#! /usr/bin/env sheepy
+/* or direct path to sheepy: #! /usr/local/bin/sheepy */
+
+/* Libsheepy documentation: http://spartatek.se/libsheepy/ */
+#include "libsheepyObject.h"
+#include "short.h"
+
+int argc; char **argv;
+
+/* enable/disable logging */
+/* #undef pLog */
+/* #define pLog(...) */
+
+int main(int ARGC, char** ARGV) {
+
+ argc = ARGC; argv = ARGV;
+
+ initLibsheepy(ARGV[0]);
+
+ createSmallDict(d);
+
+ $(&d, "wer");
+
+ i_("de");
+
+ lv(&d);
+
+}
+// vim: set expandtab ts=2 sw=2:
diff --git a/shpPackages/short/package.yml b/shpPackages/short/package.yml
@@ -0,0 +1,15 @@
+---
+ name: short
+ version: 0.0.3
+ description: "convenient defines for often used libsheepy function calls making the lines shorter and more readable"
+ bin: ./short.h
+ repository:
+ type: git
+ url: git+https://github.com/USER/short.git
+ keywords:
+ - utility
+ author: Remy
+ license: MIT
+ bugs:
+ url: https://github.com/USER/short/issues
+ homepage: https://github.com/USER/short#readme
diff --git a/shpPackages/short/short.h b/shpPackages/short/short.h
@@ -0,0 +1,15 @@
+#include "libsheepyObject.h"
+
+#define lv logTVarG
+#define i_ logI
+
+#define iI iterIndexG
+#define iK iterKeyG
+
+// get string from array or dict
+#define $(object, key) getG(object, rtChar, key)
+
+// get unsigned int
+#define u$(object, key) getG(object, rtU64, key)
+
+// vim: set expandtab ts=2 sw=2:
diff --git a/sserver.c b/sserver.c
@@ -0,0 +1,196 @@
+#! /usr/bin/env sheepy
+/* or direct path to sheepy: #! /usr/local/bin/sheepy */
+
+/* Libsheepy documentation: https://spartatek.se/libsheepy/ */
+#include "libsheepyObject.h"
+#include <netinet/in.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+// open
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "netFrame.h"
+#include "shpPackages/short/short.h"
+
+#define CONFIG "~/.tuyau/serverConfig.yml"
+
+int packetCount = 0;
+int fd = -1;
+u64 transferSz = 0;
+
+smallJsont *tokens = null;
+
+void saveReceivedData(void *receiveB, size_t sz);
+
+bool cb(void *buf, size_t size, void *context) {
+ saveReceivedData(buf, size);
+ ret yes;
+}
+
+int main(int ARGC, char** ARGV) {
+
+ initLibsheepy(ARGV[0]);
+ setLogMode(LOG_FUNC);
+
+ cleanCharP(config) = expandHome(CONFIG);
+ cleanAllocateSmallJson(cfg);
+ readFileG(cfg, config);
+
+ tokens = allocG(rtSmallJsont);
+
+ iter(cfg, D) {
+ cast(smallDictt*,d,D);
+ setG(tokens, $(d,"token"), $(d,"root"));
+ }
+
+ lv(tokens);
+
+ int sock;
+ struct sockaddr_in server;
+ int mysock;
+ int rval;
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock < 0){
+ perror("Failed to create socket");
+ XFailure;
+ }
+
+ server.sin_family = AF_INET;
+ server.sin_addr.s_addr = INADDR_ANY;
+ server.sin_port = htons(1032);
+
+ if (bind(sock, (struct sockaddr *) &server, sizeof(server))){
+ perror("bind failed");
+ XFailure;
+ }
+
+ cleanAllocateNetFrame(netframe);
+
+ o(netframe, setCallback, cb, NULL /*context*/);
+
+ listen(sock, 5);
+ forever {
+ mysock = accept(sock, (struct sockaddr *)0, 0);
+ if (mysock == 1)
+ perror("accept failed");
+ else {
+ var r = o(netframe,receive, mysock);
+ logVarG(r);
+ }
+ }
+
+ terminateG(tokens);
+}
+
+void saveReceivedData(void *receiveB, size_t sz) {
+ logVarG(sz);
+ if (packetCount == 0) {
+ // header
+ u8 *command = (u8*) receiveB;
+ u8 *token = (u8*) (receiveB + 1);
+ char tk[9] = init0Var;
+ memcpy(tk, token, 8);
+
+ if (not hasG(tokens, tk)) {
+ logE("token not found");
+ ret;
+ }
+
+ char *root = $(tokens, tk);
+
+ u16 *filenameLength = (u16*)(receiveB + 9);
+ // receiveB + 11 = filename
+ cleanCharP(filename) = malloc(*filenameLength + 1);
+ filename[*filenameLength] = 0;
+ memcpy(filename, receiveB + 11, *filenameLength);
+ u32 bufi = 11 + *filenameLength;
+ u16 *filemode = (u16*)(receiveB + bufi);
+ bufi += 2;
+ u16 *pathLength = (u16*)(receiveB + bufi);
+ bufi += 2;
+ cleanCharP(destPath) = null;
+ if (*pathLength) {
+ destPath = malloc(*pathLength + 1);
+ memcpy(destPath, receiveB + bufi, *pathLength);
+ destPath[*pathLength] = 0;
+ bufi += *pathLength;
+ }
+ // file size
+ u64 *filesize = (u64*)(receiveB + bufi);
+ bufi += 8;
+
+ logD("bufi %d fsz %d + %d, filename %s, destPath %s",bufi, *filesize, bufi + *filesize, filename, destPath);
+
+ char *path = catS(root, "/", nS(destPath));
+ pErrorNULL(normalizePathG(&path));
+ pErrorNULL(trimG(&path));
+ cleanCharP(nroot) = normalizePathG(root);
+ //lv(path);
+ if (not startsWithG(path, nroot)) {
+ logE("Incorrect path");
+ ret;
+ }
+
+ // check isdir or if there is a filename
+ bool filenameInDestPath = no;
+ if (destPath and not isPath(path)) {
+ if (endsWithG(destPath,'/')) {
+ logE("Directory doesn't exist %s", path);
+ ret;
+ }
+ cleanCharP(dir) = shDirname(path);
+ if (not isPath(dir)) {
+ logE("Directory doesn't exist %s", dir);
+ ret;
+ }
+ filenameInDestPath = yes;
+ }
+ //lv(filenameInDestPath);
+ if (not filenameInDestPath) {
+ pErrorNULL(iAppendManyS(&path, "/", filename));
+ }
+ lv(path);
+
+ if (*filesize <= sz - bufi) {
+ pError0(writeFile(path, receiveB + bufi, *filesize));
+ pError0(fileChmod(path, *filemode));
+ }
+ else {
+ logD("open fd");
+ inc packetCount;
+ fd = open(path, O_WRONLY | O_CREAT, *filemode);
+ if (fd == -1) {
+ logE("cant open %s", path);
+ ret;
+ }
+ int r = write(fd, receiveB + bufi, sz - bufi);
+ if (r == -1) {
+ logE("cant write %s", path);
+ ret;
+ }
+ transferSz = *filesize - (sz - bufi);
+ }
+ }
+ else {
+ if (fd == -1) ret;
+ // big file
+ int r = write(fd, receiveB, sz);
+ if (r == -1) {
+ logE("cant write");
+ ret;
+ }
+ if (transferSz <= sz) {
+ transferSz = 0;
+ close(fd);
+ fd = -1;
+ packetCount = 0;
+ }
+ else transferSz -= sz;
+ }
+}
+// vim: set expandtab ts=2 sw=2:
diff --git a/tuyau.c b/tuyau.c
@@ -0,0 +1,26 @@
+#! /usr/bin/env sheepy
+/* or direct path to sheepy: #! /usr/local/bin/sheepy */
+
+/* Libsheepy documentation: https://spartatek.se/libsheepy/ */
+#include "libsheepyObject.h"
+
+int argc; char **argv;
+
+/* enable/disable logging */
+/* #undef pLog */
+/* #define pLog(...) */
+
+int main(int ARGC, char** ARGV) {
+
+ argc = ARGC; argv = ARGV;
+
+ initLibsheepy(ARGV[0]);
+ setLogMode(LOG_VERBOSE);
+ //openProgLogFile();
+ //setLogSymbols(LOG_UTF8);
+ //disableLibsheepyErrorLogs;
+
+ logI("C template");
+
+}
+// vim: set expandtab ts=2 sw=2:+
\ No newline at end of file