Move the listener code into its own file.
Change-Id: I7332455ed1a213daedeaa4a81260edf08b2fd131
diff --git a/Android.mk b/Android.mk
index 51318ef..702300b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -16,6 +16,7 @@
# get enough of adb in here that we no longer need minadb. https://b/17626262
LIBADB_SRC_FILES := \
adb_auth.c \
+ adb_listeners.c \
transport.c \
transport_usb.c \
diff --git a/adb.c b/adb.c
index a336478..69d9d0f 100644
--- a/adb.c
+++ b/adb.c
@@ -30,6 +30,7 @@
#include "sysdeps.h"
#include "adb.h"
#include "adb_auth.h"
+#include "adb_listeners.h"
#include "qemu_tracing.h"
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
@@ -49,7 +50,6 @@
#endif
int HOST = 0;
-int gListenAll = 0;
static int auth_enabled = 0;
@@ -550,285 +550,6 @@
put_apacket(p);
}
-alistener listener_list = {
- .next = &listener_list,
- .prev = &listener_list,
-};
-
-static void ss_listener_event_func(int _fd, unsigned ev, void *_l)
-{
- asocket *s;
-
- if(ev & FDE_READ) {
- struct sockaddr addr;
- socklen_t alen;
- int fd;
-
- alen = sizeof(addr);
- fd = adb_socket_accept(_fd, &addr, &alen);
- if(fd < 0) return;
-
- adb_socket_setbufsize(fd, CHUNK_SIZE);
-
- s = create_local_socket(fd);
- if(s) {
- connect_to_smartsocket(s);
- return;
- }
-
- adb_close(fd);
- }
-}
-
-static void listener_event_func(int _fd, unsigned ev, void *_l)
-{
- alistener *l = _l;
- asocket *s;
-
- if(ev & FDE_READ) {
- struct sockaddr addr;
- socklen_t alen;
- int fd;
-
- alen = sizeof(addr);
- fd = adb_socket_accept(_fd, &addr, &alen);
- if(fd < 0) return;
-
- s = create_local_socket(fd);
- if(s) {
- s->transport = l->transport;
- connect_to_remote(s, l->connect_to);
- return;
- }
-
- adb_close(fd);
- }
-}
-
-static void free_listener(alistener* l)
-{
- if (l->next) {
- l->next->prev = l->prev;
- l->prev->next = l->next;
- l->next = l->prev = l;
- }
-
- // closes the corresponding fd
- fdevent_remove(&l->fde);
-
- if (l->local_name)
- free((char*)l->local_name);
-
- if (l->connect_to)
- free((char*)l->connect_to);
-
- if (l->transport) {
- remove_transport_disconnect(l->transport, &l->disconnect);
- }
- free(l);
-}
-
-static void listener_disconnect(void* _l, atransport* t)
-{
- alistener* l = _l;
-
- free_listener(l);
-}
-
-int local_name_to_fd(const char *name)
-{
- int port;
-
- if(!strncmp("tcp:", name, 4)){
- int ret;
- port = atoi(name + 4);
-
- if (gListenAll > 0) {
- ret = socket_inaddr_any_server(port, SOCK_STREAM);
- } else {
- ret = socket_loopback_server(port, SOCK_STREAM);
- }
-
- return ret;
- }
-#ifndef HAVE_WIN32_IPC /* no Unix-domain sockets on Win32 */
- // It's non-sensical to support the "reserved" space on the adb host side
- if(!strncmp(name, "local:", 6)) {
- return socket_local_server(name + 6,
- ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
- } else if(!strncmp(name, "localabstract:", 14)) {
- return socket_local_server(name + 14,
- ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
- } else if(!strncmp(name, "localfilesystem:", 16)) {
- return socket_local_server(name + 16,
- ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
- }
-
-#endif
- printf("unknown local portname '%s'\n", name);
- return -1;
-}
-
-// Write a single line describing a listener to a user-provided buffer.
-// Appends a trailing zero, even in case of truncation, but the function
-// returns the full line length.
-// If |buffer| is NULL, does not write but returns required size.
-static int format_listener(alistener* l, char* buffer, size_t buffer_len) {
- // Format is simply:
- //
- // <device-serial> " " <local-name> " " <remote-name> "\n"
- //
- int local_len = strlen(l->local_name);
- int connect_len = strlen(l->connect_to);
- int serial_len = strlen(l->transport->serial);
-
- if (buffer != NULL) {
- snprintf(buffer, buffer_len, "%s %s %s\n",
- l->transport->serial, l->local_name, l->connect_to);
- }
- // NOTE: snprintf() on Windows returns -1 in case of truncation, so
- // return the computed line length instead.
- return local_len + connect_len + serial_len + 3;
-}
-
-// Write the list of current listeners (network redirections) into a
-// user-provided buffer. Appends a trailing zero, even in case of
-// trunctaion, but return the full size in bytes.
-// If |buffer| is NULL, does not write but returns required size.
-static int format_listeners(char* buf, size_t buflen)
-{
- alistener* l;
- int result = 0;
- for (l = listener_list.next; l != &listener_list; l = l->next) {
- // Ignore special listeners like those for *smartsocket*
- if (l->connect_to[0] == '*')
- continue;
- int len = format_listener(l, buf, buflen);
- // Ensure there is space for the trailing zero.
- result += len;
- if (buf != NULL) {
- buf += len;
- buflen -= len;
- if (buflen <= 0)
- break;
- }
- }
- return result;
-}
-
-static int remove_listener(const char *local_name, atransport* transport)
-{
- alistener *l;
-
- for (l = listener_list.next; l != &listener_list; l = l->next) {
- if (!strcmp(local_name, l->local_name)) {
- listener_disconnect(l, l->transport);
- return 0;
- }
- }
- return -1;
-}
-
-static void remove_all_listeners(void)
-{
- alistener *l, *l_next;
- for (l = listener_list.next; l != &listener_list; l = l_next) {
- l_next = l->next;
- // Never remove smart sockets.
- if (l->connect_to[0] == '*')
- continue;
- listener_disconnect(l, l->transport);
- }
-}
-
-// error/status codes for install_listener.
-typedef enum {
- INSTALL_STATUS_OK = 0,
- INSTALL_STATUS_INTERNAL_ERROR = -1,
- INSTALL_STATUS_CANNOT_BIND = -2,
- INSTALL_STATUS_CANNOT_REBIND = -3,
-} install_status_t;
-
-static install_status_t install_listener(const char *local_name,
- const char *connect_to,
- atransport* transport,
- int no_rebind)
-{
- alistener *l;
-
- //printf("install_listener('%s','%s')\n", local_name, connect_to);
-
- for(l = listener_list.next; l != &listener_list; l = l->next){
- if(strcmp(local_name, l->local_name) == 0) {
- char *cto;
-
- /* can't repurpose a smartsocket */
- if(l->connect_to[0] == '*') {
- return INSTALL_STATUS_INTERNAL_ERROR;
- }
-
- /* can't repurpose a listener if 'no_rebind' is true */
- if (no_rebind) {
- return INSTALL_STATUS_CANNOT_REBIND;
- }
-
- cto = strdup(connect_to);
- if(cto == 0) {
- return INSTALL_STATUS_INTERNAL_ERROR;
- }
-
- //printf("rebinding '%s' to '%s'\n", local_name, connect_to);
- free((void*) l->connect_to);
- l->connect_to = cto;
- if (l->transport != transport) {
- remove_transport_disconnect(l->transport, &l->disconnect);
- l->transport = transport;
- add_transport_disconnect(l->transport, &l->disconnect);
- }
- return INSTALL_STATUS_OK;
- }
- }
-
- if((l = calloc(1, sizeof(alistener))) == 0) goto nomem;
- if((l->local_name = strdup(local_name)) == 0) goto nomem;
- if((l->connect_to = strdup(connect_to)) == 0) goto nomem;
-
-
- l->fd = local_name_to_fd(local_name);
- if(l->fd < 0) {
- free((void*) l->local_name);
- free((void*) l->connect_to);
- free(l);
- printf("cannot bind '%s'\n", local_name);
- return -2;
- }
-
- close_on_exec(l->fd);
- if(!strcmp(l->connect_to, "*smartsocket*")) {
- fdevent_install(&l->fde, l->fd, ss_listener_event_func, l);
- } else {
- fdevent_install(&l->fde, l->fd, listener_event_func, l);
- }
- fdevent_set(&l->fde, FDE_READ);
-
- l->next = &listener_list;
- l->prev = listener_list.prev;
- l->next->prev = l;
- l->prev->next = l;
- l->transport = transport;
-
- if (transport) {
- l->disconnect.opaque = l;
- l->disconnect.func = listener_disconnect;
- add_transport_disconnect(transport, &l->disconnect);
- }
- return INSTALL_STATUS_OK;
-
-nomem:
- fatal("cannot allocate listener");
- return INSTALL_STATUS_INTERNAL_ERROR;
-}
-
#if defined(_WIN32)
static BOOL WINAPI ctrlc_handler(DWORD type)
{
diff --git a/adb_listeners.c b/adb_listeners.c
new file mode 100644
index 0000000..e9d3c22
--- /dev/null
+++ b/adb_listeners.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "adb_listeners.h"
+
+#include <sys/socket.h>
+
+#include "sysdeps.h"
+
+int gListenAll = 0; /* Not static because it is used in commandline.c. */
+
+alistener listener_list = {
+ .next = &listener_list,
+ .prev = &listener_list,
+};
+
+void ss_listener_event_func(int _fd, unsigned ev, void *_l)
+{
+ asocket *s;
+
+ if(ev & FDE_READ) {
+ struct sockaddr addr;
+ socklen_t alen;
+ int fd;
+
+ alen = sizeof(addr);
+ fd = adb_socket_accept(_fd, &addr, &alen);
+ if(fd < 0) return;
+
+ adb_socket_setbufsize(fd, CHUNK_SIZE);
+
+ s = create_local_socket(fd);
+ if(s) {
+ connect_to_smartsocket(s);
+ return;
+ }
+
+ adb_close(fd);
+ }
+}
+
+void listener_event_func(int _fd, unsigned ev, void *_l)
+{
+ alistener *l = _l;
+ asocket *s;
+
+ if(ev & FDE_READ) {
+ struct sockaddr addr;
+ socklen_t alen;
+ int fd;
+
+ alen = sizeof(addr);
+ fd = adb_socket_accept(_fd, &addr, &alen);
+ if(fd < 0) return;
+
+ s = create_local_socket(fd);
+ if(s) {
+ s->transport = l->transport;
+ connect_to_remote(s, l->connect_to);
+ return;
+ }
+
+ adb_close(fd);
+ }
+}
+
+static void free_listener(alistener* l)
+{
+ if (l->next) {
+ l->next->prev = l->prev;
+ l->prev->next = l->next;
+ l->next = l->prev = l;
+ }
+
+ // closes the corresponding fd
+ fdevent_remove(&l->fde);
+
+ if (l->local_name)
+ free((char*)l->local_name);
+
+ if (l->connect_to)
+ free((char*)l->connect_to);
+
+ if (l->transport) {
+ remove_transport_disconnect(l->transport, &l->disconnect);
+ }
+ free(l);
+}
+
+void listener_disconnect(void* _l, atransport* t)
+{
+ alistener* l = _l;
+
+ free_listener(l);
+}
+
+int local_name_to_fd(const char *name)
+{
+ int port;
+
+ if(!strncmp("tcp:", name, 4)){
+ int ret;
+ port = atoi(name + 4);
+
+ if (gListenAll > 0) {
+ ret = socket_inaddr_any_server(port, SOCK_STREAM);
+ } else {
+ ret = socket_loopback_server(port, SOCK_STREAM);
+ }
+
+ return ret;
+ }
+#ifndef HAVE_WIN32_IPC /* no Unix-domain sockets on Win32 */
+ // It's non-sensical to support the "reserved" space on the adb host side
+ if(!strncmp(name, "local:", 6)) {
+ return socket_local_server(name + 6,
+ ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
+ } else if(!strncmp(name, "localabstract:", 14)) {
+ return socket_local_server(name + 14,
+ ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
+ } else if(!strncmp(name, "localfilesystem:", 16)) {
+ return socket_local_server(name + 16,
+ ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
+ }
+
+#endif
+ printf("unknown local portname '%s'\n", name);
+ return -1;
+}
+
+// Write a single line describing a listener to a user-provided buffer.
+// Appends a trailing zero, even in case of truncation, but the function
+// returns the full line length.
+// If |buffer| is NULL, does not write but returns required size.
+static int format_listener(alistener* l, char* buffer, size_t buffer_len) {
+ // Format is simply:
+ //
+ // <device-serial> " " <local-name> " " <remote-name> "\n"
+ //
+ int local_len = strlen(l->local_name);
+ int connect_len = strlen(l->connect_to);
+ int serial_len = strlen(l->transport->serial);
+
+ if (buffer != NULL) {
+ snprintf(buffer, buffer_len, "%s %s %s\n",
+ l->transport->serial, l->local_name, l->connect_to);
+ }
+ // NOTE: snprintf() on Windows returns -1 in case of truncation, so
+ // return the computed line length instead.
+ return local_len + connect_len + serial_len + 3;
+}
+
+// Write the list of current listeners (network redirections) into a
+// user-provided buffer. Appends a trailing zero, even in case of
+// trunctaion, but return the full size in bytes.
+// If |buffer| is NULL, does not write but returns required size.
+int format_listeners(char* buf, size_t buflen)
+{
+ alistener* l;
+ int result = 0;
+ for (l = listener_list.next; l != &listener_list; l = l->next) {
+ // Ignore special listeners like those for *smartsocket*
+ if (l->connect_to[0] == '*')
+ continue;
+ int len = format_listener(l, buf, buflen);
+ // Ensure there is space for the trailing zero.
+ result += len;
+ if (buf != NULL) {
+ buf += len;
+ buflen -= len;
+ if (buflen <= 0)
+ break;
+ }
+ }
+ return result;
+}
+
+int remove_listener(const char *local_name, atransport* transport)
+{
+ alistener *l;
+
+ for (l = listener_list.next; l != &listener_list; l = l->next) {
+ if (!strcmp(local_name, l->local_name)) {
+ listener_disconnect(l, l->transport);
+ return 0;
+ }
+ }
+ return -1;
+}
+
+void remove_all_listeners(void)
+{
+ alistener *l, *l_next;
+ for (l = listener_list.next; l != &listener_list; l = l_next) {
+ l_next = l->next;
+ // Never remove smart sockets.
+ if (l->connect_to[0] == '*')
+ continue;
+ listener_disconnect(l, l->transport);
+ }
+}
+
+install_status_t install_listener(const char *local_name,
+ const char *connect_to,
+ atransport* transport,
+ int no_rebind)
+{
+ alistener *l;
+
+ //printf("install_listener('%s','%s')\n", local_name, connect_to);
+
+ for(l = listener_list.next; l != &listener_list; l = l->next){
+ if(strcmp(local_name, l->local_name) == 0) {
+ char *cto;
+
+ /* can't repurpose a smartsocket */
+ if(l->connect_to[0] == '*') {
+ return INSTALL_STATUS_INTERNAL_ERROR;
+ }
+
+ /* can't repurpose a listener if 'no_rebind' is true */
+ if (no_rebind) {
+ return INSTALL_STATUS_CANNOT_REBIND;
+ }
+
+ cto = strdup(connect_to);
+ if(cto == 0) {
+ return INSTALL_STATUS_INTERNAL_ERROR;
+ }
+
+ //printf("rebinding '%s' to '%s'\n", local_name, connect_to);
+ free((void*) l->connect_to);
+ l->connect_to = cto;
+ if (l->transport != transport) {
+ remove_transport_disconnect(l->transport, &l->disconnect);
+ l->transport = transport;
+ add_transport_disconnect(l->transport, &l->disconnect);
+ }
+ return INSTALL_STATUS_OK;
+ }
+ }
+
+ if((l = calloc(1, sizeof(alistener))) == 0) goto nomem;
+ if((l->local_name = strdup(local_name)) == 0) goto nomem;
+ if((l->connect_to = strdup(connect_to)) == 0) goto nomem;
+
+
+ l->fd = local_name_to_fd(local_name);
+ if(l->fd < 0) {
+ free((void*) l->local_name);
+ free((void*) l->connect_to);
+ free(l);
+ printf("cannot bind '%s'\n", local_name);
+ return -2;
+ }
+
+ close_on_exec(l->fd);
+ if(!strcmp(l->connect_to, "*smartsocket*")) {
+ fdevent_install(&l->fde, l->fd, ss_listener_event_func, l);
+ } else {
+ fdevent_install(&l->fde, l->fd, listener_event_func, l);
+ }
+ fdevent_set(&l->fde, FDE_READ);
+
+ l->next = &listener_list;
+ l->prev = listener_list.prev;
+ l->next->prev = l;
+ l->prev->next = l;
+ l->transport = transport;
+
+ if (transport) {
+ l->disconnect.opaque = l;
+ l->disconnect.func = listener_disconnect;
+ add_transport_disconnect(transport, &l->disconnect);
+ }
+ return INSTALL_STATUS_OK;
+
+nomem:
+ fatal("cannot allocate listener");
+ return INSTALL_STATUS_INTERNAL_ERROR;
+}
diff --git a/adb_listeners.h b/adb_listeners.h
new file mode 100644
index 0000000..14fdcd6
--- /dev/null
+++ b/adb_listeners.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ADB_LISTENERS_H
+#define __ADB_LISTENERS_H
+
+#include "adb.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// error/status codes for install_listener.
+typedef enum {
+ INSTALL_STATUS_OK = 0,
+ INSTALL_STATUS_INTERNAL_ERROR = -1,
+ INSTALL_STATUS_CANNOT_BIND = -2,
+ INSTALL_STATUS_CANNOT_REBIND = -3,
+} install_status_t;
+
+extern alistener listener_list;
+
+void listener_disconnect(void* _l, atransport* t);
+void listener_event_func(int _fd, unsigned ev, void *_l);
+void ss_listener_event_func(int _fd, unsigned ev, void *_l);
+
+install_status_t install_listener(const char *local_name,
+ const char *connect_to,
+ atransport* transport,
+ int no_rebind);
+
+int format_listeners(char* buf, size_t buflen);
+
+int remove_listener(const char *local_name, atransport* transport);
+void remove_all_listeners(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ADB_LISTENERS_H */
diff --git a/transport.h b/transport.h
index c1b8ff3..d95ad32 100644
--- a/transport.h
+++ b/transport.h
@@ -17,6 +17,8 @@
#ifndef __TRANSPORT_H
#define __TRANSPORT_H
+#include <sys/types.h>
+
#ifdef __cplusplus
extern "C" {
#endif