diff --git a/src/api.c b/src/api.c index d9d6669..a089c15 100644 --- a/src/api.c +++ b/src/api.c @@ -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; } diff --git a/src/caniadd.c b/src/caniadd.c index d81e799..3377791 100644 --- a/src/caniadd.c +++ b/src/caniadd.c @@ -1,17 +1,39 @@ #include #include #include +#include +#include #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(); diff --git a/src/ed2k_util.c b/src/ed2k_util.c index ae7b63f..ce90e82 100644 --- a/src/ed2k_util.c +++ b/src/ed2k_util.c @@ -3,10 +3,12 @@ #include #include #include +#include #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, diff --git a/src/error.h b/src/error.h index cf2b673..23695a7 100644 --- a/src/error.h +++ b/src/error.h @@ -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) \ diff --git a/src/globals.h b/src/globals.h new file mode 100644 index 0000000..0414a30 --- /dev/null +++ b/src/globals.h @@ -0,0 +1,7 @@ +#ifndef _GLOBALS_H +#define _GLOBALS_H +#include + +extern bool should_exit; + +#endif /* _GLOBALS_H */ diff --git a/src/net.c b/src/net.c index 4bc86a1..7c6ac2b 100644 --- a/src/net.c +++ b/src/net.c @@ -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; } diff --git a/src/net.h b/src/net.h index 6021e9c..347b59c 100644 --- a/src/net.h +++ b/src/net.h @@ -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);