@@ -15,6 +15,7 @@ | |||
#include "config.h" | |||
#include "ed2k.h" | |||
#include "util.h" | |||
#include "globals.h" | |||
/* Needed, bcuz of custom %B format */ | |||
#pragma GCC diagnostic push | |||
@@ -409,10 +410,12 @@ void api_free() | |||
uio_error("Cannot cancel api keepalive thread"); | |||
} else { | |||
int je = pthread_join(api_ka_thread, NULL); | |||
if (je != 0) { | |||
if (je != 0) | |||
uio_error("Cannot join api keepalive thread: %s", | |||
strerror(je)); | |||
} | |||
else | |||
uio_debug("Keepalive thread ended"); | |||
if (pthread_mutex_destroy(&api_work_mx) != 0) | |||
uio_error("Cannot destroy api work mutex"); | |||
} | |||
@@ -473,21 +476,33 @@ static void api_ratelimit() | |||
} | |||
} | |||
/* | |||
* Returns the written byte count | |||
* Or -1 on error, and -2 if errno was EINTR | |||
*/ | |||
static ssize_t api_send(char *buffer, size_t data_len, size_t buf_size) | |||
{ | |||
ssize_t read_len; | |||
int en; | |||
api_ratelimit(); | |||
uio_debug("{Api}: Sending: %.*s", (int)data_len, buffer); | |||
if (api_encryption) | |||
data_len = api_encrypt(buffer, data_len); | |||
if (net_send(buffer, data_len) == -1) { | |||
uio_error("Cannot send data: %s", strerror(errno)); | |||
return -1; | |||
} | |||
en = net_send(buffer, data_len); | |||
if (en < 0) | |||
return en; | |||
read_len = net_read(buffer, buf_size); | |||
if (read_len < 0) { | |||
uio_error("!!! BAD PLACE EINTR !!! report pls"); | |||
return en; /* This could lead so some problems if we also want to | |||
log out. If we hit this, the msg got sent, but we | |||
couldn't read the response. That means, in the | |||
logout call, this msg's data will be read | |||
Let's see if this ever comes up */ | |||
} | |||
api_ratelimit_sent(); | |||
if (api_encryption) | |||
@@ -566,8 +581,11 @@ enum error api_cmd_version(struct api_result *res) | |||
enum error err = NOERR; | |||
pthread_mutex_lock(&api_work_mx); | |||
if (res_len == -1) { | |||
err = ERR_API_COMMFAIL; | |||
if (res_len < 0) { | |||
if (res_len == -2 && should_exit) | |||
err = ERR_SHOULD_EXIT; | |||
else | |||
err = ERR_API_COMMFAIL; | |||
goto end; | |||
} | |||
@@ -607,8 +625,11 @@ static enum error api_cmd_auth(const char *uname, const char *pass, | |||
sizeof(buffer)); | |||
enum error err = NOERR; | |||
if (res_len == -1) { | |||
err = ERR_API_COMMFAIL; | |||
if (res_len < 0) { | |||
if (res_len == -2 && should_exit) | |||
err = ERR_SHOULD_EXIT; | |||
else | |||
err = ERR_API_COMMFAIL; | |||
goto end; | |||
} | |||
@@ -653,8 +674,11 @@ static enum error api_cmd_logout(struct api_result *res) | |||
long code; | |||
enum error err = NOERR; | |||
if (res_len == -1) { | |||
err = ERR_API_COMMFAIL; | |||
if (res_len < 0) { | |||
if (res_len == -2 && should_exit) | |||
err = ERR_SHOULD_EXIT; | |||
else | |||
err = ERR_API_COMMFAIL; | |||
goto end; | |||
} | |||
@@ -683,8 +707,11 @@ enum error api_cmd_uptime(struct api_result *res) | |||
long code; | |||
enum error err = NOERR; | |||
if (res_len == -1) { | |||
err = ERR_API_COMMFAIL; | |||
if (res_len < 0) { | |||
if (res_len == -2 && should_exit) | |||
err = ERR_SHOULD_EXIT; | |||
else | |||
err = ERR_API_COMMFAIL; | |||
goto end; | |||
} | |||
@@ -729,8 +756,11 @@ enum error api_cmd_mylistadd(int64_t size, const uint8_t *hash, | |||
api_session, size, hash_str, ml_state, watched), | |||
sizeof(buffer)); | |||
if (res_len == -1) { | |||
err = ERR_API_COMMFAIL; | |||
if (res_len < 0) { | |||
if (res_len == -2 && should_exit) | |||
err = ERR_SHOULD_EXIT; | |||
else | |||
err = ERR_API_COMMFAIL; | |||
goto end; | |||
} | |||
@@ -1,17 +1,39 @@ | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <signal.h> | |||
#include <errno.h> | |||
#include <string.h> | |||
#include "config.h" | |||
#include "error.h" | |||
#include "uio.h" | |||
#include "cmd.h" | |||
#include "globals.h" | |||
bool should_exit = false; | |||
static void signal_handler(int signum, siginfo_t *info, void *ctx) | |||
{ | |||
should_exit = true; | |||
printf("\033[0GGot C-c. Press again to force exit\n"); | |||
} | |||
int main(int argc, char **argv) | |||
{ | |||
int exit_code = EXIT_SUCCESS; | |||
enum error err = config_parse(argc, argv); | |||
enum error err; | |||
struct sigaction sact = { | |||
.sa_flags = SA_SIGINFO | SA_RESETHAND, | |||
//.sa_flags = SA_SIGINFO, | |||
.sa_sigaction = signal_handler, | |||
}; | |||
if (sigaction(SIGINT, &sact, NULL) != 0) { | |||
uio_error("Cannot set up signal handler: %s", strerror(errno)); | |||
return EXIT_FAILURE; | |||
} | |||
err = config_parse(argc, argv); | |||
if (err == ERR_OPT_EXIT) | |||
return EXIT_SUCCESS; | |||
else if (err != NOERR) | |||
@@ -20,7 +42,9 @@ int main(int argc, char **argv) | |||
//config_dump(); | |||
err = cmd_main(); | |||
if (err != NOERR) | |||
if (err == ERR_SHOULD_EXIT) | |||
uio_debug("Exiting as requested orz"); | |||
else if (err != NOERR) | |||
exit_code = EXIT_FAILURE; | |||
config_free(); | |||
@@ -3,10 +3,12 @@ | |||
#include <string.h> | |||
#include <errno.h> | |||
#include <ftw.h> | |||
#include <assert.h> | |||
#include "ed2k.h" | |||
#include "ed2k_util.h" | |||
#include "uio.h" | |||
#include "globals.h" | |||
static struct ed2k_util_opts l_opts; | |||
@@ -15,11 +17,13 @@ static enum error ed2k_util_hash(const char *file_path, blksize_t blksize, | |||
{ | |||
unsigned char buf[blksize], hash[ED2K_HASH_SIZE]; | |||
struct ed2k_ctx ed2k; | |||
enum error err; | |||
FILE *f; | |||
size_t read_len; | |||
int en; | |||
if (l_opts.pre_hash_fn) { | |||
enum error err = l_opts.pre_hash_fn(file_path, st, l_opts.data); | |||
err = l_opts.pre_hash_fn(file_path, st, l_opts.data); | |||
if (err == ED2KUTIL_DONTHASH) | |||
return NOERR; | |||
else if (err != NOERR) | |||
@@ -28,24 +32,52 @@ static enum error ed2k_util_hash(const char *file_path, blksize_t blksize, | |||
f = fopen(file_path, "rb"); | |||
if (!f) { | |||
uio_error("Failed to open file: %s (%s)", file_path, strerror(errno)); | |||
return ERR_ED2KUTIL_FS; | |||
en = errno; | |||
uio_error("Failed to open file: %s (%s)", file_path, strerror(en)); | |||
if (en == EINTR && should_exit) | |||
return ERR_SHOULD_EXIT; | |||
else | |||
return ERR_ED2KUTIL_FS; | |||
} | |||
ed2k_init(&ed2k); | |||
read_len = fread(buf, 1, sizeof(buf), f); | |||
while (read_len > 0) { | |||
/* From my test, fread wont return anything special on signal interrupt */ | |||
while (read_len > 0 && !should_exit) { | |||
ed2k_update(&ed2k, buf, read_len); | |||
read_len = fread(buf, 1, sizeof(buf), f); | |||
} | |||
// TODO check if eof or error | |||
if (should_exit) { | |||
err = ERR_SHOULD_EXIT; | |||
goto fail; | |||
} | |||
if (ferror(f)) { /* Loop stopped bcuz of error, not EOF */ | |||
uio_error("Failure while reading file"); | |||
err = ERR_ED2KUTIL_FS; | |||
goto fail; | |||
} | |||
assert(feof(f)); | |||
ed2k_final(&ed2k, hash); | |||
fclose(f); | |||
if (fclose(f) != 0) { | |||
en = errno; | |||
uio_debug("Fclose failed: %s", strerror(en)); | |||
if (en == EINTR && should_exit) | |||
return ERR_SHOULD_EXIT; | |||
else | |||
return ERR_ED2KUTIL_FS; | |||
} | |||
if (l_opts.post_hash_fn) | |||
return l_opts.post_hash_fn(file_path, hash, st, l_opts.data); | |||
return NOERR; | |||
fail: | |||
if (f) /* We can't get a 2nd interrupt now */ | |||
fclose(f); | |||
return err; | |||
} | |||
static int ed2k_util_walk(const char *fpath, const struct stat *sb, | |||
@@ -45,6 +45,8 @@ | |||
E(ERR_THRD) /* Generic pthread error */ \ | |||
\ | |||
E(ERR_LIBEVENT) /* There are some problem with a libevent function */ \ | |||
\ | |||
E(ERR_SHOULD_EXIT) /* Probably got a C-c, program should exit now */ \ | |||
E(_ERR_COUNT) \ | |||
@@ -0,0 +1,7 @@ | |||
#ifndef _GLOBALS_H | |||
#define _GLOBALS_H | |||
#include <stdbool.h> | |||
extern bool should_exit; | |||
#endif /* _GLOBALS_H */ |
@@ -248,7 +248,11 @@ ssize_t net_send(const void *msg, size_t msg_len) | |||
{ | |||
ssize_t w_len = send(net_socket, msg, msg_len, 0); | |||
if (w_len == -1) { | |||
uio_error("{net} Send failed: %s", strerror(errno)); | |||
int en = errno; | |||
uio_error("{net} Send failed: %s", strerror(en)); | |||
if (en == EINTR) | |||
return -2; | |||
return -1; | |||
} | |||
return w_len; | |||
@@ -258,8 +262,14 @@ ssize_t net_read(void* out_data, size_t read_size) | |||
{ | |||
ssize_t read = recv(net_socket, out_data, read_size, 0); | |||
if (read == -1) { | |||
int en = errno; | |||
uio_error("{net} Read failed: %s", strerror(errno)); | |||
if (en == EINTR) | |||
return -2; | |||
return -1; | |||
} | |||
if (read == read_size) | |||
uio_warning("{net} Data may have been discarded!"); | |||
return read; | |||
} |
@@ -12,6 +12,8 @@ enum error net_init(); | |||
/* | |||
* Send and read data to and from the api | |||
* Returns the number of bytes sent/read or -1 on error | |||
* If the error is EINTR, it returns -2 | |||
*/ | |||
ssize_t net_send(const void *msg, size_t msg_len); | |||
ssize_t net_read(void *out_data, size_t read_size); | |||