173 lines
4.2 KiB
C
173 lines
4.2 KiB
C
/* 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;
|
|
}
|
|
|