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