blob: 76a03ebff1e1838c81d9ba15a3acc5712f6864b4 [file] [log] [blame]
Dan Alberte9fca142015-02-18 18:03:26 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "adb_listeners.h"
18
Dan Alberte9fca142015-02-18 18:03:26 -080019#include "sysdeps.h"
20
21int gListenAll = 0; /* Not static because it is used in commandline.c. */
22
23alistener listener_list = {
24 .next = &listener_list,
25 .prev = &listener_list,
26};
27
28void ss_listener_event_func(int _fd, unsigned ev, void *_l)
29{
30 asocket *s;
31
32 if(ev & FDE_READ) {
33 struct sockaddr addr;
34 socklen_t alen;
35 int fd;
36
37 alen = sizeof(addr);
38 fd = adb_socket_accept(_fd, &addr, &alen);
39 if(fd < 0) return;
40
41 adb_socket_setbufsize(fd, CHUNK_SIZE);
42
43 s = create_local_socket(fd);
44 if(s) {
45 connect_to_smartsocket(s);
46 return;
47 }
48
49 adb_close(fd);
50 }
51}
52
53void listener_event_func(int _fd, unsigned ev, void *_l)
54{
55 alistener *l = _l;
56 asocket *s;
57
58 if(ev & FDE_READ) {
59 struct sockaddr addr;
60 socklen_t alen;
61 int fd;
62
63 alen = sizeof(addr);
64 fd = adb_socket_accept(_fd, &addr, &alen);
65 if(fd < 0) return;
66
67 s = create_local_socket(fd);
68 if(s) {
69 s->transport = l->transport;
70 connect_to_remote(s, l->connect_to);
71 return;
72 }
73
74 adb_close(fd);
75 }
76}
77
78static void free_listener(alistener* l)
79{
80 if (l->next) {
81 l->next->prev = l->prev;
82 l->prev->next = l->next;
83 l->next = l->prev = l;
84 }
85
86 // closes the corresponding fd
87 fdevent_remove(&l->fde);
88
89 if (l->local_name)
90 free((char*)l->local_name);
91
92 if (l->connect_to)
93 free((char*)l->connect_to);
94
95 if (l->transport) {
96 remove_transport_disconnect(l->transport, &l->disconnect);
97 }
98 free(l);
99}
100
101void listener_disconnect(void* _l, atransport* t)
102{
103 alistener* l = _l;
104
105 free_listener(l);
106}
107
108int local_name_to_fd(const char *name)
109{
110 int port;
111
112 if(!strncmp("tcp:", name, 4)){
113 int ret;
114 port = atoi(name + 4);
115
116 if (gListenAll > 0) {
117 ret = socket_inaddr_any_server(port, SOCK_STREAM);
118 } else {
119 ret = socket_loopback_server(port, SOCK_STREAM);
120 }
121
122 return ret;
123 }
124#ifndef HAVE_WIN32_IPC /* no Unix-domain sockets on Win32 */
125 // It's non-sensical to support the "reserved" space on the adb host side
126 if(!strncmp(name, "local:", 6)) {
127 return socket_local_server(name + 6,
128 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
129 } else if(!strncmp(name, "localabstract:", 14)) {
130 return socket_local_server(name + 14,
131 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
132 } else if(!strncmp(name, "localfilesystem:", 16)) {
133 return socket_local_server(name + 16,
134 ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
135 }
136
137#endif
138 printf("unknown local portname '%s'\n", name);
139 return -1;
140}
141
142// Write a single line describing a listener to a user-provided buffer.
143// Appends a trailing zero, even in case of truncation, but the function
144// returns the full line length.
145// If |buffer| is NULL, does not write but returns required size.
146static int format_listener(alistener* l, char* buffer, size_t buffer_len) {
147 // Format is simply:
148 //
149 // <device-serial> " " <local-name> " " <remote-name> "\n"
150 //
151 int local_len = strlen(l->local_name);
152 int connect_len = strlen(l->connect_to);
153 int serial_len = strlen(l->transport->serial);
154
155 if (buffer != NULL) {
156 snprintf(buffer, buffer_len, "%s %s %s\n",
157 l->transport->serial, l->local_name, l->connect_to);
158 }
159 // NOTE: snprintf() on Windows returns -1 in case of truncation, so
160 // return the computed line length instead.
161 return local_len + connect_len + serial_len + 3;
162}
163
164// Write the list of current listeners (network redirections) into a
165// user-provided buffer. Appends a trailing zero, even in case of
166// trunctaion, but return the full size in bytes.
167// If |buffer| is NULL, does not write but returns required size.
168int format_listeners(char* buf, size_t buflen)
169{
170 alistener* l;
171 int result = 0;
172 for (l = listener_list.next; l != &listener_list; l = l->next) {
173 // Ignore special listeners like those for *smartsocket*
174 if (l->connect_to[0] == '*')
175 continue;
176 int len = format_listener(l, buf, buflen);
177 // Ensure there is space for the trailing zero.
178 result += len;
179 if (buf != NULL) {
180 buf += len;
181 buflen -= len;
182 if (buflen <= 0)
183 break;
184 }
185 }
186 return result;
187}
188
189int remove_listener(const char *local_name, atransport* transport)
190{
191 alistener *l;
192
193 for (l = listener_list.next; l != &listener_list; l = l->next) {
194 if (!strcmp(local_name, l->local_name)) {
195 listener_disconnect(l, l->transport);
196 return 0;
197 }
198 }
199 return -1;
200}
201
202void remove_all_listeners(void)
203{
204 alistener *l, *l_next;
205 for (l = listener_list.next; l != &listener_list; l = l_next) {
206 l_next = l->next;
207 // Never remove smart sockets.
208 if (l->connect_to[0] == '*')
209 continue;
210 listener_disconnect(l, l->transport);
211 }
212}
213
214install_status_t install_listener(const char *local_name,
215 const char *connect_to,
216 atransport* transport,
217 int no_rebind)
218{
219 alistener *l;
220
221 //printf("install_listener('%s','%s')\n", local_name, connect_to);
222
223 for(l = listener_list.next; l != &listener_list; l = l->next){
224 if(strcmp(local_name, l->local_name) == 0) {
225 char *cto;
226
227 /* can't repurpose a smartsocket */
228 if(l->connect_to[0] == '*') {
229 return INSTALL_STATUS_INTERNAL_ERROR;
230 }
231
232 /* can't repurpose a listener if 'no_rebind' is true */
233 if (no_rebind) {
234 return INSTALL_STATUS_CANNOT_REBIND;
235 }
236
237 cto = strdup(connect_to);
238 if(cto == 0) {
239 return INSTALL_STATUS_INTERNAL_ERROR;
240 }
241
242 //printf("rebinding '%s' to '%s'\n", local_name, connect_to);
243 free((void*) l->connect_to);
244 l->connect_to = cto;
245 if (l->transport != transport) {
246 remove_transport_disconnect(l->transport, &l->disconnect);
247 l->transport = transport;
248 add_transport_disconnect(l->transport, &l->disconnect);
249 }
250 return INSTALL_STATUS_OK;
251 }
252 }
253
254 if((l = calloc(1, sizeof(alistener))) == 0) goto nomem;
255 if((l->local_name = strdup(local_name)) == 0) goto nomem;
256 if((l->connect_to = strdup(connect_to)) == 0) goto nomem;
257
258
259 l->fd = local_name_to_fd(local_name);
260 if(l->fd < 0) {
261 free((void*) l->local_name);
262 free((void*) l->connect_to);
263 free(l);
264 printf("cannot bind '%s'\n", local_name);
265 return -2;
266 }
267
268 close_on_exec(l->fd);
269 if(!strcmp(l->connect_to, "*smartsocket*")) {
270 fdevent_install(&l->fde, l->fd, ss_listener_event_func, l);
271 } else {
272 fdevent_install(&l->fde, l->fd, listener_event_func, l);
273 }
274 fdevent_set(&l->fde, FDE_READ);
275
276 l->next = &listener_list;
277 l->prev = listener_list.prev;
278 l->next->prev = l;
279 l->prev->next = l;
280 l->transport = transport;
281
282 if (transport) {
283 l->disconnect.opaque = l;
284 l->disconnect.func = listener_disconnect;
285 add_transport_disconnect(transport, &l->disconnect);
286 }
287 return INSTALL_STATUS_OK;
288
289nomem:
290 fatal("cannot allocate listener");
291 return INSTALL_STATUS_INTERNAL_ERROR;
292}