O2 2.0
A communication protocol for interactive music and media applications.
hostipimpl.h
1// hostipimpl.h -- get the host ip address; this is the implementation
2//
3// Roger B. Dannenberg, 2020
4//
5
6#include <stdint.h>
7#include <stdbool.h>
8#include <string.h>
9#include <ctype.h>
10#ifdef WIN32
11#define PLATFORM_WIN32
12#include <stdlib.h>
13#include <Winsock2.h>
14#include <iphlpapi.h>
15
16#elif (defined(__unix__) || defined(__APPLE__))
17#define PLATFORM_UNIX
18#include <sys/socket.h>
19#include <unistd.h> // define close()
20#include <netdb.h>
21#include <sys/time.h>
22
23#include "sys/ioctl.h"
24#include <ifaddrs.h>
25
26#endif
27#include <assert.h>
28#include <stdio.h>
29#include "o2base.h"
30#include "hostip.h"
31
32#if (defined(PLATFORM_WIN32) || defined(PLATFORM_UNIX))
33// this can be turned off before calling o2n_initialize(). It enables
34// Internet connections, which requires that we contact a STUN server
35// to obtain a public IP address. If there is not network, this may
36// cause O2 to hang for about 30 seconds for a network timeout.
37bool o2n_internet_enabled = true;
38// this can be turned off before calling o2n_initialize(). It enables
39// local area network connections:
40bool o2n_network_enabled = true;
41// this will be turned on if we find an internal IP address, but
42// it stays false if o2n_network_enabled is false:
43bool o2n_network_found = false;
44
45void o2n_get_internal_ip(char *internal_ip)
46{
47 if (internal_ip[0]) { // already known
48 return;
49 }
50 assert(!o2n_network_found); // not yet found
51 assert(o2n_network_enabled); // otherwise, we should not be called
52 // look for AF_INET interface. If you find one, copy it
53 // to name. If you find one that is not 127.0.0.1, then
54 // stop looking.
55#ifdef WIN32
56 ULONG outbuflen = 15000;
57 DWORD rslt;
58 ULONG flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
59 GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
60 ULONG iterations = 0;
61 PIP_ADAPTER_ADDRESSES addresses;
62 do {
63 addresses = (PIP_ADAPTER_ADDRESSES) O2_MALLOC(outbuflen);
64 if (addresses == NULL) {
65 return;
66 }
67 rslt = GetAdaptersAddresses(AF_INET, flags, NULL,
68 addresses, &outbuflen);
69 if (rslt == ERROR_BUFFER_OVERFLOW) {
70 O2_FREE(addresses);
71 addresses = NULL;
72 }
73 } while (rslt == ERROR_BUFFER_OVERFLOW && iterations++ < 3);
74 if (rslt != NO_ERROR) {
75 return;
76 }
77 PIP_ADAPTER_ADDRESSES cur = addresses;
78 while (cur) {
79 if (cur->IfType != IF_TYPE_SOFTWARE_LOOPBACK &&
80 cur->OperStatus == IfOperStatusUp) {
81 PIP_ADAPTER_UNICAST_ADDRESS addr;
82 for (addr = cur->FirstUnicastAddress; addr != NULL;
83 addr = addr->Next) {
84 SOCKADDR_IN *saddr = (SOCKADDR_IN *)addr->Address.lpSockaddr;
85 snprintf(internal_ip, O2N_IP_LEN, "%08x",
86 ntohl(saddr->sin_addr.S_un.S_addr));
87 if (!(streql(internal_ip, "7f000001"))) {
88 o2n_network_found = true;
89 break;
90 }
91 }
92 }
93 cur = cur->Next;
94 }
95 O2_FREE(addresses);
96#else
97 struct ifaddrs *ifap, *ifa;
98 if (getifaddrs(&ifap)) {
99 perror("getting IP address");
100 return;
101 }
102 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
103 if (ifa->ifa_addr->sa_family == AF_INET) {
104 struct sockaddr_in *sa = (struct sockaddr_in *) ifa->ifa_addr;
105 snprintf(internal_ip, O2N_IP_LEN, "%08x",
106 ntohl(sa->sin_addr.s_addr));
107 if (!streql(internal_ip, "7f000001")) {
108 o2n_network_found = true;
109 break;
110 }
111 }
112 }
113 freeifaddrs(ifap);
114#endif
115 // make sure we got an address:
116 if (!internal_ip[0]) {
117 strcpy(internal_ip, "7f000001"); // localhost
118 }
119}
120#endif
121
122
123static int hex_to_nibble(char hex)
124{
125 if (isdigit(hex)) return hex - '0';
126 else if (hex >= 'A' && hex <= 'F') return hex - 'A' + 10;
127 else if (hex >= 'a' && hex <= 'f') return hex - 'a' + 10;
128#ifndef O2_NO_DEBUG
129 printf("ERROR: bad hex character passed to hex_to_nibble()\n");
130#endif
131 return 0;
132}
133
134
135// this one is used elsewhere so it is not static
136int o2_hex_to_byte(const char *hex)
137{
138 return (hex_to_nibble(hex[0]) << 4) + hex_to_nibble(hex[1]);
139}
140
141
142unsigned int o2_hex_to_int(const char *hex)
143{
144 char h;
145 int i = 0;
146 while ((h = *hex++)) {
147 i = (i << 4) + hex_to_nibble(h);
148 }
149 return i;
150}
151
152
153// convert 8-char, 32-bit hex representation to dot-notation,
154// e.g. "7f000001" converts to "127.0.0.1"
155// dot must be a string of length 16 or more
156void o2_hex_to_dot(const char *hex, char *dot)
157{
158 int i1 = o2_hex_to_byte(hex);
159 int i2 = o2_hex_to_byte(hex + 2);
160 int i3 = o2_hex_to_byte(hex + 4);
161 int i4 = o2_hex_to_byte(hex + 6);
162 snprintf(dot, 16, "%d.%d.%d.%d", i1, i2, i3, i4);
163}
164
void o2_hex_to_dot(const char *hex, char *dot)
Convert from hex format to dot format IP address.
Definition: hostipimpl.h:156
unsigned int o2_hex_to_int(const char *hex)
Convert hex string to integer.
Definition: hostipimpl.h:142