diff --git a/examples/.gitignore b/examples/.gitignore index 4d41f76..f47d81c 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -1,2 +1,3 @@ filelistc filelistd +streamfld diff --git a/examples/Makefile.am b/examples/Makefile.am index ae718f3..486c413 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -13,7 +13,7 @@ AM_CFLAGS = -Wall -g # where to find libsxmp libsxmp = ../lib/.libs/libsxmp.la -bin_PROGRAMS = filelistd filelistc +bin_PROGRAMS = filelistd filelistc streamfld filelistd_SOURCES = helpers.c filelistd.c filelistd_LDADD = $(LIBTDATA_LIBS) $(LIBSEXPR_LIBS) $(OPENSSL_LIBS) \ @@ -23,3 +23,6 @@ filelistc_SOURCES = filelistc.c filelistc_LDADD = $(LIBTDATA_LIBS) $(LIBSEXPR_LIBS) $(OPENSSL_LIBS) \ $(LIBUUID_LIBS) $(libsxmp) -lpthread +streamfld_SOURCES = helpers.c streamfld.c +streamfld_LDADD = $(LIBTDATA_LIBS) $(LIBSEXPR_LIBS) $(OPENSSL_LIBS) \ + $(LIBUUID_LIBS) $(libsxmp) -lpthread diff --git a/examples/streamfld.c b/examples/streamfld.c new file mode 100644 index 0000000..a5d41d6 --- /dev/null +++ b/examples/streamfld.c @@ -0,0 +1,285 @@ +/* + * Secure X Message Passing Library v2 examples. + * + * (c) Originally written by somebody else ... + * (c) Alexander Vdolainen 2013-2015 + * + * libsxmp is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libsxmp 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see ."; + * + */ + +/* + * This is an example of sxmp usage. + * NOTE: It was developed quite fast within one day, + * btw - this the reason of some ugly code here. + * + * This is a master or simply - daemon part, it will + * listen a requests and create a stream with directory entries, + * which ridden by the client. + * Using the builtin stream functionality added since 0.4.2 version. + * + * This implements a simple client-server topology, to see + * more advanced technics check out other examples. + * + * NOTE(win32): don't have a time to test it or fix it to + * make it works on windows, if you can - u're welcome. + */ + +#include +#include +#define __USE_GNU +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "filelist.h" +#include "helpers.h" +#include "../config.h" + +#define FULL_PROGRAM_NAME "File lister master (builtin streams based)" + +/* firstly we need to take an rpc calls data, + * sxmp uses usrtc from libtdata to store it + */ +static usrtc_t *fulist; + +/* ok, here we will define out sxmp specific functions */ + +/* + * RPC list contain groups of RPC calls called channel types + * for each sxmp link depends on access rules you can change + * available channel types. + * To do so you must provide a special callback returning this list. + * Since we haven't any access restrictions in our example, just + * create a fake. + */ +static usrtc_t *__rettlist(sxlink_t *l) +{ + return fulist; +} + +/* + * Each sxmp link validated by certificate ID, + * i.e. when basic checking is done, you can also + * review the certificate ID, for example you need + * to disable certificate for a time being. + * + * Here we don't have those checks, just always accept + */ +static int __validate_sslpem(sxlink_t *l) +{ + return 0; +} + +/* + * To be more paranoic, sxmp also allow to + * check up username and password. + * We don't overview this tuff here, just + * always allow. + */ +static int __secure_check(sxlink_t *l) +{ + return SXE_SUCCESS; +} + +/* misc functions */ +static int __ping(void *m, sexp_t *sx) +{ + return sxmsg_return((sxmsg_t*)m, SXE_SUCCESS); +} + +/* command line options helpers */ +static void __help_print(FILE *fso, const char *fmtname) +{ + fprintf(fso, "\n%s\n\n", FULL_PROGRAM_NAME); + + /* usage options */ + fprintf(fso, "Usage:\n"); + fprintf(fso, "\t%s -r | --root-x509 -u | --master-x509 " + " [-p | --listen-port ]\n", fmtname); + + /* defaults */ + fprintf(fso, "\t%s -h | --help\n", fmtname); + fprintf(fso, "\t%s -v | --version\n", fmtname); + + /* options description */ + fprintf(fso, "\nOptions:\n"); + fprintf(fso, "\t%-33s Set pathname of the remote root X.509 public certificate.\n", + "-r | --root-x509 "); + fprintf(fso, "\t%-33s Set pathname of the host X.509 public and private certificate.\n", + "-m | --master-x509 "); + fprintf(fso, "\t%-33s Remote host listening port number [default: %d].\n", + "-p | --listen-port ", DEFAULT_PORT); + fprintf(fso, "\t%-33s Show help screen.\n", "-h | --help"); + fprintf(fso, "\t%-33s Print version information.\n", "-v | --version"); + return; +} + +static void __version_print(FILE *fso) +{ + fprintf(fso, "\nFile list example master daemon (builtin streams).\n"); + fprintf(fso, "Examples bundle for %s %s.\n", PACKAGE_NAME, PACKAGE_VERSION); + return; +} + +int main(int argc, char **argv) +{ + char *rootca = NULL, *cert = NULL; + sxhub_t *sxmphub = sxhub_create(); + int port = DEFAULT_PORT; + int opt; + + while(1) { + int option_index = 0; + static struct option long_options[] = { + /* These options a generic ones. */ + {"help", no_argument, NULL, 'h'}, /* print out help and version info */ + {"version", no_argument, NULL, 'v'}, /* just out a version info */ + /* The following options about settings . */ + {"root-x509", required_argument, NULL, 'r'}, + {"master-x509", required_argument, NULL, 'm'}, + {"listen-port", required_argument, NULL, 'p'}, + { NULL, 0, NULL, 0 }, + }; + + if((opt = getopt_long(argc, argv, "hvr:m:", long_options, + &option_index)) == -1) break; + + switch(opt) { + case 'h': + __help_print(stdout, argv[0]); + return 0; + break; + case 'v': + __version_print(stdout); + return 0; + break; + case 'r': + if(!(rootca = strdup(optarg))) return ENOMEM; + break; + case 'm': + if(!(cert = strdup(optarg))) return ENOMEM; + break; + case 'p': + port = atoi(optarg); + break; + } + } + + if(!rootca) { + fprintf(stderr, "Root CA not pointed.\n Failure.\n"); + __help_print(stderr, argv[0]); + return EINVAL; + } + + if(!cert) { + fprintf(stderr, "User certificate not pointed.\n Failure.\n"); + __help_print(stderr, argv[0]); + return EINVAL; + } + + sxmp_init(); + + /* all is fine let's init connection subsystem */ + if(!sxmphub) { + fprintf(stderr, "Subsystem init failed: %d\n", opt); + return 2; + } + /* set working certificates */ + opt = sxhub_setsslserts(sxmphub, rootca, cert, cert); + if(opt) { + fprintf(stderr, "Subsystem init failed (set SSL x.509 pems): %d\n", opt); + return opt; + } + + /* clean up */ + free(rootca); + free(cert); + + /* set important callbacks to do the security checking */ + sxhub_set_authcheck(sxmphub, __secure_check); + sxhub_set_sslvalidate(sxmphub, __validate_sslpem); + + /* ok, now we need to construct RPC lists (channels) */ + if(!(fulist = malloc(sizeof(usrtc_t)))) { + fprintf(stderr, "Cannot allocate memory for RPC lists\n Failure.\n"); + return ENOMEM; + } + opt = sxmp_rpclist_init(fulist); + if(opt) { + fprintf(stderr, "Failed to init rpc list\n Failure.\n"); + return opt; + } + + /* we will add one channel with type id READONLY_CHANNEL for read only operations */ + opt = sxmp_rpclist_add(fulist, READONLY_CHANNEL, "Read only operations", NULL); + if(opt) { + fprintf(stderr, "Failed to add typed RPC channel\n Failure.\n"); + return opt; + } + + /* ok, let's add stream functions */ + opt = sxmp_rpclist_add_function(fulist, READONLY_CHANNEL, "ping", __ping); + if(opt) { + __fail: + fprintf(stderr, "Failed to add functions to typed RPC channel\n Failure.\n"); + return opt; + } + + /* ok, setup it */ + sxhub_set_rpcvalidator(sxmphub, __rettlist); + + signal(SIGPIPE, SIG_IGN); + + /* now we're ready to run the listen process */ + int srv = openlistener_socket(port); + + while(1) { + struct sockaddr_in addr; + socklen_t len = sizeof(addr); + sxlink_t *link; + + int client = accept(srv, (struct sockaddr*)&addr, &len); /* accept connection as usual */ + + link = sxlink_master_accept(sxmphub, client, NULL); + + if(!link) fprintf(stderr, "Cannot create sxmp link (%d)\n", errno); + } + + sxhub_destroy(sxmphub); + + sxmp_finalize(); + + return 0; +}