michael@0: /* Copyright 2012 Mozilla Foundation and Mozilla contributors michael@0: * michael@0: * Licensed under the Apache License, Version 2.0 (the "License"); michael@0: * you may not use this file except in compliance with the License. michael@0: * You may obtain a copy of the License at michael@0: * michael@0: * http://www.apache.org/licenses/LICENSE-2.0 michael@0: * michael@0: * Unless required by applicable law or agreed to in writing, software michael@0: * distributed under the License is distributed on an "AS IS" BASIS, michael@0: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. michael@0: * See the License for the specific language governing permissions and michael@0: * limitations under the License. michael@0: */ michael@0: michael@0: if (!this.ctypes) { michael@0: // We're likely being loaded as a JSM. michael@0: this.EXPORTED_SYMBOLS = [ "libcutils", "libnetutils", "netHelpers" ]; michael@0: Components.utils.import("resource://gre/modules/ctypes.jsm"); michael@0: } michael@0: michael@0: const SYSTEM_PROPERTY_KEY_MAX = 32; michael@0: const SYSTEM_PROPERTY_VALUE_MAX = 92; michael@0: michael@0: // We leave this as 'undefined' instead of setting it to 'false'. That michael@0: // way a file that includes us can have it defined already without us michael@0: // overriding the value here. michael@0: let DEBUG; michael@0: michael@0: /** michael@0: * Expose some system-level functions. michael@0: */ michael@0: this.libcutils = (function() { michael@0: let lib; michael@0: try { michael@0: lib = ctypes.open("libcutils.so"); michael@0: } catch(ex) { michael@0: // Return a fallback option in case libcutils.so isn't present (e.g. michael@0: // when building Firefox with MOZ_B2G_RIL. michael@0: if (DEBUG) { michael@0: dump("Could not load libcutils.so. Using fake propdb.\n"); michael@0: } michael@0: let fake_propdb = Object.create(null); michael@0: return { michael@0: property_get: function(key, defaultValue) { michael@0: if (key in fake_propdb) { michael@0: return fake_propdb[key]; michael@0: } michael@0: return defaultValue === undefined ? null : defaultValue; michael@0: }, michael@0: property_set: function(key, value) { michael@0: fake_propdb[key] = value; michael@0: } michael@0: }; michael@0: } michael@0: michael@0: let c_property_get = lib.declare("property_get", ctypes.default_abi, michael@0: ctypes.int, // return value: length michael@0: ctypes.char.ptr, // key michael@0: ctypes.char.ptr, // value michael@0: ctypes.char.ptr); // default michael@0: let c_property_set = lib.declare("property_set", ctypes.default_abi, michael@0: ctypes.int, // return value: success michael@0: ctypes.char.ptr, // key michael@0: ctypes.char.ptr); // value michael@0: let c_value_buf = ctypes.char.array(SYSTEM_PROPERTY_VALUE_MAX)(); michael@0: michael@0: return { michael@0: michael@0: /** michael@0: * Get a system property. michael@0: * michael@0: * @param key michael@0: * Name of the property michael@0: * @param defaultValue [optional] michael@0: * Default value to return if the property isn't set (default: null) michael@0: */ michael@0: property_get: function(key, defaultValue) { michael@0: if (defaultValue === undefined) { michael@0: defaultValue = null; michael@0: } michael@0: c_property_get(key, c_value_buf, defaultValue); michael@0: return c_value_buf.readString(); michael@0: }, michael@0: michael@0: /** michael@0: * Set a system property michael@0: * michael@0: * @param key michael@0: * Name of the property michael@0: * @param value michael@0: * Value to set the property to. michael@0: */ michael@0: property_set: function(key, value) { michael@0: let rv = c_property_set(key, value); michael@0: if (rv) { michael@0: throw Error('libcutils.property_set("' + key + '", "' + value + michael@0: '") failed with error ' + rv); michael@0: } michael@0: } michael@0: michael@0: }; michael@0: })(); michael@0: michael@0: /** michael@0: * Network-related functions from libnetutils. michael@0: */ michael@0: this.libnetutils = (function() { michael@0: let library; michael@0: try { michael@0: library = ctypes.open("libnetutils.so"); michael@0: } catch(ex) { michael@0: if (DEBUG) { michael@0: dump("Could not load libnetutils.so!\n"); michael@0: } michael@0: // For now we just fake the ctypes library interfacer to return michael@0: // no-op functions when library.declare() is called. michael@0: library = { michael@0: declare: function() { michael@0: return function fake_libnetutils_function() {}; michael@0: } michael@0: }; michael@0: } michael@0: michael@0: let iface = { michael@0: ifc_enable: library.declare("ifc_enable", ctypes.default_abi, michael@0: ctypes.int, michael@0: ctypes.char.ptr), michael@0: ifc_disable: library.declare("ifc_disable", ctypes.default_abi, michael@0: ctypes.int, michael@0: ctypes.char.ptr), michael@0: ifc_add_host_route: library.declare("ifc_add_host_route", michael@0: ctypes.default_abi, michael@0: ctypes.int, michael@0: ctypes.char.ptr, michael@0: ctypes.int), michael@0: ifc_remove_host_routes: library.declare("ifc_remove_host_routes", michael@0: ctypes.default_abi, michael@0: ctypes.int, michael@0: ctypes.char.ptr), michael@0: ifc_set_default_route: library.declare("ifc_set_default_route", michael@0: ctypes.default_abi, michael@0: ctypes.int, michael@0: ctypes.char.ptr, michael@0: ctypes.int), michael@0: ifc_get_default_route: library.declare("ifc_get_default_route", michael@0: ctypes.default_abi, michael@0: ctypes.int, michael@0: ctypes.char.ptr), michael@0: ifc_remove_default_route: library.declare("ifc_remove_default_route", michael@0: ctypes.default_abi, michael@0: ctypes.int, michael@0: ctypes.char.ptr), michael@0: ifc_configure: library.declare("ifc_configure", ctypes.default_abi, michael@0: ctypes.int, michael@0: ctypes.char.ptr, michael@0: ctypes.int, michael@0: ctypes.int, michael@0: ctypes.int, michael@0: ctypes.int, michael@0: ctypes.int), michael@0: ifc_add_route: library.declare("ifc_add_route", ctypes.default_abi, michael@0: ctypes.int, // return value michael@0: ctypes.char.ptr, // ifname michael@0: ctypes.char.ptr, // dst michael@0: ctypes.int, // prefix_length michael@0: ctypes.char.ptr), // gw michael@0: ifc_remove_route: library.declare("ifc_remove_route", ctypes.default_abi, michael@0: ctypes.int, // return value michael@0: ctypes.char.ptr, // ifname michael@0: ctypes.char.ptr, // dst michael@0: ctypes.int, // prefix_length michael@0: ctypes.char.ptr), // gw michael@0: dhcp_stop: library.declare("dhcp_stop", ctypes.default_abi, michael@0: ctypes.int, michael@0: ctypes.char.ptr), michael@0: dhcp_release_lease: library.declare("dhcp_release_lease", ctypes.default_abi, michael@0: ctypes.int, michael@0: ctypes.char.ptr), michael@0: dhcp_get_errmsg: library.declare("dhcp_get_errmsg", ctypes.default_abi, michael@0: ctypes.char.ptr), michael@0: michael@0: // Constants for ifc_reset_connections. michael@0: // NOTE: Ignored in versions before ICS. michael@0: RESET_IPV4_ADDRESSES: 0x01, michael@0: RESET_IPV6_ADDRESSES: 0x02, michael@0: }; michael@0: michael@0: iface.RESET_ALL_ADDRESSES = iface.RESET_IPV4_ADDRESSES | michael@0: iface.RESET_IPV6_ADDRESSES; michael@0: michael@0: return iface; michael@0: })(); michael@0: michael@0: /** michael@0: * Helpers for conversions. michael@0: */ michael@0: this.netHelpers = { michael@0: michael@0: /** michael@0: * Swap byte orders for 32-bit value michael@0: */ michael@0: swap32: function(n) { michael@0: return (((n >> 24) & 0xFF) << 0) | michael@0: (((n >> 16) & 0xFF) << 8) | michael@0: (((n >> 8) & 0xFF) << 16) | michael@0: (((n >> 0) & 0xFF) << 24); michael@0: }, michael@0: michael@0: /** michael@0: * Convert network byte order to host byte order michael@0: * Note: Assume that the system is little endian michael@0: */ michael@0: ntohl: function(n) { michael@0: return this.swap32(n); michael@0: }, michael@0: michael@0: /** michael@0: * Convert host byte order to network byte order michael@0: * Note: Assume that the system is little endian michael@0: */ michael@0: htonl: function(n) { michael@0: return this.swap32(n); michael@0: }, michael@0: michael@0: /** michael@0: * Convert integer representation of an IP address to the string michael@0: * representation. michael@0: * michael@0: * @param ip michael@0: * IP address in number format. michael@0: */ michael@0: ipToString: function(ip) { michael@0: return ((ip >> 0) & 0xFF) + "." + michael@0: ((ip >> 8) & 0xFF) + "." + michael@0: ((ip >> 16) & 0xFF) + "." + michael@0: ((ip >> 24) & 0xFF); michael@0: }, michael@0: michael@0: /** michael@0: * Convert string representation of an IP address to the integer michael@0: * representation (network byte order). michael@0: * michael@0: * @param string michael@0: * String containing the IP address. michael@0: */ michael@0: stringToIP: function(string) { michael@0: if (!string) { michael@0: return null; michael@0: } michael@0: let ip = 0; michael@0: let start, end = -1; michael@0: for (let i = 0; i < 4; i++) { michael@0: start = end + 1; michael@0: end = string.indexOf(".", start); michael@0: if (end == -1) { michael@0: end = string.length; michael@0: } michael@0: let num = parseInt(string.slice(start, end), 10); michael@0: if (isNaN(num)) { michael@0: return null; michael@0: } michael@0: ip |= num << (i * 8); michael@0: } michael@0: return ip; michael@0: }, michael@0: michael@0: /** michael@0: * Make a subnet mask. michael@0: */ michael@0: makeMask: function(len) { michael@0: let mask = 0; michael@0: for (let i = 0; i < len; ++i) { michael@0: mask |= (0x80000000 >> i); michael@0: } michael@0: return this.ntohl(mask); michael@0: }, michael@0: michael@0: /** michael@0: * Get Mask length from given mask address michael@0: */ michael@0: getMaskLength: function(mask) { michael@0: let len = 0; michael@0: let netmask = this.ntohl(mask); michael@0: while (netmask & 0x80000000) { michael@0: len++; michael@0: netmask = netmask << 1; michael@0: } michael@0: return len; michael@0: } michael@0: };