Commit 950d35c5 authored by Andreas Zisowsky's avatar Andreas Zisowsky Committed by Kishen Maloor

Add Android port

Signed-off-by: default avatarAndreas Zisowsky <zisowsky@lynxtechnology.com>
Change-Id: I8b69b2aa1049b0789e132dd3a7a889335e7244d3
Reviewed-on: https://gerrit.iotivity.org/gerrit/26099Tested-by: default avatarIoTivity Jenkins <jenkins-daemon@iotivity.org>
Reviewed-by: Kishen Maloor's avatarKishen Maloor <kishen.maloor@intel.com>
parent d3b3f747
# Port for native Android compilation (without Java).
# Tested NDK versions:
# API Android version
# 19 4.4
# 21 5.0
# 23 6.0
# 24 7.0
#
# API version 24 is closest to regular Linux so far.
# With API 24 the Android port is almost identical to the Linux port
# except for the removal of the unsupported pthread_cancel and that
# the IP adapter assures that interfaces have multicast and broadcast
# enabled to avoid 3G/4G/5G interfaces.
#
# It is expected that higher versions then API 24 should work without any
# further modifications.
#
# Testing compilations on non-rooted Android phones:
# - Enable USB debugging on your phone.
# - Install ADB or Android Studio
# - adb start-server
# Your phone should query now if you trust the computer. Hit OK.
# - adb push simpleclient /data/local/tmp/
# Most likely your phone gives you in /data/local some more permissions
# Non-rooted devices are a bit restrictive what you can do in the file system.
# - adb shell
# - cd /data/local/tmp
# - chmod 755 simpleclient
# It was observed that the file has read-write permissions only after the upload
# on Android 7.
# - In a different terminal window start simpleserver on your developer box.
# - ./simpleclient
# - Kill client with Ctrl-C or Ctrl-\
# - exit
# - *** DISABLE USB debugging!!! *** (security issue if left on)
#
# Note: On regular Android phones the server versions will not be found
# (ie. simpleserver will not be discovered). But the clients
# should work.
#
# Download NDK: https://developer.android.com/ndk/downloads/index.html
# Unzip downloaded package.
# Choose architecture and API level.
# cd <NDK>/build/tools
# ./make_standalone_toolchain.py --arch <architecture> --api <level> --install-dir <path>
# For example: ./make_standalone_toolchain.py --arch arm --api 23 --install-dir ~/android-arm-23
# This makefile uses then the NDK in <install-dir>.
# For further setup see: https://developer.android.com/ndk/guides/standalone_toolchain.html
#
# Either set ANDROID_API and ANDROID_BASE in this makefile
# or invoke like this: make NDK_HOME=/opt/android-ndk ANDROID_API=24
# Location of the installation directory and the API level.
ANDROID_API := 19
ifeq (${NDK_HOME},)
ANDROID_BASE := "${HOME}/android-arm-${ANDROID_API}"
else
ANDROID_BASE := "${NDK_HOME}"
endif
# Compiler prefix
ANDROID_HOST := arm-linux-androideabi-
BIN_BASE := ${ANDROID_BASE}/bin/${ANDROID_HOST}
ifeq ($(origin CC),default)
CC := ${BIN_BASE}gcc
endif
ifeq ($(origin AR),default)
AR := ${BIN_BASE}ar
endif
RM ?= rm
MKDIR ?= mkdir
ROOT_DIR = ../..
OBJDIR ?= ./${ANDROID_HOST}obj
MBEDTLS_DIR := $(ROOT_DIR)/deps/mbedtls
DTLS= aes.c aesni.c arc4.c asn1parse.c asn1write.c base64.c \
bignum.c blowfish.c camellia.c ccm.c cipher.c cipher_wrap.c \
cmac.c ctr_drbg.c des.c dhm.c ecdh.c ecdsa.c \
ecjpake.c ecp.c ecp_curves.c entropy.c entropy_poll.c error.c \
gcm.c havege.c hmac_drbg.c md.c md2.c md4.c \
md5.c md_wrap.c oid.c padlock.c \
pem.c pk.c pk_wrap.c pkcs12.c pkcs5.c pkparse.c \
pkwrite.c platform.c ripemd160.c rsa.c sha1.c sha256.c \
sha512.c threading.c timing.c version.c version_features.c \
xtea.c pkcs11.c x509.c x509_crt.c debug.c net_sockets.c \
ssl_cache.c ssl_ciphersuites.c ssl_cli.c ssl_cookie.c \
ssl_srv.c ssl_ticket.c ssl_tls.c rsa_internal.c
DTLSFLAGS=-I../../deps/mbedtls/include -D__OC_RANDOM
CBOR=../../deps/tinycbor/src/cborencoder.c ../../deps/tinycbor/src/cborencoder_close_container_checked.c ../../deps/tinycbor/src/cborparser.c# ../../deps/tinycbor/src/cbortojson.c ../../deps/tinycbor/src/cborpretty.c ../../deps/tinycbor/src/cborparser_dup_string.c
SRC_COMMON:=$(wildcard ../../util/*.c) ${CBOR}
SRC:=$(wildcard ../../messaging/coap/*.c ../../api/*.c ../../port/android/*.c)
# From API level 24 on Android supports getifaddrs itself.
ifeq ($(shell if [ ${ANDROID_API} -gt 23 ]; then echo gt; fi),gt)
SRC:=$(filter-out ../../port/android/ifaddrs-android.c,${SRC})
endif
HEADERS = $(wildcard ../../include/*.h)
HEADERS += ../../port/android/config.h
HEADERS_COAP = $(wildcard ../../messaging/coap/*.h)
HEADERS_UTIL = $(wildcard ../../util/*.h)
HEADERS_UTIL_PT = $(wildcard ../../util/pt/*.h)
HEADERS_PORT = $(wildcard ../../port/*.h)
HEADERS_TINYCBOR = $(wildcard ../../deps/tinycbor/src/*.h)
CFLAGS?=-fPIE -pie -fno-asynchronous-unwind-tables -fno-omit-frame-pointer -ffreestanding -Os -fno-stack-protector -ffunction-sections -fdata-sections -fno-reorder-functions -fno-defer-pop -fno-strict-overflow -I./ -I../../include/ -I../../ -std=gnu99 -Wall -D__ANDROID_API__=${ANDROID_API}
OBJ_COMMON=$(addprefix ${OBJDIR}/,$(notdir $(SRC_COMMON:.c=.o)))
OBJ_CLIENT=$(addprefix ${OBJDIR}/client/,$(notdir $(SRC:.c=.o)))
OBJ_SERVER=$(addprefix ${OBJDIR}/server/,$(filter-out oc_obt.o,$(notdir $(SRC:.c=.o))))
OBJ_CLIENT_SERVER=$(addprefix ${OBJDIR}/client_server/,$(notdir $(SRC:.c=.o)))
VPATH=../../messaging/coap/:../../util/:../../api/:../../deps/tinycbor/src/:../../deps/mbedtls/library:
LIBS?= -lm
SAMPLES := server client temp_sensor simpleserver simpleclient client_collections_linux \
server_collections_linux server_block_linux client_block_linux smart_home_server_linux multi_device_server multi_device_client \
smart_lock server_multithread_linux client_multithread_linux
OBT = onboarding_tool
ifeq ($(DEBUG),1)
CFLAGS += -DOC_DEBUG -g -O0
else
CFLAGS += -Wl,--gc-sections
endif
ifeq ($(DYNAMIC),1)
CFLAGS += -DOC_DYNAMIC_ALLOCATION
endif
ifneq ($(SECURE),0)
SRC += $(addprefix ../../security/,oc_acl.c oc_cred.c oc_doxm.c oc_pstat.c oc_tls.c oc_svr.c oc_store.c)
SRC_COMMON += $(addprefix $(MBEDTLS_DIR)/library/,${DTLS})
MBEDTLS_PATCH_FILE := $(MBEDTLS_DIR)/patched.txt
ifeq ($(DYNAMIC),1)
SRC += ../../security/oc_obt.c
SAMPLES += ${OBT}
else
SRC_COMMON += $(MBEDTLS_DIR)/library/memory_buffer_alloc.c
endif
CFLAGS += ${DTLSFLAGS} -DOC_SECURITY
VPATH += ../../security/:../../deps/mbedtls/library:
endif
ifeq ($(IPV4),1)
CFLAGS += -DOC_IPV4
endif
ifeq ($(TCP),1)
EXTRA_CFLAGS += -DOC_TCP
endif
CONSTRAINED_LIBS = libiotivity-constrained-server.a libiotivity-constrained-client.a \
libiotivity-constrained-client-server.a
all: $(CONSTRAINED_LIBS) $(SAMPLES)
.PHONY: clean
${SRC} ${SRC_COMMON}: $(MBEDTLS_PATCH_FILE)
${OBJDIR}/%.o: %.c
@mkdir -p ${@D}
${CC} -c -o $@ $< ${CFLAGS}
${OBJDIR}/server/%.o: %.c
@mkdir -p ${@D}
${CC} -c -o $@ $< ${CFLAGS} -DOC_SERVER
${OBJDIR}/client/%.o: %.c
@mkdir -p ${@D}
${CC} -c -o $@ $< ${CFLAGS} -DOC_CLIENT
${OBJDIR}/client_server/%.o: %.c
@mkdir -p ${@D}
${CC} -c -o $@ $< ${CFLAGS} -DOC_CLIENT -DOC_SERVER
libiotivity-constrained-server.a: $(OBJ_COMMON) $(OBJ_SERVER)
$(AR) -rcs $@ $(OBJ_COMMON) $(OBJ_SERVER)
libiotivity-constrained-client.a: $(OBJ_COMMON) $(OBJ_CLIENT)
$(AR) -rcs $@ $(OBJ_COMMON) $(OBJ_CLIENT)
libiotivity-constrained-client-server.a: $(OBJ_COMMON) $(OBJ_CLIENT_SERVER)
$(AR) -rcs $@ $(OBJ_COMMON) $(OBJ_CLIENT_SERVER)
server: libiotivity-constrained-server.a
${CC} -o $@ ../../apps/server_linux.c libiotivity-constrained-server.a -DOC_SERVER ${CFLAGS} ${LIBS}
client: libiotivity-constrained-client.a
${CC} -o $@ ../../apps/client_linux.c libiotivity-constrained-client.a -DOC_CLIENT ${CFLAGS} ${LIBS}
smart_lock: libiotivity-constrained-client.a
${CC} -o $@ ../../apps/smart_lock_linux.c libiotivity-constrained-client.a -DOC_CLIENT ${CFLAGS} ${LIBS}
temp_sensor: libiotivity-constrained-client.a
${CC} -o $@ ../../apps/temp_sensor_client_linux.c libiotivity-constrained-client.a -DOC_CLIENT ${CFLAGS} ${LIBS}
simpleserver: libiotivity-constrained-server.a
${CC} -o $@ ../../apps/simpleserver.c libiotivity-constrained-server.a -DOC_SERVER ${CFLAGS} ${LIBS}
simpleclient: libiotivity-constrained-client.a
${CC} -o $@ ../../apps/simpleclient.c libiotivity-constrained-client.a -DOC_CLIENT ${CFLAGS} ${LIBS}
client_collections_linux: libiotivity-constrained-client.a
${CC} -o $@ ../../apps/client_collections_linux.c libiotivity-constrained-client.a -DOC_CLIENT ${CFLAGS} ${LIBS}
server_collections_linux: libiotivity-constrained-server.a
${CC} -o $@ ../../apps/server_collections_linux.c libiotivity-constrained-server.a -DOC_SERVER ${CFLAGS} ${LIBS}
client_block_linux: libiotivity-constrained-client.a
${CC} -o $@ ../../apps/client_block_linux.c libiotivity-constrained-client.a -DOC_CLIENT ${CFLAGS} ${LIBS}
server_block_linux: libiotivity-constrained-server.a
${CC} -o $@ ../../apps/server_block_linux.c libiotivity-constrained-server.a -DOC_SERVER ${CFLAGS} ${LIBS}
smart_home_server_linux: libiotivity-constrained-server.a
${CC} -o $@ ../../apps/smart_home_server_linux.c libiotivity-constrained-server.a -DOC_SERVER ${CFLAGS} ${LIBS}
multi_device_server: libiotivity-constrained-server.a
${CC} -o $@ ../../apps/multi_device_server_linux.c libiotivity-constrained-server.a -DOC_SERVER ${CFLAGS} ${LIBS}
multi_device_client: libiotivity-constrained-client.a
${CC} -o $@ ../../apps/multi_device_client_linux.c libiotivity-constrained-client.a -DOC_CLIENT ${CFLAGS} ${LIBS}
${OBT}: libiotivity-constrained-client.a
${CC} -o $@ ../../onboarding_tool/obtmain.c libiotivity-constrained-client.a -DOC_CLIENT ${CFLAGS} ${LIBS}
server_multithread_linux: libiotivity-constrained-server.a
${CC} -o $@ ../../apps/server_multithread_linux.c libiotivity-constrained-server.a -DOC_SERVER ${CFLAGS} ${LIBS}
client_multithread_linux: libiotivity-constrained-client.a
${CC} -o $@ ../../apps/client_multithread_linux.c libiotivity-constrained-client.a -DOC_CLIENT ${CFLAGS} ${LIBS}
ifneq ($(SECURE),0)
MBEDTLS_PATCHES ?= $(sort $(wildcard ../../patches/*.patch))
${MBEDTLS_DIR}/.git:
git submodule update --init ${@D}
$(MBEDTLS_PATCH_FILE): ${MBEDTLS_DIR}/.git ${MBEDTLS_PATCHES}
if [ -d ${MBEDTLS_DIR} ]; then \
cd ${MBEDTLS_DIR} && \
git clean -fdx . && \
git reset --hard && \
cd -; \
fi && \
git submodule update --init && \
cd ${MBEDTLS_DIR} && \
for patch in $(MBEDTLS_PATCHES); do patch -r - -s -N -p1 < $${patch} ; done && \
echo "Patches applied in $^" > ${@F}
endif
clean:
$(RM) -rf ${OBJDIR} $(CONSTRAINED_LIBS)
cleanall: clean
$(RM) -rf ${all} $(SAMPLES) $(OBT) $(MBEDTLS_PATCH_FILE)
distclean: cleanall
/*
// Copyright (c) 2017 Intel Corporation
//
// 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 "port/oc_assert.h"
#include <stdlib.h>
void
abort_impl(void)
{
abort();
}
void
exit_impl(int status)
{
exit(status);
}
/*
// Copyright (c) 2016 Intel Corporation
//
// 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 "port/oc_clock.h"
#include "port/oc_log.h"
#include <math.h>
#include <time.h>
#include <unistd.h>
void
oc_clock_init(void)
{}
oc_clock_time_t
oc_clock_time(void)
{
oc_clock_time_t time = 0;
struct timespec t;
if (clock_gettime(CLOCK_REALTIME, &t) != -1) {
time = (oc_clock_time_t)t.tv_sec * OC_CLOCK_SECOND +
(oc_clock_time_t)ceil(t.tv_nsec / (1.e09 / OC_CLOCK_SECOND));
}
return time;
}
unsigned long
oc_clock_seconds(void)
{
struct timespec t;
if (clock_gettime(CLOCK_REALTIME, &t) != -1) {
return t.tv_sec;
}
return 0;
}
void
oc_clock_wait(oc_clock_time_t t)
{
usleep(t * 1.e03);
}
#ifndef CONFIG_H
#define CONFIG_H
/* Time resolution */
#include <stdint.h>
#include <time.h>
typedef uint64_t oc_clock_time_t;
#define OC_CLOCK_CONF_TICKS_PER_SECOND CLOCKS_PER_SEC
/* Security Layer */
/* Max inactivity timeout before tearing down DTLS connection */
#define OC_DTLS_INACTIVITY_TIMEOUT (600)
/* Add support for passing network up/down events to the app */
#define OC_NETWORK_MONITOR
/* Add support for passing TCP/TLS/DTLS session connection events to the app */
#define OC_SESSION_EVENTS
/* Add support for dns lookup to the endpoint */
#define OC_DNS_LOOKUP
#define OC_DNS_LOOKUP_IPV6
/* If we selected support for dynamic memory allocation */
#ifdef OC_DYNAMIC_ALLOCATION
#define OC_COLLECTIONS
#define OC_BLOCK_WISE
#else /* OC_DYNAMIC_ALLOCATION */
/* List of constraints below for a build that does not employ dynamic
memory allocation
*/
/* Memory pool sizes */
#define OC_BYTES_POOL_SIZE (1800)
#define OC_INTS_POOL_SIZE (100)
#define OC_DOUBLES_POOL_SIZE (4)
/* Server-side parameters */
/* Maximum number of server resources */
#define OC_MAX_APP_RESOURCES (4)
#define OC_MAX_NUM_COLLECTIONS (1)
/* Common paramters */
/* Prescriptive lower layers MTU size, enable block-wise transfers */
#define OC_BLOCK_WISE_SET_MTU (700)
/* Maximum size of request/response payloads */
#define OC_MAX_APP_DATA_SIZE (2048)
/* Maximum number of concurrent requests */
#define OC_MAX_NUM_CONCURRENT_REQUESTS (3)
/* Maximum number of nodes in a payload tree structure */
#define OC_MAX_NUM_REP_OBJECTS (150)
/* Number of devices on the OCF platform */
#define OC_MAX_NUM_DEVICES (2)
/* Maximum number of endpoints */
#define OC_MAX_NUM_ENDPOINTS (20)
/* Security layer */
/* Maximum number of authorized clients */
#define OC_MAX_NUM_SUBJECTS (2)
/* Maximum number of concurrent (D)TLS sessions */
#define OC_MAX_TLS_PEERS (1)
/* Maximum number of peer for TCP channel */
#define OC_MAX_TCP_PEERS (2)
/* Maximum number of interfaces for IP adapter */
/* Warning: Android has often over 10 interfaces. */
#define OC_MAX_IP_INTERFACES (20)
/* Maximum number of callbacks for Network interface event monitoring */
#define OC_MAX_NETWORK_INTERFACE_CBS (2)
/* Maximum number of callbacks for connection of session */
#define OC_MAX_SESSION_EVENT_CBS (2)
#endif /* !OC_DYNAMIC_ALLOCATION */
#endif /* CONFIG_H */
/*
Copyright (c) 2011, The WebRTC project authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Google nor the names of its contributors may
be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "ifaddrs-android.h"
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/utsname.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <unistd.h>
#include <errno.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
struct netlinkrequest
{
struct nlmsghdr header;
struct ifaddrmsg msg;
};
static const int kMaxReadSize = 4096;
static int
set_ifname(struct ifaddrs *ifaddr, int interface)
{
char buf[IFNAMSIZ] = { 0 };
char *name = if_indextoname(interface, buf);
if (name == NULL) {
return -1;
}
ifaddr->ifa_name = malloc(strlen(name) + 1);
strncpy(ifaddr->ifa_name, name, strlen(name) + 1);
return 0;
}
static int
set_flags(struct ifaddrs *ifaddr)
{
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd == -1) {
return -1;
}
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifaddr->ifa_name, IFNAMSIZ - 1);
int rc = ioctl(fd, SIOCGIFFLAGS, &ifr);
close(fd);
if (rc == -1) {
return -1;
}
ifaddr->ifa_flags = ifr.ifr_flags;
return 0;
}
static int
set_addresses(struct ifaddrs *ifaddr, struct ifaddrmsg *msg, void *data,
size_t len)
{
if (msg->ifa_family == AF_INET) {
struct sockaddr_in *sa = malloc(sizeof(struct sockaddr_in));
memset(sa, 0, sizeof(struct sockaddr_in));
sa->sin_family = AF_INET;
memcpy(&sa->sin_addr, data, len);
ifaddr->ifa_addr = (struct sockaddr *)sa;
} else if (msg->ifa_family == AF_INET6) {
struct sockaddr_in6 *sa = malloc(sizeof(struct sockaddr_in6));
memset(sa, 0, sizeof(struct sockaddr_in6));
sa->sin6_family = AF_INET6;
sa->sin6_scope_id = msg->ifa_index;
memcpy(&sa->sin6_addr, data, len);
ifaddr->ifa_addr = (struct sockaddr *)sa;
} else {
return -1;
}
return 0;
}
static int
make_prefixes(struct ifaddrs *ifaddr, int family, int prefixlen)
{
char *prefix = NULL;
if (family == AF_INET) {
struct sockaddr_in *mask = malloc(sizeof(struct sockaddr_in));
memset(mask, 0, sizeof(struct sockaddr_in));
mask->sin_family = AF_INET;
memset(&mask->sin_addr, 0, sizeof(struct in_addr));
ifaddr->ifa_netmask = (struct sockaddr *)mask;
if (prefixlen > 32) {
prefixlen = 32;
}
prefix = (char *)&mask->sin_addr;
} else if (family == AF_INET6) {
struct sockaddr_in6 *mask = malloc(sizeof(struct sockaddr_in6));
memset(mask, 0, sizeof(struct sockaddr_in6));
mask->sin6_family = AF_INET6;
memset(&mask->sin6_addr, 0, sizeof(struct in6_addr));
ifaddr->ifa_netmask = (struct sockaddr *)mask;
if (prefixlen > 128) {
prefixlen = 128;
}
prefix = (char *)&mask->sin6_addr;
} else {
return -1;
}
for (int i = 0; i < (prefixlen / 8); i++) {
*prefix++ = 0xFF;
}
char remainder = 0xff;
remainder <<= (8 - prefixlen % 8);
*prefix = remainder;
return 0;
}
static int
populate_ifaddrs(struct ifaddrs *ifaddr, struct ifaddrmsg *msg, void *bytes,
size_t len)
{
if (set_ifname(ifaddr, msg->ifa_index) != 0) {
return -1;
}
if (set_flags(ifaddr) != 0) {
return -1;
}
if (set_addresses(ifaddr, msg, bytes, len) != 0) {
return -1;
}
if (make_prefixes(ifaddr, msg->ifa_family, msg->ifa_prefixlen) != 0) {
return -1;
}
return 0;
}
int
android_getifaddrs(struct ifaddrs **result)
{
int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (fd < 0) {
return -1;
}
struct netlinkrequest ifaddr_request;
memset(&ifaddr_request, 0, sizeof(ifaddr_request));
ifaddr_request.header.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
ifaddr_request.header.nlmsg_type = RTM_GETADDR;
ifaddr_request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
ssize_t count = send(fd, &ifaddr_request, ifaddr_request.header.nlmsg_len, 0);
if ((size_t)count != ifaddr_request.header.nlmsg_len) {
close(fd);
return -1;
}
struct ifaddrs *start = NULL;
struct ifaddrs *current = NULL;
char buf[kMaxReadSize];
ssize_t amount_read = recv(fd, &buf, kMaxReadSize, 0);
while (amount_read > 0) {
struct nlmsghdr *header = (struct nlmsghdr *)&buf[0];
size_t header_size = (size_t)amount_read;
for (; NLMSG_OK(header, header_size);
header = NLMSG_NEXT(header, header_size)) {
switch (header->nlmsg_type) {
case NLMSG_DONE:
/* Success. Return. */
*result = start;
close(fd);
return 0;
case NLMSG_ERROR:
close(fd);
android_freeifaddrs(start);
return -1;
case RTM_NEWADDR: {
struct ifaddrmsg *address_msg = (struct ifaddrmsg *)NLMSG_DATA(header);
struct rtattr *rta = IFA_RTA(address_msg);
ssize_t payload_len = IFA_PAYLOAD(header);
while (RTA_OK(rta, payload_len)) {
if (rta->rta_type == IFA_ADDRESS) {
int family = address_msg->ifa_family;
if (family == AF_INET || family == AF_INET6) {
struct ifaddrs *newest = malloc(sizeof(struct ifaddrs));
memset(newest, 0, sizeof(struct ifaddrs));
if (current) {
current->ifa_next = newest;
} else {