From feed7cc1f965dba94ec8c8919bd9b5541f8464ce Mon Sep 17 00:00:00 2001 From: Max Lv Date: Fri, 24 Jul 2015 10:42:46 +0800 Subject: [PATCH] add android ipc function --- src/android.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/android.h | 45 +++++++++++ src/local.c | 64 ++++++++++++---- 3 files changed, 299 insertions(+), 13 deletions(-) create mode 100644 src/android.c create mode 100644 src/android.h diff --git a/src/android.c b/src/android.c new file mode 100644 index 00000000..8a51ba43 --- /dev/null +++ b/src/android.c @@ -0,0 +1,203 @@ +/* + * android.c - Setup IPC for shadowsocks-android + * + * Copyright (C) 2013 - 2015, Max Lv + * + * This file is part of the shadowsocks-libev. + * + * shadowsocks-libev is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * shadowsocks-libev is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with shadowsocks-libev; see the file COPYING. If not, see + * . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "netutils.h" +#include "utils.h" +#include "android.h" + +#ifndef EAGAIN +#define EAGAIN EWOULDBLOCK +#endif + +#ifndef EWOULDBLOCK +#define EWOULDBLOCK EAGAIN +#endif + +static void remote_recv_cb(EV_P_ ev_io *w, int revents); +static void remote_send_cb(EV_P_ ev_io *w, int revents); + +static struct remote * new_remote(int fd, int timeout); + +static void free_remote(struct remote *remote); +static void close_and_free_remote(EV_P_ struct remote *remote); + +int verbose = 0; + +static int setnonblocking(int fd) +{ + int flags; + if (-1 == (flags = fcntl(fd, F_GETFL, 0))) { + flags = 0; + } + return fcntl(fd, F_SETFL, flags | O_NONBLOCK); +} + +static void remote_timeout_cb(EV_P_ ev_timer *watcher, int revents) +{ + struct remote_ctx *remote_ctx = (struct remote_ctx *)(((void *)watcher) - sizeof(ev_io)); + struct remote *remote = remote_ctx->remote; + + if (verbose) { + LOGI("[android] IPC connection timeout"); + } + + remote->protect_cb(-1, remote->data); + close_and_free_remote(EV_A_ remote); +} + +static void remote_recv_cb(EV_P_ ev_io *w, int revents) +{ + struct remote_ctx *remote_recv_ctx = (struct remote_ctx *)w; + struct remote *remote = remote_recv_ctx->remote; + + int fd, ret = 0; + + if (ancil_recv_fd(remote->fd, &fd)) { + ERROR("[android] ancil_recv_fd"); + ret = -1; + } + + if (fd != remote->protect_fd) { + ret = -1; + } + + remote->protect_cb(ret, remote->data); + close_and_free_remote(remote); +} + +static void remote_send_cb(EV_P_ ev_io *w, int revents) +{ + struct remote_ctx *remote_send_ctx = (struct remote_ctx *)w; + struct remote *remote = remote_send_ctx->remote; + + int r = getpeername(remote->fd, (struct sockaddr *)&addr, &len); + + if (r == 0) { + ev_io_stop(EV_A_ & remote_send_ctx->io); + ev_timer_stop(EV_A_ & remote_send_ctx->watcher); + + if (ancil_send_fd(remote->fd, remote->protect_fd)) { + ERROR("[android] ancil_send_fd"); + remote->protect_cb(-1, remote->data); + close_and_free_remote(EV_A_ remote); + return; + } + + ev_io_start(EV_A_ & remote->recv_ctx->io); + ev_timer_start(EV_A_ & remote->recv_ctx->watcher); + } else { + ERROR("[android] getpeername"); + remote->protect_cb(-1, remote->data); + close_and_free_remote(EV_A_ remote); + return; + } +} + + +static struct remote * new_remote(int fd, int timeout) +{ + struct remote *remote; + remote = malloc(sizeof(struct remote)); + remote->recv_ctx = malloc(sizeof(struct remote_ctx)); + remote->send_ctx = malloc(sizeof(struct remote_ctx)); + remote->fd = fd; + 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, timeout, 0); + ev_timer_init(&remote->recv_ctx->watcher, remote_timeout_cb, timeout, 0); + remote->recv_ctx->remote = remote; + remote->send_ctx->remote = remote; + return remote; +} + +static void free_remote(struct remote *remote) +{ + if (remote != NULL) { + free(remote->recv_ctx); + free(remote->send_ctx); + free(remote); + } +} + +static void close_and_free_remote(EV_P_ struct remote *remote) +{ + if (remote != NULL) { + ev_timer_stop(EV_A_ & remote->send_ctx->watcher); + ev_timer_stop(EV_A_ & remote->recv_ctx->watcher); + ev_io_stop(EV_A_ & remote->send_ctx->io); + ev_io_stop(EV_A_ & remote->recv_ctx->io); + close(remote->fd); + free_remote(remote); + } +} + +int protect_socket(void (*protect_cb)(int ret, void *data), void *data, int fd) { + // Inilitialize ev loop + struct ev_loop *loop = EV_DEFAULT; + + int remotefd; + struct sockaddr_un addr; + + // Setup + setnonblocking(remotefd); + + if ( (remotefd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + LOGE("[android] socket() failed: %s (socket fd = %d)\n", strerror(errno), remotefd); + return -1; + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, "/data/data/com.github.shadowsocks/protect_path", sizeof(addr.sun_path)-1); + + struct remote *remote = new_remote(remotefd, 100); + + remote->protect_fd = fd; + remote->protect_cb = protect_cb; + remote->data = data; + + if (connect(remotefd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { + LOGE("[android] connect() failed: %s (fd = %d)\n", strerror(errno), remotefd); + close(remotefd); + return -1 + } + + // listen to remote connected event + ev_io_start(EV_A_ & remote->send_ctx->io); + ev_timer_start(EV_A_ & remote->send_ctx->watcher); + + return 0; +} + diff --git a/src/android.h b/src/android.h new file mode 100644 index 00000000..d7d430d8 --- /dev/null +++ b/src/android.h @@ -0,0 +1,45 @@ +/* + * android.h - Define Android IPC's buffers and callbacks + * + * Copyright (C) 2013 - 2015, Max Lv + * + * This file is part of the shadowsocks-libev. + * + * shadowsocks-libev is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * shadowsocks-libev is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with shadowsocks-libev; see the file COPYING. If not, see + * . + */ + +#ifndef _ANDROID_H +#define _ANDROID_H + +#include + +#include "common.h" + +struct remote_ctx { + ev_io io; + ev_timer watcher; + struct remote *remote; +}; + +struct remote { + int fd; + int protect_fd; + void *data; + void (*protect_cb)(int ret, void *data); + struct remote_ctx *recv_ctx; + struct remote_ctx *send_ctx; +}; + +#endif // _ANDROID_H diff --git a/src/local.c b/src/local.c index d67fd1d5..244a3197 100644 --- a/src/local.c +++ b/src/local.c @@ -67,6 +67,10 @@ #include "acl.h" #include "local.h" +#ifdef ANDROID +#include "android.h" +#endif + #ifndef EAGAIN #define EAGAIN EWOULDBLOCK #endif @@ -98,6 +102,8 @@ static void remote_send_cb(EV_P_ ev_io *w, int revents); static void accept_cb(EV_P_ ev_io *w, int revents); static void signal_cb(EV_P_ ev_signal *w, int revents); +static void protect_cb(int ret, void *data); + static int create_and_bind(const char *addr, const char *port); static struct remote * create_remote(struct listen_ctx *listener, struct sockaddr *addr); static void free_remote(struct remote *remote); @@ -195,6 +201,26 @@ static void free_connections(struct ev_loop *loop) } } +#ifdef ANDROID +static void protect_cb(int ret, void *data) { + struct remote_ctx *remote_ctx = (struct remote_ctx *)data; + struct remote *remote = remote_ctx->remote; + struct server *server = remote->server; + + if (verbose) { + LOGI("[android] one connection protected"); + } + + if (ret == -1) { + close_and_free_remote(EV_DEFAULT, remote); + close_and_free_remote(EV_DEFAULT, server); + return; + } + + server_recv_cb(EV_DEFAULT, server->recv_ctx, EV_CUSTOM); +} +#endif + static void server_recv_cb(EV_P_ ev_io *w, int revents) { struct server_ctx *server_recv_ctx = (struct server_ctx *)w; @@ -208,23 +234,27 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) buf = remote->buf; } - ssize_t r = recv(server->fd, buf, BUF_SIZE, 0); + ssize_t r; - if (r == 0) { - // connection closed - close_and_free_remote(EV_A_ remote); - close_and_free_server(EV_A_ server); - return; - } else if (r < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK) { - // no data - // continue to wait for recv - return; - } else { - ERROR("server_recv_cb_recv"); + if (revents != EV_CUSTOM) { + r = recv(server->fd, buf, BUF_SIZE, 0); + + if (r == 0) { + // connection closed close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; + } else if (r < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + // no data + // continue to wait for recv + return; + } else { + ERROR("server_recv_cb_recv"); + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } } } @@ -237,6 +267,14 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) return; } +#ifdef ANDROID + if (revents != EV_CUSTOM) { + ev_io_stop(EV_A_ & server_recv_ctx->io); + protect_socket(protect_cb, (void*)remote, remote->fd); + return; + } +#endif + // insert shadowsocks header if (!remote->direct) { remote->buf = ss_encrypt(BUF_SIZE, remote->buf, &r,