diff options
Diffstat (limited to 'src/library.js')
-rw-r--r-- | src/library.js | 1630 |
1 files changed, 1093 insertions, 537 deletions
diff --git a/src/library.js b/src/library.js index f6b3d5ef..f3c3c1ec 100644 --- a/src/library.js +++ b/src/library.js @@ -323,10 +323,16 @@ LibraryManager.library = { path = Pointer_stringify(path); // we don't want this in the JS API as the JS API // uses mknod to create all nodes. - var err = FS.mayMknod(mode); - if (err) { - ___setErrNo(err); - return -1; + switch (mode & {{{ cDefine('S_IFMT') }}}) { + case {{{ cDefine('S_IFREG') }}}: + case {{{ cDefine('S_IFCHR') }}}: + case {{{ cDefine('S_IFBLK') }}}: + case {{{ cDefine('S_IFIFO') }}}: + case {{{ cDefine('S_IFSOCK') }}}: + break; + default: + ___setErrNo(ERRNO_CODES.EINVAL); + return -1; } try { FS.mknod(path, mode, dev); @@ -600,31 +606,32 @@ LibraryManager.library = { // poll.h // ========================================================================== + __DEFAULT_POLLMASK: {{{ cDefine('POLLIN') }}} | {{{ cDefine('POLLOUT') }}}, __pollfd_struct_layout: Runtime.generateStructInfo([ ['i32', 'fd'], ['i16', 'events'], ['i16', 'revents']]), - poll__deps: ['$FS', '__pollfd_struct_layout'], + poll__deps: ['$FS', '__DEFAULT_POLLMASK', '__pollfd_struct_layout'], poll: function(fds, nfds, timeout) { // int poll(struct pollfd fds[], nfds_t nfds, int timeout); // http://pubs.opengroup.org/onlinepubs/009695399/functions/poll.html - // NOTE: This is pretty much a no-op mimicking glibc. var offsets = ___pollfd_struct_layout; var nonzero = 0; for (var i = 0; i < nfds; i++) { var pollfd = fds + ___pollfd_struct_layout.__size__ * i; var fd = {{{ makeGetValue('pollfd', 'offsets.fd', 'i32') }}}; var events = {{{ makeGetValue('pollfd', 'offsets.events', 'i16') }}}; - var revents = 0; + var mask = {{{ cDefine('POLLNVAL') }}}; var stream = FS.getStream(fd); if (stream) { - if (events & {{{ cDefine('POLLIN') }}}) revents |= {{{ cDefine('POLLIN') }}}; - if (events & {{{ cDefine('POLLOUT') }}}) revents |= {{{ cDefine('POLLOUT') }}}; - } else { - if (events & {{{ cDefine('POLLNVAL') }}}) revents |= {{{ cDefine('POLLNVAL') }}}; + mask = ___DEFAULT_POLLMASK; + if (stream.stream_ops.poll) { + mask = stream.stream_ops.poll(stream); + } } - if (revents) nonzero++; - {{{ makeSetValue('pollfd', 'offsets.revents', 'revents', 'i16') }}} + mask &= events | {{{ cDefine('POLLERR') }}} | {{{ cDefine('POLLHUP') }}}; + if (mask) nonzero++; + {{{ makeSetValue('pollfd', 'offsets.revents', 'mask', 'i16') }}} } return nonzero; }, @@ -723,7 +730,7 @@ LibraryManager.library = { FS.close(stream); return 0; } catch (e) { - FS.handleFSError(e);; + FS.handleFSError(e); return -1; } }, @@ -1006,9 +1013,11 @@ LibraryManager.library = { return -1; } +#if SOCKET_WEBRTC if (stream && ('socket' in stream)) { return _recv(fildes, buf, nbyte, 0); } +#endif try { var slab = {{{ makeGetSlabs('buf', 'i8', true) }}}; @@ -1139,9 +1148,11 @@ LibraryManager.library = { return -1; } +#if SOCKET_WEBRTC if (stream && ('socket' in stream)) { return _send(fildes, buf, nbyte, 0); } +#endif try { var slab = {{{ makeGetSlabs('buf', 'i8', true) }}}; @@ -4268,9 +4279,11 @@ LibraryManager.library = { __cxa_guard_release: function() {}, __cxa_guard_abort: function() {}, +#if USE_TYPED_ARRAYS != 2 _ZTVN10__cxxabiv119__pointer_type_infoE: [0], // is a pointer _ZTVN10__cxxabiv117__class_type_infoE: [1], // no inherited classes _ZTVN10__cxxabiv120__si_class_type_infoE: [2], // yes inherited classes +#endif // Exceptions __cxa_allocate_exception: function(size) { @@ -4652,20 +4665,28 @@ LibraryManager.library = { cos: 'Math.cos', cosf: 'Math.cos', + cosl: 'Math.cos', sin: 'Math.sin', sinf: 'Math.sin', + sinl: 'Math.sin', tan: 'Math.tan', tanf: 'Math.tan', + tanl: 'Math.tan', acos: 'Math.acos', acosf: 'Math.acos', + acosl: 'Math.acos', asin: 'Math.asin', asinf: 'Math.asin', + asinl: 'Math.asin', atan: 'Math.atan', atanf: 'Math.atan', + atanl: 'Math.atan', atan2: 'Math.atan2', atan2f: 'Math.atan2', + atan2l: 'Math.atan2', exp: 'Math.exp', expf: 'Math.exp', + expl: 'Math.exp', // The erf and erfc functions are inspired from // http://www.digitalmars.com/archives/cplusplus/3634.html @@ -4701,7 +4722,8 @@ LibraryManager.library = { } while (Math.abs(q1 - q2) / q2 > MATH_TOLERANCE); return (ONE_SQRTPI * Math.exp(- x * x) * q2); }, - erfcf: 'erfcf', + erfcf: 'erfc', + erfcl: 'erfc', erf__deps: ['erfc'], erf: function(x) { var MATH_TOLERANCE = 1E-12; @@ -4725,18 +4747,25 @@ LibraryManager.library = { return (TWO_SQRTPI * sum); }, erff: 'erf', + erfl: 'erf', log: 'Math.log', logf: 'Math.log', + logl: 'Math.log', sqrt: 'Math.sqrt', sqrtf: 'Math.sqrt', + sqrtl: 'Math.sqrt', fabs: 'Math.abs', fabsf: 'Math.abs', + fabsl: 'Math.abs', ceil: 'Math.ceil', ceilf: 'Math.ceil', + ceill: 'Math.ceil', floor: 'Math.floor', floorf: 'Math.floor', + floorl: 'Math.floor', pow: 'Math.pow', powf: 'Math.pow', + powl: 'Math.pow', llvm_sqrt_f32: 'Math.sqrt', llvm_sqrt_f64: 'Math.sqrt', llvm_pow_f32: 'Math.pow', @@ -4807,6 +4836,7 @@ LibraryManager.library = { return __reallyNegative(a) === __reallyNegative(b) ? a : -a; }, copysignf: 'copysign', + copysignl: 'copysign', __signbit__deps: ['copysign'], __signbit: function(x) { // We implement using copysign so that we get support @@ -4819,56 +4849,70 @@ LibraryManager.library = { return Math.sqrt(a*a + b*b); }, hypotf: 'hypot', + hypotl: 'hypot', sinh: function(x) { var p = Math.pow(Math.E, x); return (p - (1 / p)) / 2; }, sinhf: 'sinh', + sinhl: 'sinh', cosh: function(x) { var p = Math.pow(Math.E, x); return (p + (1 / p)) / 2; }, coshf: 'cosh', + coshl: 'cosh', tanh__deps: ['sinh', 'cosh'], tanh: function(x) { return _sinh(x) / _cosh(x); }, tanhf: 'tanh', + tanhl: 'tanh', asinh: function(x) { return Math.log(x + Math.sqrt(x * x + 1)); }, asinhf: 'asinh', + asinhl: 'asinh', acosh: function(x) { return Math.log(x * 1 + Math.sqrt(x * x - 1)); }, acoshf: 'acosh', + acoshl: 'acosh', atanh: function(x) { return Math.log((1 + x) / (1 - x)) / 2; }, atanhf: 'atanh', + atanhl: 'atanh', exp2: function(x) { return Math.pow(2, x); }, exp2f: 'exp2', + exp2l: 'exp2', expm1: function(x) { return Math.exp(x) - 1; }, expm1f: 'expm1', + expm1l: 'expm1', round: function(x) { return (x < 0) ? -Math.round(-x) : Math.round(x); }, roundf: 'round', + roundl: 'round', lround: 'round', lroundf: 'round', + lroundl: 'round', llround: 'round', llroundf: 'round', + llroundl: 'round', rint: function(x) { if (Math.abs(x % 1) !== 0.5) return Math.round(x); return x + x % 2 + ((x < 0) ? 1 : -1); }, rintf: 'rint', + rintl: 'rint', lrint: 'rint', lrintf: 'rint', + lrintl: 'rint', #if USE_TYPED_ARRAYS == 2 llrint: function(x) { x = (x < 0) ? -Math.round(-x) : Math.round(x); @@ -4878,50 +4922,63 @@ LibraryManager.library = { llrint: 'rint', #endif llrintf: 'llrint', + llrintl: 'llrint', nearbyint: 'rint', nearbyintf: 'rint', + nearbyintl: 'rint', trunc: function(x) { return (x < 0) ? Math.ceil(x) : Math.floor(x); }, truncf: 'trunc', + truncl: 'trunc', fdim: function(x, y) { return (x > y) ? x - y : 0; }, fdimf: 'fdim', + fdiml: 'fdim', fmax: function(x, y) { return isNaN(x) ? y : isNaN(y) ? x : Math.max(x, y); }, fmaxf: 'fmax', + fmaxl: 'fmax', fmin: function(x, y) { return isNaN(x) ? y : isNaN(y) ? x : Math.min(x, y); }, fminf: 'fmin', + fminl: 'fmin', fma: function(x, y, z) { return x * y + z; }, fmaf: 'fma', + fmal: 'fma', fmod: function(x, y) { return x % y; }, fmodf: 'fmod', + fmodl: 'fmod', remainder: 'fmod', remainderf: 'fmod', + remainderl: 'fmod', log10: function(x) { return Math.log(x) / Math.LN10; }, log10f: 'log10', + log10l: 'log10', log1p: function(x) { return Math.log(1 + x); }, log1pf: 'log1p', + log1pl: 'log1p', log2: function(x) { return Math.log(x) / Math.LN2; }, log2f: 'log2', + log2l: 'log2', nan: function(x) { return NaN; }, nanf: 'nan', + nanl: 'nan', sincos: function(x, sine, cosine) { var sineVal = Math.sin(x), @@ -4929,6 +4986,7 @@ LibraryManager.library = { {{{ makeSetValue('sine', '0', 'sineVal', 'double') }}}; {{{ makeSetValue('cosine', '0', 'cosineVal', 'double') }}}; }, + sincosl: 'sincos', sincosf: function(x, sine, cosine) { var sineVal = Math.sin(x), @@ -5007,24 +5065,74 @@ LibraryManager.library = { // being compiled. Not sure how to tell LLVM to not do so. // ========================================================================== - // Data for dlfcn.h. - $DLFCN_DATA: { + $DLFCN: { +#if DLOPEN_SUPPORT + // extra asm.js dlopen support + functionTable: [], // will contain objects mapping sigs to js functions that call into the right asm module with the right index + + registerFunctions: function(asm, num, sigs, jsModule) { + // use asm module dynCall_* from functionTable + if (num % 2 == 1) num++; // keep pointers even + var table = DLFCN.functionTable; + var from = table.length; + assert(from % 2 == 0); + for (var i = 0; i < num; i++) { + table[from + i] = {}; + sigs.forEach(function(sig) { // TODO: new Function etc. + var full = 'dynCall_' + sig; + table[from + i][sig] = function() { + arguments[0] -= from; + return asm[full].apply(null, arguments); + } + }); + } + + if (jsModule.cleanups) { + var newLength = table.length; + jsModule.cleanups.push(function() { + if (table.length === newLength) { + table.length = from; // nothing added since, just shrink + } else { + // something was added above us, clear and leak the span + for (var i = 0; i < num; i++) { + table[from + i] = null; + } + } + while (table.length > 0 && table[table.length-1] === null) table.pop(); + }); + } + + // patch js module dynCall_* to use functionTable + sigs.forEach(function(sig) { + jsModule['dynCall_' + sig] = function() { + return table[arguments[0]][sig].apply(null, arguments); + }; + }); + }, +#endif + error: null, errorMsg: null, loadedLibs: {}, // handle -> [refcount, name, lib_object] loadedLibNames: {}, // name -> handle }, // void* dlopen(const char* filename, int flag); - dlopen__deps: ['$DLFCN_DATA', '$FS', '$ENV'], + dlopen__deps: ['$DLFCN', '$FS', '$ENV'], dlopen: function(filename, flag) { // void *dlopen(const char *file, int mode); // http://pubs.opengroup.org/onlinepubs/009695399/functions/dlopen.html filename = filename === 0 ? '__self__' : (ENV['LD_LIBRARY_PATH'] || '/') + Pointer_stringify(filename); - if (DLFCN_DATA.loadedLibNames[filename]) { +#if ASM_JS +#if DLOPEN_SUPPORT == 0 + abort('need to build with DLOPEN_SUPPORT=1 to get dlopen support in asm.js'); +#endif +#endif + + if (DLFCN.loadedLibNames[filename]) { // Already loaded; increment ref count and return. - var handle = DLFCN_DATA.loadedLibNames[filename]; - DLFCN_DATA.loadedLibs[handle].refcount++; + var handle = DLFCN.loadedLibNames[filename]; + DLFCN.loadedLibs[handle].refcount++; return handle; } @@ -5035,7 +5143,7 @@ LibraryManager.library = { } else { var target = FS.findObject(filename); if (!target || target.isFolder || target.isDevice) { - DLFCN_DATA.errorMsg = 'Could not find dynamic lib: ' + filename; + DLFCN.errorMsg = 'Could not find dynamic lib: ' + filename; return 0; } else { FS.forceLoadFile(target); @@ -5043,19 +5151,26 @@ LibraryManager.library = { } try { - var lib_module = eval(lib_data)({{{ Functions.getTable('x') }}}.length); + var lib_module = eval(lib_data)( +#if ASM_JS + DLFCN.functionTable.length, +#else + {{{ Functions.getTable('x') }}}.length, +#endif + Module + ); } catch (e) { #if ASSERTIONS Module.printErr('Error in loading dynamic library: ' + e); #endif - DLFCN_DATA.errorMsg = 'Could not evaluate dynamic lib: ' + filename; + DLFCN.errorMsg = 'Could not evaluate dynamic lib: ' + filename; return 0; } // Not all browsers support Object.keys(). var handle = 1; - for (var key in DLFCN_DATA.loadedLibs) { - if (DLFCN_DATA.loadedLibs.hasOwnProperty(key)) handle++; + for (var key in DLFCN.loadedLibs) { + if (DLFCN.loadedLibs.hasOwnProperty(key)) handle++; } // We don't care about RTLD_NOW and RTLD_LAZY. @@ -5069,60 +5184,66 @@ LibraryManager.library = { var cached_functions = {}; } - DLFCN_DATA.loadedLibs[handle] = { + DLFCN.loadedLibs[handle] = { refcount: 1, name: filename, module: lib_module, cached_functions: cached_functions }; - DLFCN_DATA.loadedLibNames[filename] = handle; + DLFCN.loadedLibNames[filename] = handle; return handle; }, // int dlclose(void* handle); - dlclose__deps: ['$DLFCN_DATA'], + dlclose__deps: ['$DLFCN'], dlclose: function(handle) { // int dlclose(void *handle); // http://pubs.opengroup.org/onlinepubs/009695399/functions/dlclose.html - if (!DLFCN_DATA.loadedLibs[handle]) { - DLFCN_DATA.errorMsg = 'Tried to dlclose() unopened handle: ' + handle; + if (!DLFCN.loadedLibs[handle]) { + DLFCN.errorMsg = 'Tried to dlclose() unopened handle: ' + handle; return 1; } else { - var lib_record = DLFCN_DATA.loadedLibs[handle]; + var lib_record = DLFCN.loadedLibs[handle]; if (--lib_record.refcount == 0) { - delete DLFCN_DATA.loadedLibNames[lib_record.name]; - delete DLFCN_DATA.loadedLibs[handle]; + if (lib_record.module.cleanups) { + lib_record.module.cleanups.forEach(function(cleanup) { cleanup() }); + } + delete DLFCN.loadedLibNames[lib_record.name]; + delete DLFCN.loadedLibs[handle]; } return 0; } }, // void* dlsym(void* handle, const char* symbol); - dlsym__deps: ['$DLFCN_DATA'], + dlsym__deps: ['$DLFCN'], dlsym: function(handle, symbol) { // void *dlsym(void *restrict handle, const char *restrict name); // http://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html symbol = '_' + Pointer_stringify(symbol); - if (!DLFCN_DATA.loadedLibs[handle]) { - DLFCN_DATA.errorMsg = 'Tried to dlsym() from an unopened handle: ' + handle; + if (!DLFCN.loadedLibs[handle]) { + DLFCN.errorMsg = 'Tried to dlsym() from an unopened handle: ' + handle; return 0; } else { - var lib = DLFCN_DATA.loadedLibs[handle]; + var lib = DLFCN.loadedLibs[handle]; // self-dlopen means that lib.module is not a superset of // cached_functions, so check the latter first if (lib.cached_functions.hasOwnProperty(symbol)) { return lib.cached_functions[symbol]; } else { if (!lib.module.hasOwnProperty(symbol)) { - DLFCN_DATA.errorMsg = ('Tried to lookup unknown symbol "' + symbol + + DLFCN.errorMsg = ('Tried to lookup unknown symbol "' + symbol + '" in dynamic lib: ' + lib.name); return 0; } else { var result = lib.module[symbol]; if (typeof result == 'function') { - {{{ Functions.getTable('x') }}}.push(result); - {{{ Functions.getTable('x') }}}.push(0); - result = {{{ Functions.getTable('x') }}}.length - 2; +#if ASM_JS + result = lib.module.SYMBOL_TABLE[symbol]; + assert(result); +#else + result = Runtime.addFunction(result); +#endif lib.cached_functions = result; } return result; @@ -5131,18 +5252,18 @@ LibraryManager.library = { } }, // char* dlerror(void); - dlerror__deps: ['$DLFCN_DATA'], + dlerror__deps: ['$DLFCN'], dlerror: function() { // char *dlerror(void); // http://pubs.opengroup.org/onlinepubs/009695399/functions/dlerror.html - if (DLFCN_DATA.errorMsg === null) { + if (DLFCN.errorMsg === null) { return 0; } else { - if (DLFCN_DATA.error) _free(DLFCN_DATA.error); - var msgArr = intArrayFromString(DLFCN_DATA.errorMsg); - DLFCN_DATA.error = allocate(msgArr, 'i8', ALLOC_NORMAL); - DLFCN_DATA.errorMsg = null; - return DLFCN_DATA.error; + if (DLFCN.error) _free(DLFCN.error); + var msgArr = intArrayFromString(DLFCN.errorMsg); + DLFCN.error = allocate(msgArr, 'i8', ALLOC_NORMAL); + DLFCN.errorMsg = null; + return DLFCN.error; } }, @@ -5222,8 +5343,8 @@ LibraryManager.library = { ['i32', 'tm_zone']]), // Statically allocated time struct. __tm_current: 'allocate({{{ Runtime.QUANTUM_SIZE }}}*26, "i8", ALLOC_STATIC)', - // Statically allocated timezone strings. - __tm_timezones: {}, + // Statically allocated timezone string. We only use GMT as a timezone. + __tm_timezone: 'allocate(intArrayFromString("GMT"), "i8", ALLOC_STATIC)', // Statically allocated time strings. __tm_formatted: 'allocate({{{ Runtime.QUANTUM_SIZE }}}*26, "i8", ALLOC_STATIC)', @@ -5251,7 +5372,7 @@ LibraryManager.library = { return _gmtime_r(time, ___tm_current); }, - gmtime_r__deps: ['__tm_struct_layout', '__tm_timezones'], + gmtime_r__deps: ['__tm_struct_layout', '__tm_timezone'], gmtime_r: function(time, tmPtr) { var date = new Date({{{ makeGetValue('time', 0, 'i32') }}}*1000); var offsets = ___tm_struct_layout; @@ -5273,12 +5394,7 @@ LibraryManager.library = { start.setUTCMilliseconds(0); var yday = Math.floor((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)); {{{ makeSetValue('tmPtr', 'offsets.tm_yday', 'yday', 'i32') }}} - - var timezone = "GMT"; - if (!(timezone in ___tm_timezones)) { - ___tm_timezones[timezone] = allocate(intArrayFromString(timezone), 'i8', ALLOC_NORMAL); - } - {{{ makeSetValue('tmPtr', 'offsets.tm_zone', '___tm_timezones[timezone]', 'i32') }}} + {{{ makeSetValue('tmPtr', 'offsets.tm_zone', '___tm_timezone', 'i32') }}} return tmPtr; }, @@ -5297,7 +5413,7 @@ LibraryManager.library = { return _localtime_r(time, ___tm_current); }, - localtime_r__deps: ['__tm_struct_layout', '__tm_timezones', 'tzset'], + localtime_r__deps: ['__tm_struct_layout', '__tm_timezone', 'tzset'], localtime_r: function(time, tmPtr) { _tzset(); var offsets = ___tm_struct_layout; @@ -5318,11 +5434,7 @@ LibraryManager.library = { var dst = Number(start.getTimezoneOffset() != date.getTimezoneOffset()); {{{ makeSetValue('tmPtr', 'offsets.tm_isdst', 'dst', 'i32') }}} - var timezone = 'GMT'; // XXX do not rely on browser timezone info, it is very unpredictable | date.toString().match(/\(([A-Z]+)\)/)[1]; - if (!(timezone in ___tm_timezones)) { - ___tm_timezones[timezone] = allocate(intArrayFromString(timezone), 'i8', ALLOC_NORMAL); - } - {{{ makeSetValue('tmPtr', 'offsets.tm_zone', '___tm_timezones[timezone]', 'i32') }}} + {{{ makeSetValue('tmPtr', 'offsets.tm_zone', '___tm_timezone', 'i32') }}} return tmPtr; }, @@ -6004,7 +6116,7 @@ LibraryManager.library = { // int clock_gettime(clockid_t clk_id, struct timespec *tp); var now = Date.now(); {{{ makeSetValue('tp', '___timespec_struct_layout.tv_sec', 'Math.floor(now/1000)', 'i32') }}}; // seconds - {{{ makeSetValue('tp', '___timespec_struct_layout.tv_nsec', '0', 'i32') }}}; // nanoseconds - not supported + {{{ makeSetValue('tp', '___timespec_struct_layout.tv_nsec', '(now % 1000) * 1000 * 1000', 'i32') }}}; // nanoseconds (really milliseconds) return 0; }, clock_settime: function(clk_id, tp) { @@ -6016,7 +6128,7 @@ LibraryManager.library = { clock_getres: function(clk_id, res) { // int clock_getres(clockid_t clk_id, struct timespec *res); {{{ makeSetValue('res', '___timespec_struct_layout.tv_sec', '1', 'i32') }}} - {{{ makeSetValue('res', '___timespec_struct_layout.tv_nsec', '0', 'i32') }}} + {{{ makeSetValue('res', '___timespec_struct_layout.tv_nsec', '1000 * 1000', 'i32') }}} // resolution is milliseconds return 0; }, @@ -6910,7 +7022,6 @@ LibraryManager.library = { // ========================================================================== // arpa/inet.h // ========================================================================== - htonl: function(value) { return ((value & 0xff) << 24) + ((value & 0xff00) << 8) + ((value & 0xff0000) >>> 8) + ((value & 0xff000000) >>> 24); @@ -6921,75 +7032,43 @@ LibraryManager.library = { ntohl: 'htonl', ntohs: 'htons', - // http://pubs.opengroup.org/onlinepubs/9699919799/functions/inet_ntop.html - inet_ntop__deps: ['__setErrNo', '$ERRNO_CODES', 'inet_ntop4', 'inet_ntop6'], - inet_ntop: function(af, src, dst, size) { - switch (af) { - case {{{ cDefine('AF_INET') }}}: - return _inet_ntop4(src, dst, size); - case {{{ cDefine('AF_INET6') }}}: - return _inet_ntop6(src, dst, size); - default: - ___setErrNo(ERRNO_CODES.EAFNOSUPPORT); - return 0; - } - }, - inet_pton__deps: ['__setErrNo', '$ERRNO_CODES', 'inet_pton4', 'inet_pton6'], - inet_pton: function(af, src, dst) { - switch (af) { - case {{{ cDefine('AF_INET') }}}: - return _inet_pton4(src, dst); - case {{{ cDefine('AF_INET6') }}}: - return _inet_pton6(src, dst); - default: - ___setErrNo(ERRNO_CODES.EAFNOSUPPORT); - return -1; - } - }, + // old ipv4 only functions + inet_addr__deps: ['_inet_pton4_raw'], inet_addr: function(ptr) { - var b = Pointer_stringify(ptr).split("."); - if (b.length !== 4) return -1; // we return -1 for error, and otherwise a uint32. this helps inet_pton differentiate - return (Number(b[0]) | (Number(b[1]) << 8) | (Number(b[2]) << 16) | (Number(b[3]) << 24)) >>> 0; - }, - _inet_aton_raw: function(str) { - var b = str.split("."); - return (Number(b[0]) | (Number(b[1]) << 8) | (Number(b[2]) << 16) | (Number(b[3]) << 24)) >>> 0; - }, - _inet_ntoa_raw: function(addr) { - return (addr & 0xff) + '.' + ((addr >> 8) & 0xff) + '.' + ((addr >> 16) & 0xff) + '.' + ((addr >> 24) & 0xff) + var addr = __inet_pton4_raw(Pointer_stringify(ptr)); + if (addr === null) { + return -1; + } + return addr; }, - inet_ntoa__deps: ['_inet_ntoa_raw'], + inet_ntoa__deps: ['_inet_ntop4_raw'], inet_ntoa: function(in_addr) { if (!_inet_ntoa.buffer) { _inet_ntoa.buffer = _malloc(1024); } - var addr = getValue(in_addr, 'i32'); - var str = __inet_ntoa_raw(addr); + var addr = {{{ makeGetValue('in_addr', '0', 'i32') }}}; + var str = __inet_ntop4_raw(addr); writeStringToMemory(str.substr(0, 1024), _inet_ntoa.buffer); return _inet_ntoa.buffer; }, - inet_aton__deps: ['inet_addr'], + inet_aton__deps: ['_inet_pton4_raw'], inet_aton: function(cp, inp) { - var addr = _inet_addr(cp); - setValue(inp, addr, 'i32'); - if (addr < 0) return 0; - return 1; - }, - - inet_ntop4__deps: ['__setErrNo', '$ERRNO_CODES', '_inet_ntoa_raw'], - inet_ntop4: function(src, dst, size) { - var str = __inet_ntoa_raw(getValue(src, 'i32')); - if (str.length+1 > size) { - ___setErrNo(ERRNO_CODES.ENOSPC); + var addr = __inet_pton4_raw(Pointer_stringify(cp)); + if (addr === null) { return 0; } - writeStringToMemory(str, dst); - return dst; + {{{ makeSetValue('inp', '0', 'addr', 'i32') }}} + return 1; }, - inet_ntop6__deps: ['__setErrNo', '$ERRNO_CODES', 'inet_ntop6_raw'], - inet_ntop6: function(src, dst, size) { - var str = _inet_ntop6_raw(src); + // new ipv4 / ipv6 functions + _inet_ntop4_raw: function(addr) { + return (addr & 0xff) + '.' + ((addr >> 8) & 0xff) + '.' + ((addr >> 16) & 0xff) + '.' + ((addr >> 24) & 0xff) + }, + _inet_ntop4__deps: ['__setErrNo', '$ERRNO_CODES', '_inet_ntop4_raw'], + _inet_ntop4: function(src, dst, size) { + var addr = {{{ makeGetValue('src', '0', 'i32') }}}; + var str = __inet_ntop4_raw(addr); if (str.length+1 > size) { ___setErrNo(ERRNO_CODES.ENOSPC); return 0; @@ -6997,9 +7076,8 @@ LibraryManager.library = { writeStringToMemory(str, dst); return dst; }, - inet_ntop6_raw__deps: ['ntohs'], - inet_ntop6_raw: function(src) { - + _inet_ntop6_raw__deps: ['ntohs', '_inet_ntop4_raw'], + _inet_ntop6_raw: function(ints) { // ref: http://www.ietf.org/rfc/rfc2373.txt - section 2.5.4 // Format for IPv4 compatible and mapped 128-bit IPv6 Addresses // 128-bits are split into eight 16-bit words @@ -7014,7 +7092,6 @@ LibraryManager.library = { // +--------------------------------------+----+---------------------+ // |0000..............................0000|FFFF| IPv4 ADDRESS | (mapped) // +--------------------------------------+----+---------------------+ - var str = ""; var word = 0; var longest = 0; @@ -7022,27 +7099,37 @@ LibraryManager.library = { var zstart = 0; var len = 0; var i = 0; + var parts = [ + ints[0] & 0xffff, + (ints[0] >> 16), + ints[1] & 0xffff, + (ints[1] >> 16), + ints[2] & 0xffff, + (ints[2] >> 16), + ints[3] & 0xffff, + (ints[3] >> 16) + ]; // Handle IPv4-compatible, IPv4-mapped, loopback and any/unspecified addresses var hasipv4 = true; var v4part = ""; // check if the 10 high-order bytes are all zeros (first 5 words) - for (i = 0; i < 10; i++) { - if ({{{ makeGetValue('src', 'i', 'i8') }}} !== 0) { hasipv4 = false; break; } + for (i = 0; i < 5; i++) { + if (parts[i] !== 0) { hasipv4 = false; break; } } if (hasipv4) { // low-order 32-bits store an IPv4 address (bytes 13 to 16) (last 2 words) - v4part = __inet_ntoa_raw({{{ makeGetValue('src', '12', 'i32') }}}); + v4part = __inet_ntop4_raw(parts[6] | (parts[7] << 16)); // IPv4-mapped IPv6 address if 16-bit value (bytes 11 and 12) == 0xFFFF (6th word) - if ({{{ makeGetValue('src', '10', 'i16') }}} === -1) { + if (parts[5] === -1) { str = "::ffff:"; str += v4part; return str; } // IPv4-compatible IPv6 address if 16-bit value (bytes 11 and 12) == 0x0000 (6th word) - if ({{{ makeGetValue('src', '10', 'i16') }}} === 0) { + if (parts[5] === 0) { str = "::"; //special case IPv6 addresses if(v4part === "0.0.0.0") v4part = ""; // any/unspecified address @@ -7056,7 +7143,7 @@ LibraryManager.library = { // first run to find the longest contiguous zero words for (word = 0; word < 8; word++) { - if ({{{ makeGetValue('src', 'word*2', 'i16') }}} === 0) { + if (parts[word] === 0) { if (word - lastzero > 1) { len = 0; } @@ -7072,7 +7159,7 @@ LibraryManager.library = { for (word = 0; word < 8; word++) { if (longest > 1) { // compress contiguous zeros - to produce "::" - if ({{{ makeGetValue('src', 'word*2', 'i16') }}} === 0 && word >= zstart && word < (zstart + longest) ) { + if (parts[word] === 0 && word >= zstart && word < (zstart + longest) ) { if (word === zstart) { str += ":"; if (zstart === 0) str += ":"; //leading zeros case @@ -7081,54 +7168,86 @@ LibraryManager.library = { } } // converts 16-bit words from big-endian to little-endian before converting to hex string - str += Number(_ntohs({{{ makeGetValue('src', 'word*2', 'i16') }}} & 0xffff)).toString(16); + str += Number(_ntohs(parts[word] & 0xffff)).toString(16); str += word < 7 ? ":" : ""; } return str; }, - - inet_pton4__deps: ['inet_addr'], - inet_pton4: function(src, dst) { - var ret = _inet_addr(src); - if (ret === -1 || isNaN(ret)) return 0; - setValue(dst, ret, 'i32'); - return 1; + _inet_ntop6__deps: ['__setErrNo', '$ERRNO_CODES', '_inet_ntop6_raw'], + _inet_ntop6: function(src, dst, size) { + var addr = [ + {{{ makeGetValue('src', '0', 'i32') }}}, {{{ makeGetValue('src', '4', 'i32') }}}, + {{{ makeGetValue('src', '8', 'i32') }}}, {{{ makeGetValue('src', '12', 'i32') }}} + ]; + var str = __inet_ntop6_raw(addr); + if (str.length+1 > size) { + ___setErrNo(ERRNO_CODES.ENOSPC); + return 0; + } + writeStringToMemory(str, dst); + return dst; }, - - inet_pton6__deps: ['inet_pton6_raw'], - inet_pton6: function(src, dst) { - return _inet_pton6_raw(Pointer_stringify(src), dst); + inet_ntop__deps: ['__setErrNo', '$ERRNO_CODES', '_inet_ntop4', '_inet_ntop6'], + inet_ntop: function(af, src, dst, size) { + // http://pubs.opengroup.org/onlinepubs/9699919799/functions/inet_ntop.html + switch (af) { + case {{{ cDefine('AF_INET') }}}: + return __inet_ntop4(src, dst, size); + case {{{ cDefine('AF_INET6') }}}: + return __inet_ntop6(src, dst, size); + default: + ___setErrNo(ERRNO_CODES.EAFNOSUPPORT); + return 0; + } }, - inet_pton6_raw__deps: ['htons'], - inet_pton6_raw: function(addr, dst) { + _inet_pton4_raw: function(str) { + var b = str.split('.'); + for (var i = 0; i < 4; i++) { + var tmp = Number(b[i]); + if (isNaN(tmp)) return null; + b[i] = tmp; + } + return (b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24)) >>> 0; + }, + _inet_pton4__deps: ['_inet_pton4_raw'], + _inet_pton4: function(src, dst) { + var ret = __inet_pton4_raw(Pointer_stringify(src)); + if (ret === null) { + return 0; + } + {{{ makeSetValue('dst', '0', 'ret', 'i32') }}} + return 1; + }, + _inet_pton6_raw__deps: ['htons'], + _inet_pton6_raw: function(str) { var words; var w, offset, z, i; /* http://home.deds.nl/~aeron/regex/ */ var valid6regx = /^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i - if (!valid6regx.test(addr)) { - return 0; + var parts = []; + if (!valid6regx.test(str)) { + return null; } - if (addr === "::") { - for (i=0; i < 4; i++) {{{ makeSetValue('dst', 'i*4', '0', 'i32') }}}; - return 1; + if (str === "::") { + return [0, 0, 0, 0, 0, 0, 0, 0]; } // Z placeholder to keep track of zeros when splitting the string on ":" - if (addr.indexOf("::") === 0) { - addr = addr.replace("::", "Z:"); // leading zeros case + if (str.indexOf("::") === 0) { + str = str.replace("::", "Z:"); // leading zeros case } else { - addr = addr.replace("::", ":Z:"); + str = str.replace("::", ":Z:"); } - if (addr.indexOf(".") > 0) { - // parse IPv4 embedded address - addr = addr.replace(new RegExp('[.]', 'g'), ":"); - words = addr.split(":"); + if (str.indexOf(".") > 0) { + // parse IPv4 embedded stress + str = str.replace(new RegExp('[.]', 'g'), ":"); + words = str.split(":"); words[words.length-4] = parseInt(words[words.length-4]) + parseInt(words[words.length-3])*256; words[words.length-3] = parseInt(words[words.length-2]) + parseInt(words[words.length-1])*256; words = words.slice(0, words.length-2); } else { - words = addr.split(":"); + words = str.split(":"); } offset = 0; z = 0; @@ -7137,22 +7256,69 @@ LibraryManager.library = { if (words[w] === 'Z') { // compressed zeros - write appropriate number of zero words for (z = 0; z < (8 - words.length+1); z++) { - {{{ makeSetValue('dst', '(w+z)*2', '0', 'i16') }}}; + parts[w+z] = 0; } offset = z-1; } else { // parse hex to field to 16-bit value and write it in network byte-order - {{{ makeSetValue('dst', '(w+offset)*2', '_htons(parseInt(words[w],16))', 'i16') }}}; + parts[w+offset] = _htons(parseInt(words[w],16)); } } else { // parsed IPv4 words - {{{ makeSetValue('dst', '(w+offset)*2', 'words[w]', 'i16') }}}; + parts[w+offset] = words[w]; } } + return [ + (parts[1] << 16) | parts[0], + (parts[3] << 16) | parts[2], + (parts[5] << 16) | parts[4], + (parts[7] << 16) | parts[6] + ]; + }, + _inet_pton6__deps: ['_inet_pton6_raw'], + _inet_pton6: function(src, dst) { + var ints = __inet_pton6_raw(Pointer_stringify(src)); + if (ints === null) { + return 0; + } + for (var i = 0; i < 4; i++) { + {{{ makeSetValue('dst', 'i*4', 'ints[i]', 'i32') }}}; + } return 1; }, + inet_pton__deps: ['__setErrNo', '$ERRNO_CODES', '_inet_pton4', '_inet_pton6'], + inet_pton: function(af, src, dst) { + // http://pubs.opengroup.org/onlinepubs/9699919799/functions/inet_pton.html + switch (af) { + case {{{ cDefine('AF_INET') }}}: + return __inet_pton4(src, dst); + case {{{ cDefine('AF_INET6') }}}: + return __inet_pton6(src, dst); + default: + ___setErrNo(ERRNO_CODES.EAFNOSUPPORT); + return -1; + } + }, + + // ========================================================================== + // net/if.h + // ========================================================================== + + if_nametoindex: function(a) { + return 0; + }, + if_indextoname: function(a, b) { + return 0; + }, + if_nameindex: function() { + return 0; + }, + if_freenameindex: function(a) { + }, + // ========================================================================== // netinet/in.h + // ========================================================================== _in6addr_any: 'allocate([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], "i8", ALLOC_STATIC)', @@ -7173,10 +7339,56 @@ LibraryManager.library = { // netdb.h // ========================================================================== - // All we can do is alias names to ips. you give this a name, it returns an - // "ip" that we later know to use as a name. There is no way to do actual - // name resolving clientside in a browser. - // we do the aliasing in 172.29.*.*, giving us 65536 possibilities + // We can't actually resolve hostnames in the browser, so instead + // we're generating fake IP addresses with lookup_name that we can + // resolve later on with lookup_addr. + // We do the aliasing in 172.29.*.*, giving us 65536 possibilities. + $DNS: { + address_map: { + id: 1, + addrs: {}, + names: {} + }, + + lookup_name__deps: ['_inet_pton4_raw', '_inet_pton6_raw'], + lookup_name: function (name) { + // If the name is already a valid ipv4 / ipv6 address, don't generate a fake one. + var res = __inet_pton4_raw(name); + if (res) { + return name; + } + res = __inet_pton6_raw(name); + if (res) { + return name; + } + + // See if this name is already mapped. + var addr; + + if (DNS.address_map.addrs[name]) { + addr = DNS.address_map.addrs[name]; + } else { + var id = DNS.address_map.id++; + assert(id < 65535, 'exceeded max address mappings of 65535'); + + addr = '172.29.' + (id & 0xff) + '.' + (id & 0xff00); + + DNS.address_map.names[addr] = name; + DNS.address_map.addrs[name] = addr; + } + + return addr; + }, + + lookup_addr: function (addr) { + if (DNS.address_map.names[addr]) { |