From a73916e85aaf51b697248f1fd1692211126d1a5a Mon Sep 17 00:00:00 2001 From: Andrew Bettison Date: Mon, 23 Apr 2012 17:12:10 +0930 Subject: [PATCH 1/2] Implement JNI command-line interface (untested) - argv is (const char *const *) everywhere, to avoid having to strdup() all the Java arg strings - changed (char*) to (const char*) in lots of places to fix cascading compiler warnings as a result of argv constness - fixed a bug in "config get" command when used without 'variable' arg --- commandline.c | 252 ++++++++++++++++++++++++++++++++++++++------- dna.c | 10 +- keyring.c | 14 +-- rhizome.h | 2 +- rhizome_database.c | 2 +- serval.h | 28 ++--- vomp.c | 10 +- 7 files changed, 245 insertions(+), 73 deletions(-) diff --git a/commandline.c b/commandline.c index 21622b86..b025437e 100644 --- a/commandline.c +++ b/commandline.c @@ -35,7 +35,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. static int servalNodeRunning(int *pid) { - char *instancepath = serval_instancepath(); + const char *instancepath = serval_instancepath(); struct stat st; int r=stat(instancepath,&st); if (r) { @@ -90,6 +90,61 @@ int cli_usage() { return -1; } +/* Data structures for accumulating output of a single JNI call. +*/ + +struct outv_field { + struct outv_field *next; + size_t length; +}; + +#define OUTV_CHUNK_MIN_SIZE (8192) + +int in_jni_call = 0; + +struct outv_field *outv = NULL; +size_t outc = 0; + +struct outv_field **outv_fieldp = NULL; +struct outv_field *outv_field = NULL; +char *outv_current = NULL; +char *outv_limit = NULL; + +static void outv_end_field() +{ + outv_field->length = outv_current - (char*)outv_field - sizeof(struct outv_field); + outv_fieldp = &outv_field->next; + outv_field = NULL; +} + +static int outv_create_field(size_t needed) +{ + if (outv_field == NULL) { + size_t bufsiz = (needed > OUTV_CHUNK_MIN_SIZE) ? needed : OUTV_CHUNK_MIN_SIZE; + size_t size = sizeof(struct outv_field) + bufsiz; + struct outv_field *field = (struct outv_field *) malloc(size); + if (field == NULL) + return WHYF("Out of memory allocating %lu bytes", (unsigned long) size); + *outv_fieldp = outv_field = field; + ++outc; + field->next = NULL; + field->length = 0; + outv_current = (char *)field + sizeof(struct outv_field); + outv_limit = outv_current + bufsiz; + } + return 0; +} + +static int outv_growbuf(size_t needed) +{ + size_t bufsiz = (needed > OUTV_CHUNK_MIN_SIZE) ? needed : OUTV_CHUNK_MIN_SIZE; + size_t size = (outv_current - (char*)outv_field) + bufsiz; + struct outv_chunk* chunk = (struct outv_chunk *) malloc(size); + if (chunk == NULL) + return WHYF("Out of memory allocating %lu bytes", (unsigned long) size); + outv_limit = outv_current + bufsiz; + return 0; +} #ifdef HAVE_JNI_H @@ -101,35 +156,69 @@ JNIEXPORT jobject JNICALL Java_org_servalproject_servald_ServalD_command(JNIEnv jclass resultClass = NULL; jclass stringClass = NULL; jmethodID resultConstructorId = NULL; - jobjectArray outv = NULL; - jint status = 42; + jobjectArray outArray = NULL; + // Enforce non re-entrancy. + if (in_jni_call) { + jclass exceptionClass = NULL; + if ((exceptionClass = (*env)->FindClass(env, "org/servalproject/servald/ServalDReentranceException")) == NULL) + return NULL; // exception + (*env)->ThrowNew(env, exceptionClass, "re-entrancy not supported"); + return NULL; + } if ((resultClass = (*env)->FindClass(env, "org/servalproject/servald/ServalDResult")) == NULL) return NULL; // exception if ((resultConstructorId = (*env)->GetMethodID(env, resultClass, "", "(I[Ljava/lang/String;)V")) == NULL) return NULL; // exception if ((stringClass = (*env)->FindClass(env, "java/lang/String")) == NULL) return NULL; // exception - // Eventually we will return the output buffer, but for now just echo the args. + // Construct argv, argc from method arguments. jsize len = (*env)->GetArrayLength(env, args); - if ((outv = (*env)->NewObjectArray(env, len, stringClass, NULL)) == NULL) - return NULL; // out of memory exception + const char **argv = malloc(sizeof(char*) * (len + 1)); + if (argv == NULL) { + jclass exceptionClass = NULL; + if ((exceptionClass = (*env)->FindClass(env, "java/lang/OutOfMemoryError")) == NULL) + return NULL; // exception + (*env)->ThrowNew(env, exceptionClass, "malloc returned NULL"); + return NULL; + } jsize i; for (i = 0; i != len; ++i) { const jstring arg = (jstring)(*env)->GetObjectArrayElement(env, args, i); const char *str = (*env)->GetStringUTFChars(env, arg, NULL); if (str == NULL) return NULL; // out of memory exception - (*env)->SetObjectArrayElement(env, outv, i, (*env)->NewStringUTF(env, str)); - (*env)->ReleaseStringUTFChars(env, arg, str); + argv[i] = str; } - return (*env)->NewObject(env, resultClass, resultConstructorId, status, outv); + argv[len] = NULL; + int argc = len; + // Set up the output buffer. + outv = NULL; + outc = 0; + outv_field = NULL; + outv_fieldp = &outv; + // Execute the command. + in_jni_call = 1; + jint status = parseCommandLine(argc, argv); + in_jni_call = 0; + free(argv); + // Unpack the output. + outv_end_field(); + if ((outArray = (*env)->NewObjectArray(env, outc, stringClass, NULL)) == NULL) + return NULL; // out of memory exception + for (i = 0; i != outc; ++i) { + const jstring str = (jstring)(*env)->NewString(env, (jchar*)((char*)&outv[i] + sizeof(struct outv_field)), outv[i].length); + if (str == NULL) + return NULL; // out of memory exception + (*env)->SetObjectArrayElement(env, outArray, i, str); + } + return (*env)->NewObject(env, resultClass, resultConstructorId, status, outArray); } #endif /* HAVE_JNI_H */ /* args[] excludes command name (unless hardlinks are used to use first words of command sequences as alternate names of the command. */ -int parseCommandLine(int argc, char **args) +int parseCommandLine(int argc, const char *const *args) { int i; int ambiguous=0; @@ -188,10 +277,10 @@ int parseCommandLine(int argc, char **args) /* Otherwise, make call */ setVerbosity(confValueGet("debug","")); - return command_line_options[cli_call].function(argc,args, &command_line_options[cli_call]); + return command_line_options[cli_call].function(argc, args, &command_line_options[cli_call]); } -int cli_arg(int argc, char **argv, command_line_option *o, char *argname, char **dst, int (*validator)(const char *arg), char *defaultvalue) +int cli_arg(int argc, const char *const *argv, command_line_option *o, char *argname, const char **dst, int (*validator)(const char *arg), char *defaultvalue) { int arglen = strlen(argname); int i; @@ -204,7 +293,7 @@ int cli_arg(int argc, char **argv, command_line_option *o, char *argname, char * &&( (wordlen == arglen + 2 && word[0] == '<' && !strncasecmp(&word[1], argname, arglen)) || (wordlen == arglen + 4 && word[0] == '[' && !strncasecmp(&word[2], argname, arglen))) ) { - char *value = argv[i]; + const char *value = argv[i]; if (validator && !(*validator)(value)) { fprintf(stderr, "Invalid argument %d '%s': \"%s\"\n", i, argname, value); return -1; @@ -221,17 +310,100 @@ int cli_arg(int argc, char **argv, command_line_option *o, char *argname, char * return 1; } +/* Write a single character to output. If in a JNI call, then this appends the character to the + current output field. Returns the character written cast to an unsigned char then to int, or EOF + on error. + */ +int cli_putchar(char c) +{ + if (in_jni_call) { + if (outv_create_field(1) == -1) + return EOF; + if (outv_current == outv_limit && outv_growbuf(1) == -1) + return EOF; + *outv_current++ = c; + return (unsigned char) c; + } + else + return putchar(c); +} + +/* Write a null-terminated string to output. If in a JNI call, then this appends the string to the + current output field. The terminating null is not included. Returns a non-negative integer on + success, EOF on error. + */ +int cli_puts(const char *str) +{ + if (in_jni_call) { + size_t len = strlen(str); + if (outv_create_field(1) == -1) + return EOF; + size_t avail = outv_limit - outv_current; + if (avail < len) { + strncpy(outv_current, str, avail); + outv_current = outv_limit; + if (outv_growbuf(len) == -1) + return EOF; + len -= avail; + str += avail; + } + strncpy(outv_current, str, len); + outv_current += len; + return 0; + } + else + return fputs(str, stdout); +} + +/* Write a formatted string to output. If in a JNI call, then this appends the string to the + current output field, excluding the terminating null. Returns the number of bytes + written/appended, or -1 on error. + */ int cli_printf(const char *fmt, ...) { + int ret = 0; va_list ap,ap2; va_start(ap,fmt); va_copy(ap2,ap); - //vsnprintf(msg,8192,fmt,ap2); + if (in_jni_call) { + if (outv_create_field(0) == -1) + return -1; + size_t avail = outv_limit - outv_current; + int count = vsnprintf(outv_current, avail, fmt, ap2); + if (count >= avail) { + if (outv_growbuf(count) == -1) + return -1; + vsprintf(outv_current, fmt, ap2); + } + outv_current += count; + ret = count; + } else + ret = vfprintf(stdout, fmt, ap2); va_end(ap); + return ret; +} + +/* Delimit the current output field. This closes the current field, so that the next cli_ output + function will start appending to a new field. Returns 0 on success, -1 on error. If not in a + JNI call, then this simply writes a newline to standard output (or the value of the + SERVALD_OUTPUT_DELIMITER env var if set). + */ +int cli_delim() +{ + if (in_jni_call) { + if (outv_create_field(0) == -1) + return -1; + outv_end_field(); + } else { + const char *delim = getenv("SERVALD_OUTPUT_DELIMITER"); + if (delim == NULL) + delim = "\n"; + fputs(delim, stdout); + } return 0; } -int app_dna_lookup(int argc,char **argv,struct command_line_option *o) +int app_dna_lookup(int argc, const char *const *argv, struct command_line_option *o) { /* Create the instance directory if it does not yet exist */ if (create_serval_instance_dir() == -1) @@ -284,7 +456,7 @@ int cli_absolute_path(const char *arg) return arg[0] == '/' && arg[1] != '\0'; } -int app_server_start(int argc,char **argv,struct command_line_option *o) +int app_server_start(int argc, const char *const *argv, struct command_line_option *o) { /* Process optional arguments */ int foregroundP= (argc >= 3 && !strcasecmp(argv[2], "foreground")); @@ -324,7 +496,7 @@ int app_server_start(int argc,char **argv,struct command_line_option *o) return server(NULL,foregroundP); } -int app_server_stop(int argc,char **argv,struct command_line_option *o) +int app_server_stop(int argc, const char *const *argv, struct command_line_option *o) { if (cli_arg(argc, argv, o, "instance path", &thisinstancepath, cli_absolute_path, NULL) == -1) return -1; @@ -389,7 +561,7 @@ int app_server_stop(int argc,char **argv,struct command_line_option *o) return WHY("Not implemented"); } -int app_server_status(int argc,char **argv,struct command_line_option *o) +int app_server_status(int argc, const char *const *argv, struct command_line_option *o) { if (cli_arg(argc, argv, o, "instance path", &thisinstancepath, cli_absolute_path, NULL) == -1) return -1; @@ -422,9 +594,9 @@ int app_server_status(int argc,char **argv,struct command_line_option *o) return 0; } -int app_mdp_ping(int argc,char **argv,struct command_line_option *o) +int app_mdp_ping(int argc, const char *const *argv, struct command_line_option *o) { - char *sid; + const char *sid; if (cli_arg(argc, argv, o, "SID|broadcast", &sid, validateSid, "broadcast") == -1) return -1; @@ -638,9 +810,9 @@ int cli_configvarname(const char *arg) return 1; } -int app_config_set(int argc,char **argv,struct command_line_option *o) +int app_config_set(int argc, const char *const *argv, struct command_line_option *o) { - char *var, *val; + const char *var, *val; if ( cli_arg(argc, argv, o, "variable", &var, cli_configvarname, NULL) || cli_arg(argc, argv, o, "value", &val, NULL, "")) return -1; @@ -649,9 +821,9 @@ int app_config_set(int argc,char **argv,struct command_line_option *o) return set_variable(var, val); } -int app_config_del(int argc,char **argv,struct command_line_option *o) +int app_config_del(int argc, const char *const *argv, struct command_line_option *o) { - char *var; + const char *var; if (cli_arg(argc, argv, o, "variable", &var, cli_configvarname, NULL)) return -1; if (create_serval_instance_dir() == -1) @@ -659,10 +831,10 @@ int app_config_del(int argc,char **argv,struct command_line_option *o) return set_variable(var, NULL); } -int app_config_get(int argc,char **argv,struct command_line_option *o) +int app_config_get(int argc, const char *const *argv, struct command_line_option *o) { - char *var; - if (cli_arg(argc, argv, o, "variable", &var, cli_configvarname, NULL)) + const char *var; + if (cli_arg(argc, argv, o, "variable", &var, cli_configvarname, NULL) == -1) return -1; if (create_serval_instance_dir() == -1) return -1; @@ -675,7 +847,7 @@ int app_config_get(int argc,char **argv,struct command_line_option *o) } /* Read lines of config file. */ char line[1024]; - int varlen=strlen(var); + int varlen = var ? strlen(var) : 0; line[0]=0; fgets(line,1024,in); while(line[0]) { if (varlen == 0) { @@ -692,9 +864,9 @@ int app_config_get(int argc,char **argv,struct command_line_option *o) return 0; } -int app_rhizome_add_file(int argc, char **argv, struct command_line_option *o) +int app_rhizome_add_file(int argc, const char *const *argv, struct command_line_option *o) { - char *filepath, *manifestpath; + const char *filepath, *manifestpath; cli_arg(argc, argv, o, "filepath", &filepath, NULL, ""); cli_arg(argc, argv, o, "manifestpath", &manifestpath, NULL, ""); /* Ensure the Rhizome database exists and is open */ @@ -758,9 +930,9 @@ int cli_uint(const char *arg) return s != arg && *s == '\0'; } -int app_rhizome_list(int argc, char **argv, struct command_line_option *o) +int app_rhizome_list(int argc, const char *const *argv, struct command_line_option *o) { - char *offset, *limit; + const char *offset, *limit; cli_arg(argc, argv, o, "offset", &offset, cli_uint, "0"); cli_arg(argc, argv, o, "limit", &limit, cli_uint, "0"); /* Create the instance directory if it does not yet exist */ @@ -771,18 +943,18 @@ int app_rhizome_list(int argc, char **argv, struct command_line_option *o) return rhizome_list_manifests(atoi(offset), atoi(limit)); } -int app_keyring_create(int argc, char **argv, struct command_line_option *o) +int app_keyring_create(int argc, const char *const *argv, struct command_line_option *o) { - char *pin; + const char *pin; cli_arg(argc, argv, o, "pin,pin ...", &pin, NULL, ""); keyring_file *k=keyring_open_with_pins(pin); if (!k) fprintf(stderr,"keyring create:Failed to create/open keyring file\n"); return 0; } -int app_keyring_list(int argc, char **argv, struct command_line_option *o) +int app_keyring_list(int argc, const char *const *argv, struct command_line_option *o) { - char *pin; + const char *pin; cli_arg(argc, argv, o, "pin,pin ...", &pin, NULL, ""); keyring_file *k=keyring_open_with_pins(pin); @@ -812,9 +984,9 @@ int app_keyring_list(int argc, char **argv, struct command_line_option *o) return 0; } -int app_keyring_add(int argc, char **argv, struct command_line_option *o) +int app_keyring_add(int argc, const char *const *argv, struct command_line_option *o) { - char *pin; + const char *pin; cli_arg(argc, argv, o, "pin", &pin, NULL, ""); keyring_file *k=keyring_open_with_pins(""); @@ -834,9 +1006,9 @@ int app_keyring_add(int argc, char **argv, struct command_line_option *o) return 0; } -int app_keyring_set_did(int argc, char **argv, struct command_line_option *o) +int app_keyring_set_did(int argc, const char *const *argv, struct command_line_option *o) { - char *sid, *did, *pin; + const char *sid, *did, *pin; cli_arg(argc, argv, o, "sid", &sid, NULL, ""); cli_arg(argc, argv, o, "did", &did, NULL, ""); cli_arg(argc, argv, o, "pin", &pin, NULL, ""); diff --git a/dna.c b/dna.c index 29310b77..f91d989e 100644 --- a/dna.c +++ b/dna.c @@ -246,11 +246,11 @@ int exec_argc=0; int servalShutdown=0; -char *thisinstancepath=NULL; -char *serval_instancepath() +const char *thisinstancepath=NULL; +const char *serval_instancepath() { if (thisinstancepath) return thisinstancepath; - char *instancepath=getenv("SERVALINSTANCE_PATH"); + const char *instancepath=getenv("SERVALINSTANCE_PATH"); if (!instancepath) instancepath=DEFAULT_INSTANCE_PATH; return instancepath; } @@ -507,7 +507,7 @@ int setVerbosity(char *optarg) { return 0; } -int main(int argc,char **argv) +int main(int argc, char **argv) { int c; char *pin=NULL; @@ -548,7 +548,7 @@ int main(int argc,char **argv) parser. */ /* Don't include name of program in arguments */ - int return_value=parseCommandLine(argc-1,&argv[1]); + int return_value = parseCommandLine(argc - 1, (const char*const*)&argv[1]); #if defined WIN32 WSACleanup(); diff --git a/keyring.c b/keyring.c index 610b91d7..d08bac6a 100644 --- a/keyring.c +++ b/keyring.c @@ -332,7 +332,7 @@ int keyring_enter_identitypin(keyring_file *k,char *pin) */ int keyring_munge_block(unsigned char *block,int len /* includes the first 96 bytes */, unsigned char *KeyRingSalt,int KeyRingSaltLen, - char *KeyRingPin,char *PKRPin) + const char *KeyRingPin, const char *PKRPin) { int exit_code=1; unsigned char hashKey[crypto_hash_sha512_BYTES]; @@ -509,7 +509,7 @@ int keyring_pack_identity(keyring_context *c,keyring_identity *i, return exit_code; } -keyring_identity *keyring_unpack_identity(unsigned char *slot,char *pin) +keyring_identity *keyring_unpack_identity(unsigned char *slot, const char *pin) { /* Skip salt and MAC */ int i; @@ -651,7 +651,7 @@ int keyring_identity_mac(keyring_context *c,keyring_identity *id, unpack the details of the identity. */ int keyring_decrypt_pkr(keyring_file *k,keyring_context *c, - char *pin,int slot_number) + const char *pin,int slot_number) { int exit_code=1; unsigned char slot[KEYRING_PAGE_SIZE]; @@ -711,7 +711,7 @@ int keyring_decrypt_pkr(keyring_file *k,keyring_context *c, /* Try all valid slots with the PIN and see if we find any identities with that PIN. We might find more than one. */ -int keyring_enter_pin(keyring_file *k,char *pin) +int keyring_enter_pin(keyring_file *k, const char *pin) { if (!k) return -1; if (!pin) pin=""; @@ -1293,7 +1293,7 @@ int keyring_find_sid(keyring_file *k,int *cn,int *in,int *kp,unsigned char *sid) } -int keyring_enter_pins(keyring_file *k,char *pinlist) +int keyring_enter_pins(keyring_file *k, const char *pinlist) { char pin[1024]; int i,j=0; @@ -1311,13 +1311,13 @@ int keyring_enter_pins(keyring_file *k,char *pinlist) return 0; } -keyring_file *keyring_open_with_pins(char *pinlist) +keyring_file *keyring_open_with_pins(const char *pinlist) { keyring_file *k=NULL; if (create_serval_instance_dir() == -1) return NULL; - char *instancePath = serval_instancepath(); + const char *instancePath = serval_instancepath(); char keyringFile[1024]; snprintf(keyringFile,1024,"%s/serval.keyring",instancePath); if ((k=keyring_open(keyringFile))==NULL) diff --git a/rhizome.h b/rhizome.h index b2006a5c..73fd5f8b 100644 --- a/rhizome.h +++ b/rhizome.h @@ -154,7 +154,7 @@ typedef struct rhizome_manifest { } rhizome_manifest; extern long long rhizome_space; -extern char *rhizome_datastore_path; +extern const char *rhizome_datastore_path; extern sqlite3 *rhizome_db; diff --git a/rhizome_database.c b/rhizome_database.c index a5055c7c..f1dabf45 100644 --- a/rhizome_database.c +++ b/rhizome_database.c @@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include long long rhizome_space=0; -char *rhizome_datastore_path=NULL; +const char *rhizome_datastore_path = NULL; sqlite3 *rhizome_db=NULL; diff --git a/serval.h b/serval.h index bedddb4c..863868b3 100644 --- a/serval.h +++ b/serval.h @@ -145,7 +145,7 @@ extern int returnMultiVars; extern char *gatewayspec; -extern char *rhizome_datastore_path; +extern const char *rhizome_datastore_path; extern struct in_addr client_addr; extern int client_port; @@ -238,9 +238,9 @@ extern keyring_file *keyring; /* Public calls to keyring management */ keyring_file *keyring_open(char *file); -keyring_file *keyring_open_with_pins(char *pinlist); -int keyring_enter_pin(keyring_file *k,char *pin); -int keyring_enter_pins(keyring_file *k,char *pinlist); +keyring_file *keyring_open_with_pins(const char *pinlist); +int keyring_enter_pin(keyring_file *k, const char *pin); +int keyring_enter_pins(keyring_file *k, const char *pinlist); int keyring_set_did(keyring_identity *id,char *did); int keyring_sanitise_position(keyring_file *k,int *cn,int *in,int *kp); int keyring_next_identity(keyring_file *k,int *cn,int *in,int *kp); @@ -1054,7 +1054,7 @@ typedef struct dna_identity_status { int uniqueDidAndName; } dna_identity_status; -int parseCommandLine(int argc,char *argv[]); +int parseCommandLine(int argc, const char *const *argv); dna_identity_status *dnacache_lookup(char *did,char *name,char *sid); dna_identity_status *dnacache_lookup_next(); @@ -1072,8 +1072,8 @@ int _memabuseCheck(const char *func,const char *file,const int line); #define memabuseCheck() /* */ #endif -char *thisinstancepath; -char *serval_instancepath(); +const char *thisinstancepath; +const char *serval_instancepath(); int form_serval_instance_path(char * buf, size_t bufsiz, const char *path); int create_serval_instance_dir(); @@ -1304,7 +1304,7 @@ int vomp_tick(); int vomp_tick_interval(); typedef struct command_line_option { - int (*function)(int argc,char **argv,struct command_line_option *o); + int (*function)(int argc, const char *const *argv, struct command_line_option *o); char *words[32]; // 32 words should be plenty! unsigned long long flags; #define CLIFLAG_NONOVERLAY (1<<0) /* Uses a legacy IPv4 DNA call instead of overlay mnetwork */ @@ -1313,12 +1313,12 @@ typedef struct command_line_option { } command_line_option; extern command_line_option command_line_options[]; -int cli_arg(int argc, char **argv, command_line_option *o, char *argname, char **dst, int (*validator)(const char *arg), char *defaultvalue); +int cli_arg(int argc, const char *const *argv, command_line_option *o, char *argname, const char **dst, int (*validator)(const char *arg), char *defaultvalue); int overlay_mdp_getmyaddr(int index,unsigned char *sid); -int app_vomp_status(int argc, char **argv, struct command_line_option *o); -int app_vomp_dial(int argc, char **argv, struct command_line_option *o); -int app_vomp_pickup(int argc, char **argv, struct command_line_option *o); -int app_vomp_hangup(int argc, char **argv, struct command_line_option *o); -int app_vomp_monitor(int argc, char **argv, struct command_line_option *o); +int app_vomp_status(int argc, const char *const *argv, struct command_line_option *o); +int app_vomp_dial(int argc, const char *const *argv, struct command_line_option *o); +int app_vomp_pickup(int argc, const char *const *argv, struct command_line_option *o); +int app_vomp_hangup(int argc, const char *const *argv, struct command_line_option *o); +int app_vomp_monitor(int argc, const char *const *argv, struct command_line_option *o); diff --git a/vomp.c b/vomp.c index 042ef88d..c7e3e9e9 100644 --- a/vomp.c +++ b/vomp.c @@ -952,7 +952,7 @@ char *vomp_describe_codec(int c) return "unknown"; } -int app_vomp_status(int argc, char **argv, struct command_line_option *o) +int app_vomp_status(int argc, const char *const *argv, struct command_line_option *o) { overlay_mdp_frame mdp; bzero(&mdp,sizeof(mdp)); @@ -1021,7 +1021,7 @@ int app_vomp_status(int argc, char **argv, struct command_line_option *o) return overlay_mdp_client_done(); } -int app_vomp_dial(int argc, char **argv, struct command_line_option *o) +int app_vomp_dial(int argc, const char *const *argv, struct command_line_option *o) { char *sid,*did,*callerid; cli_arg(argc, argv, o, "sid", &sid, NULL, ""); @@ -1053,7 +1053,7 @@ int app_vomp_dial(int argc, char **argv, struct command_line_option *o) } -int app_vomp_pickup(int argc, char **argv, struct command_line_option *o) +int app_vomp_pickup(int argc, const char *const *argv, struct command_line_option *o) { char *call_token; cli_arg(argc, argv, o, "call", &call_token, NULL, ""); @@ -1078,7 +1078,7 @@ int app_vomp_pickup(int argc, char **argv, struct command_line_option *o) return overlay_mdp_client_done(); } -int app_vomp_hangup(int argc, char **argv, struct command_line_option *o) +int app_vomp_hangup(int argc, const char *const *argv, struct command_line_option *o) { char *call_token; cli_arg(argc, argv, o, "call", &call_token, NULL, ""); @@ -1103,7 +1103,7 @@ int app_vomp_hangup(int argc, char **argv, struct command_line_option *o) return overlay_mdp_client_done(); } -int app_vomp_monitor(int argc, char **argv, struct command_line_option *o) +int app_vomp_monitor(int argc, const char *const *argv, struct command_line_option *o) { overlay_mdp_frame mdp; bzero(&mdp,sizeof(mdp)); From 1494172da6a5a426c5665c8cb9134f9286e8e008 Mon Sep 17 00:00:00 2001 From: Andrew Bettison Date: Mon, 23 Apr 2012 18:25:26 +0930 Subject: [PATCH 2/2] Trival test of dna JNI command line entry point --- .gitignore | 49 +++++++++++++++++++++++---------------------- aclocal.m4 | 10 +++++++-- commandline.c | 26 ++++++++++++++++++++---- configure.in | 20 +++++++++++------- m4/ax_prog_javac.m4 | 10 +++++++-- testconfig.sh.in | 4 ++++ testdefs.sh | 1 + tests/dna_jni | 45 +++++++++++++++++++++++++++++++++++++++++ vomp.c | 6 +++--- 9 files changed, 129 insertions(+), 42 deletions(-) create mode 100644 testconfig.sh.in create mode 100755 tests/dna_jni diff --git a/.gitignore b/.gitignore index 7a487eed..82a08e27 100644 --- a/.gitignore +++ b/.gitignore @@ -1,27 +1,28 @@ -*~ -/win32/Debug -/win32/Release -*.user -*.ncb -*.o -*.suo -.*.sw? -configure -autom4te.cache -Makefile -config.log -config.status -config.guess -config.sub -install-sh -ltmain.sh -nacl/nacl-20110221/build -nacl/naclinc.txt -nacl/nacllib.txt -serval.c -dna -*.so -test.*.log +*~ +/win32/Debug +/win32/Release +*.user +*.ncb +*.o +*.suo +.*.sw? +configure +autom4te.cache +Makefile +testconfig.sh +config.log +config.status +config.guess +config.sub +install-sh +ltmain.sh +nacl/nacl-20110221/build +nacl/naclinc.txt +nacl/nacllib.txt +serval.c +dna +*.so +test.*.log config.guess config.sub install-sh diff --git a/aclocal.m4 b/aclocal.m4 index d83526f5..1575c9af 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -192,8 +192,14 @@ if test "x$JAVAPREFIX" = x; then else test "x$JAVAC" = x && AC_CHECK_PROGS(JAVAC, "gcj -C" guavac jikes javac, $JAVAPREFIX) fi -test "x$JAVAC" = x && AC_MSG_ERROR([no acceptable Java compiler found in \$PATH]) -AX_PROG_JAVAC_WORKS +if test "x$JAVAC" = x; then + AC_MSG_ERROR([no acceptable Java compiler found in \$PATH]) +else + AX_PROG_JAVAC_WORKS + if test "x$ac_cv_prog_javac_works" != xyes; then + JAVAC= + fi +fi AC_PROVIDE([$0])dnl ]) # =========================================================================== diff --git a/commandline.c b/commandline.c index b025437e..637978a5 100644 --- a/commandline.c +++ b/commandline.c @@ -231,9 +231,13 @@ int parseCommandLine(int argc, const char *const *args) int mandatory = 0; for (j = 0; (word = command_line_options[i].words[j]); ++j) { int wordlen = strlen(word); - if (!( (wordlen > 2 && word[0] == '<' && word[wordlen-1] == '>') - || (wordlen > 4 && word[0] == '[' && word[1] == '<' && word[wordlen-2] == '>' && word[wordlen-1] == ']') - || (wordlen > 0) + if (optional < 0) { + fprintf(stderr,"Internal error: command_line_options[%d].word[%d]=\"%s\" not allowed after \"...\"\n", i, j, word); + break; + } + else if (!( (wordlen > 2 && word[0] == '<' && word[wordlen-1] == '>') + || (wordlen > 4 && word[0] == '[' && word[1] == '<' && word[wordlen-2] == '>' && word[wordlen-1] == ']') + || (wordlen > 0) )) { fprintf(stderr,"Internal error: command_line_options[%d].word[%d]=\"%s\" is malformed\n", i, j, word); break; @@ -245,13 +249,15 @@ int parseCommandLine(int argc, const char *const *args) } } else if (word[0] == '[') { ++optional; + } else if (wordlen == 3 && word[0] == '.' && word[1] == '.' && word[2] == '.') { + optional = -1; } else { ++mandatory; if (j < argc && strcasecmp(word, args[j])) // literal words don't match break; } } - if (!word && argc >= mandatory && argc <= mandatory + optional) { + if (!word && argc >= mandatory && (optional < 0 || argc <= mandatory + optional)) { /* A match! We got through the command definition with no internal errors and all literal args matched and we have a proper number of args. If we have multiple matches, then note that the call is ambiguous. */ @@ -403,6 +409,16 @@ int cli_delim() return 0; } +int app_echo(int argc, const char *const *argv, struct command_line_option *o) +{ + int i; + for (i = 1; i < argc; ++i) { + cli_puts(argv[i]); + cli_delim(); + } + return 0; +} + int app_dna_lookup(int argc, const char *const *argv, struct command_line_option *o) { /* Create the instance directory if it does not yet exist */ @@ -1048,6 +1064,8 @@ command_line_option command_line_options[]={ "Lookup the SIP/MDP address of the supplied telephone number (DID)."}, {cli_usage,{"help",NULL},0, "Display command usage."}, + {app_echo,{"echo","...",NULL},CLIFLAG_STANDALONE, + "Lookup the SIP/MDP address of the supplied telephone number (DID)."}, {app_server_start,{"node","start",NULL},CLIFLAG_STANDALONE, "Start Serval Mesh node process with instance path taken from SERVALINSTANCE_PATH environment variable."}, {app_server_start,{"node","start","in","",NULL},CLIFLAG_STANDALONE, diff --git a/configure.in b/configure.in index 8f264043..3dcd0096 100644 --- a/configure.in +++ b/configure.in @@ -11,14 +11,17 @@ dnl Check for a working Java compiler, keep going if unsuccessful. pushdef([AC_MSG_ERROR], defn([AC_MSG_WARN])) AC_PROG_JAVAC popdef([AC_MSG_ERROR]) +AC_SUBST([JAVAC]) dnl Check for JNI includes, keep going if not present. -pushdef([AC_MSG_ERROR], defn([AC_MSG_WARN])) -AC_JNI_INCLUDE_DIR -for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS; do - CPPFLAGS="$CPPFLAGS -I$JNI_INCLUDE_DIR" -done -popdef([AC_MSG_ERROR]) +if test -n "$JAVAC"; then + pushdef([AC_MSG_ERROR], defn([AC_MSG_WARN])) + AC_JNI_INCLUDE_DIR + for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS; do + CPPFLAGS="$CPPFLAGS -I$JNI_INCLUDE_DIR" + done + popdef([AC_MSG_ERROR]) +fi AC_CHECK_LIB(c,srandomdev) @@ -40,4 +43,7 @@ AC_CHECK_LIB(dl,dlopen,[LDFLAGS="$LDFLAGS -ldl"]) AC_CHECK_LIB(pthread,pthread_create,[LDFLAGS="$LDFLAGS -lpthread"]) AC_CHECK_LIB(portaudio,Pa_Terminate,[LDFLAGS="$LDFLAGS -lportaudio"; CFLAGS="$CFLAGS -DWITH_PORTAUDIO"]) -AC_OUTPUT(Makefile) +AC_OUTPUT([ + Makefile + testconfig.sh +]) diff --git a/m4/ax_prog_javac.m4 b/m4/ax_prog_javac.m4 index d9bcc2d7..fe73f194 100644 --- a/m4/ax_prog_javac.m4 +++ b/m4/ax_prog_javac.m4 @@ -73,7 +73,13 @@ if test "x$JAVAPREFIX" = x; then else test "x$JAVAC" = x && AC_CHECK_PROGS(JAVAC, "gcj -C" guavac jikes javac, $JAVAPREFIX) fi -test "x$JAVAC" = x && AC_MSG_ERROR([no acceptable Java compiler found in \$PATH]) -AX_PROG_JAVAC_WORKS +if test "x$JAVAC" = x; then + AC_MSG_ERROR([no acceptable Java compiler found in \$PATH]) +else + AX_PROG_JAVAC_WORKS + if test "x$ac_cv_prog_javac_works" != xyes; then + JAVAC= + fi +fi AC_PROVIDE([$0])dnl ]) diff --git a/testconfig.sh.in b/testconfig.sh.in new file mode 100644 index 00000000..29e5917a --- /dev/null +++ b/testconfig.sh.in @@ -0,0 +1,4 @@ +#!/bin/bash +# This file is sourced by some of the test scripts in ./tests. +# It defines some settings that were established by ./configure. +JAVAC="@JAVAC@" diff --git a/testdefs.sh b/testdefs.sh index 33325a46..14722310 100644 --- a/testdefs.sh +++ b/testdefs.sh @@ -1,6 +1,7 @@ # Common definitions for all test suites in test/* this=$(abspath "${BASH_SOURCE[0]}") +here="${this%/*}" # Utility function for setting up a fixture with a DNA server process: # - Ensure that no dna processes are running diff --git a/tests/dna_jni b/tests/dna_jni new file mode 100755 index 00000000..55905b26 --- /dev/null +++ b/tests/dna_jni @@ -0,0 +1,45 @@ +#!/bin/bash + +# Tests for Serval DNA JNI entry points. +# +# Copyright 2012 Paul Gardner-Stephen +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +source "${0%/*}/../testframework.sh" +source "${0%/*}/../testdefs.sh" +source "${0%/*}/../testconfig.sh" + +setup() { + setup_dna + compile_java_classes +} + +compile_java_classes() { + local batphone_source=$(abspath "$here/../..") + assert [ "$JAVAC" ] + mkdir classes + assert $JAVAC -d classes "$batphone_source"/src/org/servalproject/servald/*.java + assert [ -r classes/org/servalproject/servald/ServalD.class ] +} + +doc_Echo="Serval echo command works via JNI" +test_Echo() { + execute $dna echo "Hello," "world!" + assertStdoutIs -e 'Hello,\nworld!\n' +} + +runTests "$@" + diff --git a/vomp.c b/vomp.c index c7e3e9e9..e8f026b5 100644 --- a/vomp.c +++ b/vomp.c @@ -1023,7 +1023,7 @@ int app_vomp_status(int argc, const char *const *argv, struct command_line_optio int app_vomp_dial(int argc, const char *const *argv, struct command_line_option *o) { - char *sid,*did,*callerid; + const char *sid,*did,*callerid; cli_arg(argc, argv, o, "sid", &sid, NULL, ""); cli_arg(argc, argv, o, "did", &did, NULL, ""); cli_arg(argc, argv, o, "callerid", &callerid, NULL, NULL); @@ -1055,7 +1055,7 @@ int app_vomp_dial(int argc, const char *const *argv, struct command_line_option int app_vomp_pickup(int argc, const char *const *argv, struct command_line_option *o) { - char *call_token; + const char *call_token; cli_arg(argc, argv, o, "call", &call_token, NULL, ""); overlay_mdp_frame mdp; @@ -1080,7 +1080,7 @@ int app_vomp_pickup(int argc, const char *const *argv, struct command_line_optio int app_vomp_hangup(int argc, const char *const *argv, struct command_line_option *o) { - char *call_token; + const char *call_token; cli_arg(argc, argv, o, "call", &call_token, NULL, ""); overlay_mdp_frame mdp;