260 lines
6.3 KiB
C
260 lines
6.3 KiB
C
#include <getopt.h>
|
|
|
|
#include <hash.h>
|
|
#include <blksync.h>
|
|
|
|
|
|
char sHelp[] = "usage: dsync [ -v ] [ -4 | -6 ] [ -depth | -r ] [ -s ] [ -p <port> ] [ -b <blocksize> ] <file> [ host ]\n"
|
|
"\t-h\tshow this help\n"
|
|
"\t-v\targ_verbose\n"
|
|
"\t-depth\tlisten and wait for connection\n"
|
|
"\t-r\targ_reverse_mode connection (sync from arg_listener_mode instead of to)\n"
|
|
"\t-b\tset non-default blocksize\n"
|
|
"\t-p\tuse tcp port <port> for listening or connecting\n"
|
|
"\t-4\tuse ipv4\n"
|
|
"\t-6\tuse ipv6\n"
|
|
"\t-s\tsimulate (don't change target file)\n"
|
|
"\t-t\ttest mode, only output block hashes\n"
|
|
;
|
|
|
|
int af = AF_UNSPEC;
|
|
|
|
uint16_t port = 13487;
|
|
|
|
int main_listen();
|
|
int main_connect();
|
|
|
|
int show_help(char *msg){
|
|
if (msg && strlen(msg))
|
|
fprintf(stdout, "%s\n", msg);
|
|
|
|
fprintf(stdout, sHelp);
|
|
fflush(stdout);
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int opt;
|
|
long _l;
|
|
|
|
bsync_engine_t *engine = create_engine();
|
|
if (!engine)
|
|
{
|
|
fprintf(stderr, "could not allocate engine memory\n");
|
|
fflush(stderr);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
while ((opt = getopt(argc, argv, "v46lrb:p:shtd"))>0){
|
|
switch (opt){
|
|
case 'h':
|
|
return show_help(NULL);
|
|
case 'v':
|
|
engine->ds_flags |= DS_VERBOSE;
|
|
break;
|
|
case 'l':
|
|
engine->ds_flags |= DS_LISTENER;
|
|
break;
|
|
case 'r':
|
|
engine->ds_flags |= DS_REVERSE;
|
|
break;
|
|
case 's':
|
|
engine->ds_flags |= DS_SIMULATE;
|
|
break;
|
|
case '4':
|
|
af = AF_INET;
|
|
break;
|
|
case '6':
|
|
af = AF_INET6;
|
|
break;
|
|
case 'p':
|
|
_l = strtol(optarg, NULL, 0 );
|
|
if (_l > 65535)
|
|
return show_help("port must be less then 65536");
|
|
|
|
port = _l;
|
|
break;
|
|
case 'b':
|
|
_l = strtol(optarg, NULL, 0 );
|
|
if (_l >= (1L<<32))
|
|
return show_help("blocksize must be smaller then 1<<32\n");
|
|
engine->blocksize = _l;
|
|
break;
|
|
case 't':
|
|
engine->sr_mode = SR_TEST;
|
|
break;
|
|
case 'd':
|
|
engine->ds_flags |= DS_DUMPBLOCKS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (engine->sr_mode != SR_TEST)
|
|
engine->sr_mode = ((engine->ds_flags & DS_LISTENER)==DS_LISTENER) == ((engine->ds_flags & DS_REVERSE)==DS_REVERSE) ? SR_SENDER : SR_RECEIVER;
|
|
|
|
if (optind >= argc)
|
|
return show_help("need a file or device to sync");
|
|
|
|
strncpy( engine->filename, argv[optind++], sizeof(engine->filename));
|
|
|
|
if ((engine->sr_mode != SR_TEST) && (optind >= argc) && !(engine->ds_flags & DS_LISTENER))
|
|
show_help("need a hostname\n");
|
|
|
|
if (optind < argc)
|
|
strncpy(engine->hostname, argv[optind++], sizeof(engine->hostname));
|
|
|
|
engine->file = open( engine->filename, engine->sr_mode == SR_SENDER ? O_RDONLY : (O_RDWR | O_CREAT), S_IRWXU | S_IRWXG | S_IRWXO);
|
|
if (engine->file < 0){
|
|
fprintf(stderr, "could not open %s\n", engine->filename);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
engine->filesize = lseek( engine->file, 0, SEEK_END);
|
|
lseek(engine->file, 0, SEEK_SET);
|
|
|
|
if (!(engine->sr_mode == SR_TEST)) {
|
|
if (engine->ds_flags & DS_LISTENER) {
|
|
assert_x(accept_connection(engine, engine->hostname, port), NULL);
|
|
} else {
|
|
assert_x(connect_to_host(engine, engine->hostname, port), NULL);
|
|
}
|
|
}
|
|
|
|
if (engine->ds_flags & DS_VERBOSE)
|
|
dump_engine(engine);
|
|
|
|
switch (engine->sr_mode){
|
|
case SR_SENDER:
|
|
bs_sender(engine);
|
|
break;
|
|
case SR_RECEIVER:
|
|
bs_receiver(engine);
|
|
break;
|
|
case SR_TEST:
|
|
bs_test(engine);
|
|
break;
|
|
default:
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
close(engine->file);
|
|
close(engine->listenSocket);
|
|
close(engine->clientSocket);
|
|
|
|
if (engine)
|
|
free(engine);
|
|
}
|
|
|
|
int accept_connection(bsync_engine_t *engine, char *hostname, int port){
|
|
struct addrinfo hints;
|
|
struct addrinfo *result, *ai;
|
|
int one = 1;
|
|
char sport[12];
|
|
sprintf(sport, "%d", port);
|
|
|
|
memset( &hints, 0, sizeof(hints));
|
|
hints.ai_family = af;
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
hints.ai_flags = AI_PASSIVE;
|
|
|
|
int s = getaddrinfo(hostname[0] ? hostname : NULL, sport, &hints, &result);
|
|
if (s != 0) {
|
|
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
for (ai = result; ai != NULL; ai = ai->ai_next) {
|
|
engine->listenSocket = socket( ai->ai_family, ai->ai_socktype, ai->ai_protocol );
|
|
if (engine->listenSocket < 0)
|
|
continue;
|
|
|
|
setsockopt( engine->listenSocket, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
|
|
|
|
if (bind(engine->listenSocket, ai->ai_addr, ai->ai_addrlen)!=-1)
|
|
break;
|
|
|
|
close(engine->listenSocket);
|
|
}
|
|
|
|
if (ai == NULL){
|
|
fprintf(stderr, "could not bind to %s : %d\n", hostname, port);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
freeaddrinfo(result);
|
|
|
|
listen(engine->listenSocket, 1);
|
|
|
|
engine->clientSocket = accept( engine->listenSocket, NULL, 0);
|
|
if (engine->clientSocket < 0){
|
|
fprintf(stderr, "no one connected\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int connect_to_host(bsync_engine_t *engine, char *hostname, int port){
|
|
struct addrinfo hints;
|
|
struct addrinfo *result, *ai;
|
|
char sport[12];
|
|
sprintf(sport, "%d", port);
|
|
|
|
memset( &hints, 0, sizeof(hints));
|
|
hints.ai_family = af;
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
|
int s = getaddrinfo(hostname, sport, &hints, &result);
|
|
if (s != 0) {
|
|
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
for (ai = result; ai != NULL; ai = ai->ai_next) {
|
|
engine->clientSocket = socket( ai->ai_family, ai->ai_socktype, ai->ai_protocol );
|
|
if (engine->clientSocket < 0)
|
|
continue;
|
|
if (connect(engine->clientSocket, ai->ai_addr, ai->ai_addrlen)!=-1)
|
|
break;
|
|
|
|
close(engine->clientSocket);
|
|
}
|
|
|
|
if (ai == NULL){
|
|
fprintf(stderr, "could not connect to host %s : %d\n", hostname, port);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
freeaddrinfo(result);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void dump_engine(bsync_engine_t *engine){
|
|
fprintf( stderr, "blksync engine dump:\n");
|
|
fprintf( stderr,"sr_mode=%x ds_flags=%x\n", engine->sr_mode, engine->ds_flags);
|
|
fprintf( stderr,"filename=%s\n", engine->filename);
|
|
fprintf( stderr,"filesize=%ld (0x%lx)\n", engine->filesize, engine->filesize);
|
|
fprintf( stderr,"hostname=%s\n", engine->hostname);
|
|
fprintf( stderr,"blocksize=%d\n", engine->blocksize);
|
|
fprintf( stderr,"file=%d\n", engine->file);
|
|
fprintf( stderr,"listenSocket=%d\n", engine->listenSocket);
|
|
fprintf( stderr,"clientSocket=%d\n", engine->clientSocket);
|
|
fprintf( stderr,"\n");
|
|
fflush(stderr);
|
|
}
|
|
|
|
bsync_engine_t *create_engine(){
|
|
bsync_engine_t *engine = malloc(sizeof(bsync_engine_t));
|
|
if (engine) {
|
|
memset(engine, 0, sizeof(bsync_engine_t));
|
|
pthread_mutex_init(&engine->m_file, NULL);
|
|
pthread_mutex_init(&engine->m_socket, NULL);
|
|
|
|
engine->t_start = time(NULL);
|
|
}
|
|
return engine;
|
|
}
|
|
|