Skip to content

Commit

Permalink
Attempt to straighten up joold's argv
Browse files Browse the repository at this point in the history
For #410.

Ugh. Ran out of time, and I still have some issues with it.
Also, it's missing documentation.

Will keep grinding next weekend.
  • Loading branch information
ydahhrk committed Jul 8, 2024
1 parent da26110 commit 566e0d0
Show file tree
Hide file tree
Showing 10 changed files with 546 additions and 379 deletions.
1 change: 1 addition & 0 deletions src/usr/joold/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
bin_PROGRAMS = joold
joold_SOURCES = \
joold.c \
json.c json.h \
log.c log.h \
modsocket.c modsocket.h \
netsocket.c netsocket.h \
Expand Down
226 changes: 179 additions & 47 deletions src/usr/joold/joold.c
Original file line number Diff line number Diff line change
@@ -1,78 +1,210 @@
#include <errno.h>
#include <pthread.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>

#include "log.h"
#include "common/types.h"
#include "common/xlat.h"
#include "usr/joold/modsocket.h"
#include "usr/joold/netsocket.h"
#include "usr/joold/statsocket.h"

static void cancel_thread(pthread_t thread)
static const struct option OPTIONS[] = {
{
.name = "version",
.has_arg = no_argument,
.val = 'V',
}, {
.name = "help",
.has_arg = no_argument,
.val = 'h',
},

/* Files */

{
.name = "modsocket",
.has_arg = required_argument,
.val = 'm',
}, {
.name = "netsocket",
.has_arg = required_argument,
.val = 'n',
}, {
.name = "statsocket",
.has_arg = required_argument,
.val = 's',
},

/* Modsocket */

{
.name = "instance",
.has_arg = required_argument,
.val = 'i',
},

/* Netsocket */

{
.name = "--net.multicast.addr",
.has_arg = required_argument,
.val = 1100,
}, {
.name = "--net.multicast.port",
.has_arg = required_argument,
.val = 1101,
}, {
.name = "--net.interface.in",
.has_arg = required_argument,
.val = 1102,
}, {
.name = "--net.interface.out",
.has_arg = required_argument,
.val = 1103,
}, {
.name = "--net.ttl",
.has_arg = required_argument,
.val = 1104,
},

/* Statsocket */

{
.name = "stats.address",
.has_arg = required_argument,
.val = 1200,
}, {
.name = "stats.port",
.has_arg = required_argument,
.val = 1201,
},
{ 0 },
};

static void print_help(void)
{
int error;
printf("-V, --version Print program version number\n");
printf("-h, --help Print this\n\n");

printf("-m, --modsocket=FILE Path to file containing kernel socket config\n");
printf("-n, --netsocket=FILE Path to file containing network socket config\n");
printf("-s, --statsocket=FILE Path to file containing stats socket config\n\n");

error = pthread_cancel(thread);
if (!error)
pthread_join(thread, NULL);
/*
* else:
* Well, `man 3 pthread_cancel` just `exit(EXIT_FAILURE)`s when
* `pthread_cancel()` fails.
* Let's instead be good citizens by closing the sockets anyway.
*/
printf("-i, --instance=STRING Kernelspace Jool instance name\n");
printf(" (Default: \"default\")\n\n");

printf("--net.multicast.addr=ADDR Address where the sessions will be advertised\n");
printf("--net.multicast.port=STR UDP port where the sessions will be advertised\n");
printf("--net.interface.in=STR IPv4: IP_ADD_MEMBERSHIP; IPv6: IPV6_ADD_MEMBERSHIP\n");
printf(" (see ip(7))\n");
printf("--net.interface.out=STR IPv4: IP_MULTICAST_IF, IPv6: IPV6_MULTICAST_IF\n");
printf(" (see ip(7))\n");
printf("--net.ttl=INT Multicast datagram Time To Live\n\n");

printf("--stats.address=ADDR Address to bind the stats socket to\n");
printf("--stats.port=INT Port to bind the stats socket to\n");
}

int main(int argc, char **argv)
{
pthread_t mod2net_thread;
pthread_t net2mod_thread;
char const *OPTS = "Vhm:n:s:i:";
int opt;
unsigned long ul;
int error;

printf("Remember that joold is intended as a daemon, so it outputs straight to syslog.\n");
printf("(Syslog normally sends messages to /var/log/syslog by default.)\n");
modcfg.iname = "default";
netcfg.ttl = 1;

while ((opt = getopt_long(argc, argv, OPTS, OPTIONS, NULL)) != -1) {
switch (opt) {
case 'V':
printf(JOOL_VERSION_STR "\n");
return 0;
case 'h':
print_help();
return 0;

case 'm':
error = modsocket_config(optarg);
if (error)
return error;
break;
case 'n':
error = netsocket_config(optarg);
if (error)
return error;
break;
case 's':
error = statsocket_config(optarg);
if (error)
return error;
break;

case 'i':
modcfg.iname = optarg;
break;

case 1100:
netcfg.enabled = true;
netcfg.mcast_addr = optarg;
break;
case 1101:
netcfg.enabled = true;
netcfg.mcast_port = optarg;
break;

case 1102:
netcfg.enabled = true;
netcfg.in_interface = optarg;
break;
case 1103:
netcfg.enabled = true;
netcfg.out_interface = optarg;
break;
case 1104:
netcfg.enabled = true;
errno = 0;
ul = strtoul(optarg, NULL, 10);
if (ul > 255 || errno) {
syslog(LOG_ERR, "ttl out of range: %s\n", optarg);
return 1;
}
netcfg.ttl = ul;
break;

case 1200:
statcfg.enabled = true;
statcfg.address = optarg;
break;
case 1201:
statcfg.enabled = true;
statcfg.port = optarg;
break;
}
}

printf("joold is intended as a daemon, so it outputs straight to syslog.\n");
printf("The standard streams will mostly shut up from now on.\n");
printf("---------------------------------------------\n");

openlog("joold", 0, LOG_DAEMON);

error = netsocket_setup(argc, argv);
error = modsocket_setup();
if (error)
goto end;
error = modsocket_setup(argc, argv);
if (error) {
netsocket_teardown();
error = netsocket_start();
if (error)
goto end;
}
error = statsocket_start(argc, argv);
error = statsocket_start();
if (error)
goto clean;

error = pthread_create(&mod2net_thread, NULL, modsocket_listen, NULL);
if (error) {
pr_perror("Module-to-network thread initialization", error);
goto clean;
}
error = pthread_create(&net2mod_thread, NULL, netsocket_listen, NULL);
if (error) {
pr_perror("Network-to-module thread initialization", error);
cancel_thread(mod2net_thread);
goto clean;
}

pthread_join(net2mod_thread, NULL);
pthread_join(mod2net_thread, NULL);
/* Fall through. */
goto end;

clean:
modsocket_teardown();
netsocket_teardown();
/* Fall through. */
modsocket_listen(NULL); /* Loops forever */

end:
closelog();
if (error)
fprintf(stderr, "joold error: %d\n", error);
end: closelog();
fprintf(stderr, "joold error: %d\n", error);
return error;
}
66 changes: 66 additions & 0 deletions src/usr/joold/json.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include "usr/joold/json.h"

#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syslog.h>

#include "usr/joold/log.h"
#include "usr/util/file.h"

int read_json(char const *filename, cJSON **out)
{
char *file;
cJSON *json;
struct jool_result result;

syslog(LOG_INFO, "Opening file %s...", filename);
result = file_to_string(filename, &file);
if (result.error)
return pr_result(&result);

json = cJSON_Parse(file);
if (!json) {
syslog(LOG_ERR, "JSON syntax error.");
syslog(LOG_ERR, "The JSON parser got confused around about here:");
syslog(LOG_ERR, "%s", cJSON_GetErrorPtr());
free(file);
return 1;
}

free(file);
*out = json;
return 0;
}

int json2str(cJSON *json, char const *key, char **dst)
{
char *tmp;

json = cJSON_GetObjectItem(json, key);
if (!json)
return 0;

tmp = strdup(json->valuestring);
if (tmp)
return ENOMEM;

*dst = tmp;
return 0;
}

int json2int(cJSON *json, char const *key, int *dst)
{
json = cJSON_GetObjectItem(json, key);
if (!json)
return 0;

if (!(json->numflags & VALUENUM_INT)) {
syslog(LOG_ERR, "%s '%s' is not a valid integer.", key,
json->valuestring);
return EINVAL;
}

*dst = json->valueint;
return 0;
}
11 changes: 11 additions & 0 deletions src/usr/joold/json.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifndef SRC_USR_JOOLD_JSON_H_
#define SRC_USR_JOOLD_JSON_H_

#include "usr/util/cJSON.h"

int read_json(char const *, cJSON **);

int json2str(cJSON *, char const *, char **);
int json2int(cJSON *, char const *, int *);

#endif /* SRC_USR_JOOLD_JSON_H_ */
Loading

0 comments on commit 566e0d0

Please sign in to comment.