From 3e4a22b4a9648dd606cb35814d5100b5ef948ace Mon Sep 17 00:00:00 2001 From: Fraser Adams Date: Sun, 24 Nov 2013 11:16:36 +0000 Subject: [PATCH] add getprotobyname and associated functions from netdb.h. Add test_getprotobyname.c test suite and update test_sockets.py to include test_getprotobyname. ./runner.py sockets.test_getprotobyname completes successfully --- src/library.js | 83 +++++++++++++++++++++++++++ tests/sockets/test_getprotobyname.c | 87 +++++++++++++++++++++++++++++ tests/test_sockets.py | 3 + 3 files changed, 173 insertions(+) create mode 100644 tests/sockets/test_getprotobyname.c diff --git a/src/library.js b/src/library.js index 3df617242..30947fe2b 100644 --- a/src/library.js +++ b/src/library.js @@ -7682,6 +7682,89 @@ LibraryManager.library = { return _gai_strerror.buffer; }, + // Implement netdb.h protocol entry (getprotoent, getprotobyname, getprotobynumber, setprotoent, endprotoent) + // http://pubs.opengroup.org/onlinepubs/9699919799/functions/getprotobyname.html + $PROTOCOL_LIST: [], + $PROTOCOL_MAP: {}, + setprotoent__deps: ['$PROTOCOL_LIST', '$PROTOCOL_MAP'], + setprotoent: function(stayopen) { + // void setprotoent(int stayopen); + + // Allocate and populate a protoent structure given a name, protocol number and array of aliases + function allocprotoent(name, proto, aliases) { + // write name into buffer + var nameBuf = _malloc(name.length + 1); + writeAsciiToMemory(name, nameBuf); + + // write aliases into buffer + var j = 0; + var length = aliases.length; + var aliasListBuf = _malloc((length + 1) * 4); // Use length + 1 so we have space for the terminating NULL ptr. + + for (var i = 0; i < length; i++, j += 4) { + var alias = aliases[i]; + var aliasBuf = _malloc(alias.length + 1); + writeAsciiToMemory(alias, aliasBuf); + {{{ makeSetValue('aliasListBuf', 'j', 'aliasBuf', 'i8*') }}}; + } + {{{ makeSetValue('aliasListBuf', 'j', '0', 'i8*') }}}; // Terminating NULL pointer. + + // generate protoent + var pe = _malloc({{{ C_STRUCTS.protoent.__size__ }}}); + {{{ makeSetValue('pe', C_STRUCTS.protoent.p_name, 'nameBuf', 'i8*') }}}; + {{{ makeSetValue('pe', C_STRUCTS.protoent.p_aliases, 'aliasListBuf', 'i8**') }}}; + {{{ makeSetValue('pe', C_STRUCTS.protoent.p_proto, 'proto', 'i32') }}}; + return pe; + }; + + // Populate the protocol 'database'. The entries are limited to tcp and udp, though it is fairly trivial + // to add extra entries from /etc/protocols if desired - though not sure if that'd actually be useful. + if (PROTOCOL_LIST.length === 0) { + var entry = allocprotoent('tcp', 6, ['TCP']); + PROTOCOL_LIST.push(entry); + PROTOCOL_MAP['tcp'] = PROTOCOL_MAP['6'] = entry; + entry = allocprotoent('udp', 17, ['UDP']); + PROTOCOL_LIST.push(entry); + PROTOCOL_MAP['udp'] = PROTOCOL_MAP['17'] = entry; + } + + _setprotoent.index = 0; + }, + + endprotoent: function() { + // void endprotoent(void); + // We're not using a real protocol database so we don't do a real close. + }, + + getprotoent__deps: ['setprotoent', '$PROTOCOL_LIST'], + getprotoent: function(number) { + // struct protoent *getprotoent(void); + // reads the next entry from the protocols 'database' or return NULL if 'eof' + if (_setprotoent.index === PROTOCOL_LIST.length) { + return null; + } else { + var result = PROTOCOL_LIST[_setprotoent.index++]; + return result; + } + }, + + getprotobyname__deps: ['setprotoent', '$PROTOCOL_MAP'], + getprotobyname: function(name) { + // struct protoent *getprotobyname(const char *); + name = Pointer_stringify(name); + _setprotoent(true); + var result = PROTOCOL_MAP[name]; + return result; + }, + + getprotobynumber__deps: ['setprotoent', '$PROTOCOL_MAP'], + getprotobynumber: function(number) { + // struct protoent *getprotobynumber(int proto); + _setprotoent(true); + var result = PROTOCOL_MAP[number]; + return result; + }, + // ========================================================================== // sockets. Note that the implementation assumes all sockets are always // nonblocking diff --git a/tests/sockets/test_getprotobyname.c b/tests/sockets/test_getprotobyname.c new file mode 100644 index 000000000..571a287e8 --- /dev/null +++ b/tests/sockets/test_getprotobyname.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include +#include + +void checkEntryByValue(char* name, int port, char** aliasArray) { + struct protoent* entry; + char** aliases; + + // Perform a protocol look up by name + entry = getprotobyname(name); + assert(entry != NULL); + + // Check results + assert(strcmp(name, entry->p_name) == 0); + assert(port == entry->p_proto); + + aliases = entry->p_aliases; + for (int i = 0; aliases[i] != NULL; i++) { + assert(strcmp(aliases[i], aliasArray[i]) == 0); + } + + // Perform a protocol look up by number + entry = getprotobynumber(port); + assert(entry != NULL); + + // Check results + assert(strcmp(name, entry->p_name) == 0); + assert(port == entry->p_proto); + + aliases = entry->p_aliases; + for (int i = 0; aliases[i] != NULL; i++) { + assert(strcmp(aliases[i], aliasArray[i]) == 0); + } +} + +void checkEntryDatabase() { + struct protoent* entry; + + // Don't call setprotoent() initially as getprotoent() should open the "database" if necessary. + entry = getprotoent(); + assert(entry != NULL); + assert(strcmp("tcp", entry->p_name) == 0); + + entry = getprotoent(); + assert(entry != NULL); + assert(strcmp("udp", entry->p_name) == 0); + + // Check that setprotoent() correctly sets the next entry to the first entry + setprotoent(1); + + entry = getprotoent(); + assert(entry != NULL); + assert(strcmp("tcp", entry->p_name) == 0); + + entry = getprotoent(); + assert(entry != NULL); + assert(strcmp("udp", entry->p_name) == 0); + + // If we do a getprotoent() that goes past the end of the 'database' check that it returns NULL. + entry = getprotoent(); + assert(entry == NULL); +} + +int main() { + // First check getprotobyname() and getprotobynumber() + char* aliases[] = {"TCP"}; + checkEntryByValue("tcp", 6, aliases); + + aliases[0] = "UDP"; + checkEntryByValue("udp", 17, aliases); + + // Check that the doomsday protocol hasn't been implemented :-) ...... + assert(getprotobyname("doomsday") == NULL); + + // Now check setprotoent() and getprotoent() + checkEntryDatabase(); + + endprotoent(); + + puts("success"); + + return EXIT_SUCCESS; +} + diff --git a/tests/test_sockets.py b/tests/test_sockets.py index 1229aa70f..f9dcbc683 100644 --- a/tests/test_sockets.py +++ b/tests/test_sockets.py @@ -228,6 +228,9 @@ class sockets(BrowserCore): def test_gethostbyname(self): self.do_run(open(path_from_root('tests', 'sockets', 'test_gethostbyname.c')).read(), 'success') + def test_getprotobyname(self): + self.do_run(open(path_from_root('tests', 'sockets', 'test_getprotobyname.c')).read(), 'success') + def test_sockets_echo(self): sockets_include = '-I'+path_from_root('tests', 'sockets')