diff --git a/src/android.c b/src/android.c index 6883bd88..761907d7 100644 --- a/src/android.c +++ b/src/android.c @@ -55,10 +55,10 @@ int protect_socket(int fd) return -1; } - // Set timeout to 100us + // Set timeout to 1s struct timeval tv; - tv.tv_sec = 1; /* 0 Secs Timeout */ - tv.tv_usec = 0; // Not init'ing this can cause strange errors + tv.tv_sec = 1; + tv.tv_usec = 0; setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)); setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(struct timeval)); @@ -92,3 +92,53 @@ int protect_socket(int fd) return ret; } +int send_traffic_stat(uint64_t tx, uint64_t rx) +{ + int sock; + struct sockaddr_un addr; + + if ( (sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + LOGE("[android] socket() failed: %s (socket fd = %d)\n", strerror(errno), sock); + return -1; + } + + // Set timeout to 1s + struct timeval tv; + tv.tv_sec = 1; + tv.tv_usec = 0; + setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)); + setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(struct timeval)); + + const char path[] = "/data/data/com.github.shadowsocks/stat_path"; + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); + + if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + LOGE("[android] connect() failed: %s (socket fd = %d)\n", strerror(errno), sock); + close(sock); + return -1; + } + + char stat[256] = {0}; + snprintf(stat, 256, "%" PRIu64 "|%" PRIu64, tx, rx); + size_t len = strlen(stat); + + if (send(sock, stat, len, 0) == -1) { + ERROR("[android] send"); + close(sock); + return -1; + } + + char ret = 0; + + if (recv(sock, &ret, 1, 0) == -1) { + ERROR("[android] recv"); + close(sock); + return -1; + } + + close(sock); + return ret; +} diff --git a/src/common.h b/src/common.h index 862189e5..6404e294 100644 --- a/src/common.h +++ b/src/common.h @@ -66,6 +66,7 @@ void free_udprelay(void); #ifdef ANDROID int protect_socket(int fd); +int send_traffic_stat(uint64_t tx, uint64_t rx); #endif #endif // _COMMON_H diff --git a/src/local.c b/src/local.c index 3c815727..c3703e92 100644 --- a/src/local.c +++ b/src/local.c @@ -82,6 +82,9 @@ int verbose = 0; #ifdef ANDROID int vpn = 0; +uint64_t tx = 0; +uint64_t rx = 0; +ev_timer stat_timer; #endif static int acl = 0; @@ -250,6 +253,9 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) // insert shadowsocks header if (!remote->direct) { +#ifdef ANDROID + tx += r; +#endif remote->buf = ss_encrypt(BUF_SIZE, remote->buf, &r, server->e_ctx); @@ -571,11 +577,19 @@ static void server_send_cb(EV_P_ ev_io *w, int revents) server->buf_idx = 0; ev_io_stop(EV_A_ & server_send_ctx->io); ev_io_start(EV_A_ & remote->recv_ctx->io); + return; } } } +#ifdef ANDROID +static void stat_update_cb(EV_P_ ev_timer *watcher, int revents) +{ + send_traffic_stat(tx, rx); +} +#endif + static void remote_timeout_cb(EV_P_ ev_timer *watcher, int revents) { struct remote_ctx *remote_ctx = (struct remote_ctx *)(((void *)watcher) @@ -620,6 +634,9 @@ static void remote_recv_cb(EV_P_ ev_io *w, int revents) } if (!remote->direct) { +#ifdef ANDROID + rx += r; +#endif server->buf = ss_decrypt(BUF_SIZE, server->buf, &r, server->d_ctx); if (server->buf == NULL) { LOGE("invalid password or cipher"); @@ -733,13 +750,9 @@ static struct remote * new_remote(int fd, int timeout) ev_io_init(&remote->recv_ctx->io, remote_recv_cb, fd, EV_READ); ev_io_init(&remote->send_ctx->io, remote_send_cb, fd, EV_WRITE); ev_timer_init(&remote->send_ctx->watcher, remote_timeout_cb, - min(MAX_CONNECT_TIMEOUT, - timeout), - 0); + min(MAX_CONNECT_TIMEOUT, timeout), 0); ev_timer_init(&remote->recv_ctx->watcher, remote_timeout_cb, - min(MAX_CONNECT_TIMEOUT, - timeout), - timeout); + min(MAX_CONNECT_TIMEOUT, timeout), timeout); remote->recv_ctx->remote = remote; remote->send_ctx->remote = remote; return remote; @@ -1141,6 +1154,11 @@ int main(int argc, char **argv) struct ev_loop *loop = EV_DEFAULT; +#ifdef ANDROID + ev_timer_init(&stat_timer, stat_update_cb, 1, 1); + ev_timer_start(loop, stat_timer); +#endif + // Setup socket int listenfd; listenfd = create_and_bind(local_addr, local_port); @@ -1182,6 +1200,11 @@ int main(int argc, char **argv) } // Clean up + +#ifdef ANDROID + ev_timer_stop(loop, stat_timer); +#endif + ev_io_stop(loop, &listen_ctx.io); free_connections(loop);