synk

synchronize files between hosts
Log | Files | Refs | README | LICENSE

commit d19f7b2d444e65f4d780ac3132968e432110ede9
parent bc0015b7394a71bac114b9f8f836d27f6b3de890
Author: Willy <willyatmailoodotorg>
Date:   Fri Aug 12 02:22:39 +0200

Basic client/server returning timestamp

Server reads file path on client's socket, and return the UNIX timestamp
of the last modification time for this file to the client.

Diffstat:
LICENSE | 13+++++++++++++
arg.h | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
config.mk | 12++++++++++++
mkfile | 20++++++++++++++++++++
synk.c | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
synkd.c | 124+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 305 insertions(+), 0 deletions(-)
diff --git a/LICENSE b/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2016 z3bra <willyatmailoodotorg> + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/arg.h b/arg.h @@ -0,0 +1,65 @@ +/* + * Copy me if you can. + * by 20h + */ + +#ifndef ARG_H__ +#define ARG_H__ + +extern char *argv0; + +/* use main(int argc, char *argv[]) */ +#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\ + argv[0] && argv[0][1]\ + && argv[0][0] == '-';\ + argc--, argv++) {\ + char argc_;\ + char **argv_;\ + int brk_;\ + if (argv[0][1] == '-' && argv[0][2] == '\0') {\ + argv++;\ + argc--;\ + break;\ + }\ + for (brk_ = 0, argv[0]++, argv_ = argv;\ + argv[0][0] && !brk_;\ + argv[0]++) {\ + if (argv_ != argv)\ + break;\ + argc_ = argv[0][0];\ + switch (argc_) + +/* Handles obsolete -NUM syntax */ +#define ARGNUM case '0':\ + case '1':\ + case '2':\ + case '3':\ + case '4':\ + case '5':\ + case '6':\ + case '7':\ + case '8':\ + case '9' + +#define ARGEND }\ + } + +#define ARGC() argc_ + +#define ARGNUMF() (brk_ = 1, estrtonum(argv[0], 0, INT_MAX)) + +#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\ + ((x), abort(), (char *)0) :\ + (brk_ = 1, (argv[0][1] != '\0')?\ + (&argv[0][1]) :\ + (argc--, argv++, argv[0]))) + +#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\ + (char *)0 :\ + (brk_ = 1, (argv[0][1] != '\0')?\ + (&argv[0][1]) :\ + (argc--, argv++, argv[0]))) + +#define LNGARG() &argv[0][0] + +#endif diff --git a/config.mk b/config.mk @@ -0,0 +1,12 @@ +VERSION = 0.0 + +CC = cc +LD = ${CC} + +PREFIX = /usr/local +MANDIR = ${PREFIX}/man + +CPPFLAGS = -DVERSION=\"${VERSION}\" +CFLAGS = ${CPPFLAGS} -Wall -Wextra -pedantic -g +LDFLAGS = +LIBS = -lpthread diff --git a/mkfile b/mkfile @@ -0,0 +1,20 @@ +<config.mk + +all:V: synk synkd + +%: %.o + $LD -o $target $prereq $LDFLAGS $LIBS + +%.o: %.c + $CC $CFLAGS -c $stem.c -o $stem.o + +clean:V: + rm -f *.o synk synkd + +install:V: all + mkdir -p ${DESTDIR}${PREFIX}/bin + cp synk ${DESTDIR}${PREFIX}/bin/synk + chmod 755 ${DESTDIR}${PREFIX}/bin/synk + +uninstall:V: + rm ${DESTDIR}${PREFIX}/bin/synk diff --git a/synk.c b/synk.c @@ -0,0 +1,71 @@ +#include <limits.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <arpa/inet.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include "arg.h" + +#define SERVER_HOST "127.0.0.1" +#define SERVER_PORT 9723 + +void +usage(char *name) +{ + fprintf(stderr, "usage: %s [-h HOST] [-p PORT] FILE\n", name), + exit(1); +} + +int +main(int argc, char *argv[]) +{ + int cfd; + char *argv0; + size_t len = 0; + uint16_t port = SERVER_PORT; + uint32_t host = INADDR_LOOPBACK; + struct sockaddr_in clt; + char path[PATH_MAX] = "", ts[32] = ""; + + ARGBEGIN{ + case 'h': host = atol(EARGF(usage(argv0))); break; + case 'p': port = atoi(EARGF(usage(argv0))); break; + }ARGEND; + + if (argc < 2) + return 1; + + if ((cfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { + perror("socket"); + return 1; + } + + memset(&clt, 0, sizeof(clt)); + clt.sin_family = AF_INET; + clt.sin_addr.s_addr = htonl(host); + clt.sin_port = htons(port); + + if (connect(cfd, (struct sockaddr *)&clt, sizeof(clt)) < 0) { + perror("connect"); + return 1; + } + + snprintf(path, PATH_MAX, "%s", argv[1]); + len = strnlen(path, PATH_MAX); + if (send(cfd, path, len, 0) < 0) { + perror("send"); + return -1; + } + + send(cfd, "\n", 1, 0); + + recv(cfd, ts, 32, 0); + printf("%s: %s\n", path, ts); + + return 0; +} diff --git a/synkd.c b/synkd.c @@ -0,0 +1,124 @@ +#include <limits.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <arpa/inet.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include "arg.h" + +#define LISTEN_PORT 9723 +#define MAXCONN 10 + +struct client_t { + int fd; + struct in_addr in; +}; + +void +usage(char *name) { + fprintf(stderr, "usage: %s [-h HOST] [-p PORT]\n", name); + exit(1); +} + +void * +handle_client(void *arg) +{ + int i = 0; + char buf, path[PATH_MAX] = "", ts[32] = ""; + size_t len = 0; + struct stat sb; + struct client_t *c = *(struct client_t **)arg; + + printf("%s: connected\n", inet_ntoa(c->in)); + while ((len = recv(c->fd, &buf, 1, 0)) > 0) { + if (i > PATH_MAX) { + printf("%s: filename too long (>%d)\n", inet_ntoa(c->in), PATH_MAX); + break; + } + + if (buf == '\n' || buf == '\0') { + printf("%s: %s\n", inet_ntoa(c->in), path); + stat(path, &sb); + snprintf(ts, 32, "%lu", sb.st_mtim.tv_sec); + len = strnlen(ts, 32); + send(c->fd, ts, len, 0); + memset(path, 0, PATH_MAX); + i = 0; + } else { + path[i++] = buf; + } + } + + close(c->fd); + len = 0; + printf("%s: disconnected\n", inet_ntoa(c->in)); + free(c); + pthread_exit((int *)&len); +} + +int +loop(int sfd) +{ + int cfd; + socklen_t len; + struct sockaddr_in clt; + struct client_t *c = NULL; + pthread_t th; + + for (;;) { + len = sizeof(clt); + if ((cfd = accept(sfd, (struct sockaddr *)&clt, &len)) < 0) { + perror("accept"); + return 1; + } + + c = malloc(sizeof(struct client_t)); + c->fd = cfd; + c->in = clt.sin_addr; + + pthread_create(&th, NULL, handle_client, &c); + } +} + +int +main(int argc, char *argv[]) +{ + int sfd; + char *argv0; + uint16_t port = LISTEN_PORT; + uint32_t host = INADDR_LOOPBACK; + struct sockaddr_in srv; + + ARGBEGIN{ + case 'p': + port = atoi(EARGF(usage(argv0))); + break; + }ARGEND; + + if ((sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { + perror("socket"); + return 1; + } + + memset(&srv, 0, sizeof(srv)); + srv.sin_family = AF_INET; + srv.sin_addr.s_addr = htonl(host); + srv.sin_port = htons(port); + + if (bind(sfd, (struct sockaddr *)&srv, sizeof(srv)) < 0) { + perror("bind"); + return 1; + } + + if (listen(sfd, MAXCONN) < 0) { + perror("listen"); + return 1; + } + + return loop(sfd); +}