summaryrefslogtreecommitdiffstats
path: root/libcutils/adb_networking.c
diff options
context:
space:
mode:
Diffstat (limited to 'libcutils/adb_networking.c')
-rw-r--r--libcutils/adb_networking.c172
1 files changed, 172 insertions, 0 deletions
diff --git a/libcutils/adb_networking.c b/libcutils/adb_networking.c
new file mode 100644
index 0000000..d819d44
--- /dev/null
+++ b/libcutils/adb_networking.c
@@ -0,0 +1,172 @@
+/* libs/utils/adb_networking.c
+**
+** Copyright 2006, 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.
+*/
+
+#define ADB_PORT 5037
+
+#define _GNU_SOURCE /* for asprintf */
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include <cutils/adb_networking.h>
+#include <cutils/sockets.h>
+#include <cutils/properties.h>
+
+#define ADB_RESPONSE_SIZE 4
+
+/**
+ * Unfortunately, java.net.Socket wants to create it's filedescriptor early
+ * So, this function takes an fd that must be an unconnected
+ * PF_LOCAL SOCK_STREAM
+ */
+int adb_networking_connect_fd(int fd, struct sockaddr_in *p_address)
+{
+ struct sockaddr_in local_addr;
+ socklen_t alen;
+ char *cmd;
+ char buf[ADB_RESPONSE_SIZE + 1];
+ ssize_t count_read;
+ int ret;
+ int err;
+ /* for impl of inet_ntoa below*/
+ union {
+ uint8_t b[4];
+ uint32_t l;
+ } a;
+
+ /* First, connect to adb */
+
+ memset(&local_addr, 0, sizeof(local_addr));
+ local_addr.sin_family = AF_INET;
+ local_addr.sin_port = htons(ADB_PORT);
+ local_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ do {
+ err = connect(fd, (struct sockaddr *) &local_addr, sizeof(local_addr));
+ } while (err < 0 && errno == EINTR);
+
+ if (err < 0) {
+ return -1;
+ }
+
+ a.l = p_address->sin_addr.s_addr;
+
+ // compose the command
+ asprintf(&cmd, "tcp:%u:%u.%u.%u.%u",
+ (unsigned int)ntohs(p_address->sin_port),
+ a.b[0],a.b[1],a.b[2],a.b[3]);
+
+ // buf is now the ascii hex length of cmd
+ snprintf(buf, sizeof(buf), "%04X", strlen(cmd));
+
+ // write the 4-byte length
+ do {
+ err = write(fd, buf, 4);
+ } while (err < 0 && errno == EINTR);
+
+ // write the command
+ do {
+ err = write(fd, cmd, strlen(cmd));
+ } while (err < 0 && errno == EINTR);
+
+ // read the result
+ do {
+ count_read = read(fd, buf, sizeof(buf) - 1);
+ } while (count_read < 0 && errno != EINTR);
+
+ if (count_read == ADB_RESPONSE_SIZE
+ && 0 == strncmp(buf, "OKAY", ADB_RESPONSE_SIZE)) {
+ ret = 0;
+ } else {
+ /* what errno here? <shrug? */
+ errno = ENETUNREACH;
+ ret = -1;
+ }
+
+ free(cmd);
+
+ return ret;
+}
+
+/**
+ * Fills in *p_out_addr and returns 0 on success
+ * Memset's *p_out_addr and returns -1 on fail
+ */
+
+int adb_networking_gethostbyname(const char *name, struct in_addr *p_out_addr)
+{
+ int fd;
+ char *cmd = NULL;
+ char buf[ADB_RESPONSE_SIZE + 1];
+ int err;
+ ssize_t count_read;
+
+ fd = socket_loopback_client(ADB_PORT, SOCK_STREAM);
+
+ if (fd < 0) {
+ return -1;
+ }
+
+ // compose the command
+ asprintf(&cmd, "dns:%s", name);
+
+ // buf is now the ascii hex length of cmd
+ snprintf(buf, sizeof(buf), "%04X", strlen(cmd));
+
+ // write the 4-byte length
+ do {
+ err = write(fd, buf, 4);
+ } while (err < 0 && errno == EINTR);
+
+ // write the command
+ do {
+ err = write(fd, cmd, strlen(cmd));
+ } while (err < 0 && errno == EINTR);
+
+ // read the result
+ do {
+ count_read = read(fd, buf, ADB_RESPONSE_SIZE);
+ } while (count_read < 0 && errno != EINTR);
+
+ if (count_read != ADB_RESPONSE_SIZE
+ || 0 != strncmp(buf, "OKAY", ADB_RESPONSE_SIZE)) {
+ goto error;
+ }
+
+ // read the actual IP address
+ do {
+ count_read = read(fd, &(p_out_addr->s_addr), sizeof(p_out_addr->s_addr));
+ } while (count_read < 0 && errno != EINTR);
+
+ if (count_read != 4) {
+ goto error;
+ }
+
+ free(cmd);
+ close(fd);
+ return 0;
+error:
+ free(cmd);
+ close(fd);
+ memset(p_out_addr, 0, sizeof(struct in_addr));
+ return -1;
+}
+