Mercurial > hg > index.cgi
diff src/lwwire.c @ 10:36c4cda4b6c4
Add extension support with the PINGPONG extension
Add extension support. There are two ways to add extensions:
1. as a shared object which will be loaded with ext=<filename> as a
parameter to lwwire. See the lwwire_pingpong.c file for details.
2. By doing basically the same thing as a shared object but linking it into
the main binary and calling lwwire_register_extension() appropriately.
author | William Astle <lost@l-w.ca> |
---|---|
date | Sat, 30 Jul 2016 13:16:39 -0600 |
parents | a11b330771e0 |
children | 38184ef1296d |
line wrap: on
line diff
--- a/src/lwwire.c Sat Jul 30 10:35:14 2016 -0600 +++ b/src/lwwire.c Sat Jul 30 13:16:39 2016 -0600 @@ -39,6 +39,7 @@ // for nanosleep #define _POSIX_C_SOURCE 199309L +#include <dlfcn.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> @@ -61,6 +62,17 @@ int isconst; }; +struct lwwire_extension_data +{ + int enabled; + int (*handler)(int op); // handle op, return -1 if not supported + int (*disable)(void); // disable extension negotiated + int (*enable)(void); // enable extension negotiated (return -1 if failed to init) + void (*reset)(void); // on server reset opcode; extension will be disabled automatically here +}; + +struct lwwire_extension_data lwwire_extension_list[256]; + struct lwwire_driveinfo drivedata[256]; void lwwire_protoerror(void); @@ -74,7 +86,7 @@ int lwwire_save_sector(int dn, int lsn, void *); int nonblock(int); int lwwire_drive_readononly(int dn); - +int lwwire_register_extension(int, int (*handler)(int), int (*enable)(void), int (*disable)(void), void (*reset)(void)); void lwwire_proto_read(void); void lwwire_proto_write(void); void lwwire_proto_readex(void); @@ -103,10 +115,43 @@ } memset(&drivedata, 0, sizeof(drivedata)); + memset(lwwire_extension_list, 0, sizeof(struct lwwire_extension_data) * 256); + // call lwwire_register_extension() for each extension you define + // statically. Add those calls here, or calls to the equivalent + // of the "lwwire_register" function from a DSO type extension. + for (i = 1; i < argc; i++) { - if (strncmp("drive=", argv[i], 6) == 0) + if (strncmp("ext=", argv[i], 4) == 0) + { + // SO name is at argv[i]+4 + void *dlhandle; + void *initfn; + int (*rinitfn)(void); + + dlhandle = dlopen(argv[i] + 4, RTLD_NOW | RTLD_LOCAL); + if (!dlhandle) + { + fprintf(stderr, "Cannot load extension %s: %s\n", argv[i] + 4, dlerror()); + continue; + } + initfn = dlsym(dlhandle, "lwwire_register"); + if (!initfn) + { + dlclose(dlhandle); + fprintf(stderr, "Extension '%s' is not valid.\n", argv[i] + 4); + continue; + } + rinitfn = initfn; + if ((*rinitfn)() != 0) + { + dlclose(dlhandle); + fprintf(stderr, "Initialization of extension '%s' failed.\n", argv[i] + 4); + continue; + } + } + else if (strncmp("drive=", argv[i], 6) == 0) { int dn=0; int isconst = 0; @@ -331,31 +376,68 @@ void lwwire_proto_requestextension(void) { unsigned char buf[1]; - + int ext; + if (lwwire_read(buf, 1) < 0) return; - // NAK the request - buf[0] = 0x55; + ext = buf[0]; + buf[0] = 0x55; // default to NAK + if (lwwire_extension_list[ext].enable) + { + if ((*(lwwire_extension_list[ext].enable))() == 0) + { + // enable succeeded; enable it + buf[0] = 0x42; + lwwire_extension_list[ext].enabled = 1; + } + } lwwire_write(buf, 1); } void lwwire_proto_disableextension(void) { unsigned char buf[1]; + int ext; if (lwwire_read(buf, 1) < 0) return; - // ACK disabling any unsupported extensions - buf[0] = 0x42; + ext = buf[0]; + + buf[0] = 0x42; // default to ACK + if (lwwire_extension_list[ext].disable) + { + if ((*(lwwire_extension_list[ext].disable))() != 0) + { + // extension says it can't be disabled; NAK response + buf[0] = 0x55; + } + } + if (buf[0] == 0x42) + lwwire_extension_list[ext].enabled = 0; lwwire_write(buf, 1); } void lwwire_proto_extensionop(void) { - unsigned char buf[1]; - if (lwwire_read(buf, 1) < 0) + unsigned char buf[2]; + int ext; + int op; + + if (lwwire_read(buf, 2) < 0) return; - // we don't currently support any extensions so treat as unknown + ext = buf[0]; + op = buf[1]; + if (lwwire_extension_list[ext].enabled == 1) + { + if (lwwire_extension_list[ext].handler) + { + if ((*(lwwire_extension_list[ext].handler))(op) == 0) + return; + } + lwwire_protoerror(); + return; + } + // extension not enabled; do a protocol error lwwire_protoerror(); } @@ -675,4 +757,34 @@ */ void lwwire_reset(void) { + int i; + + // tell all extensions to reset and disable them + for (i = 0; i < 256; i++) + { + if (lwwire_extension_list[i].handler) + { + (*(lwwire_extension_list[i].reset))(); + } + lwwire_extension_list[i].enabled = 0; + } } + +/* +Register an extension. This will replace the registration if the same +extension number is registered twice. Returns -1 on parameter error. +ALL function arguments are required. num must be between 0 and 255 inclusive +currently. Returns 0 if the extension is registered. +*/ +int lwwire_register_extension(int num, int (*handler)(int), int (*enable)(void), int (*disable)(void), void (*reset)(void)) +{ + if (!handler || !enable || !disable || !reset) + return -1; + if (num < 0 || num > 255) + return -1; + lwwire_extension_list[num].handler = handler; + lwwire_extension_list[num].enable = enable; + lwwire_extension_list[num].disable = disable; + lwwire_extension_list[num].reset = reset; + return 0; +}