-include Makefile.inc
-VPATH=${top_srcdir}/src:${top_srcdir}/test
+VPATH=${top_srcdir}/src:${top_srcdir}/examples
DEBUG:=-g -O0 -Wall
-CFLAGS:= ${DEBUG} -I${top_srcdir}/interface -I${top_srcdir}/src -I.
+CFLAGS:= ${DEBUG} -I${top_srcdir}/interface
COMPILE:=libtool --mode=compile ${CC} ${CFLAGS}
LINK:=libtool --mode=link ${CC} -rpath ${stagedir}/lib ${LDFLAGS}
default all: compile
-compile: ${STATICLIB} ${LTLIB}
+compile: ${STATICLIB} ${LTLIB} example
${STATICLIB}: ${OBJS}
ar crv $@ ${OBJS}
check: example_test
-echo "No unit tests so far."
-example_test: srv_example client_example
+example: srv_example cnt_example
srv_example: srv_example.o
${LINK} -o $@ ${LTLIB} srv_example.o
-client_example: client.o
- ${LINK} -o $@ client.o
+cnt_example: cnt_example.o
+ ${LINK} -o $@ cnt_example.o
doc:
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#ifndef dprintf
+#define dprintf(x) { if (debug) printf x; fflush(stdout); }
+#endif
+
+#define DEF_MSG "Test message\n"
+#define DEF_PORT 9999
+
+static struct option opts[] = {
+ { "help", no_argument, NULL, 'h'},
+ { "debug", no_argument, NULL, 'd'},
+ { "msg", required_argument, NULL, 'm'},
+ { "port", required_argument, NULL, 'p'},
+};
+
+int debug = 0;
+int port = DEF_PORT;
+char *msg = NULL;
+
+static int writen(int fd, char *ptr, int nbytes);
+static int readln(int fd, char *out);
+
+static void usage(char *me)
+{
+ fprintf(stderr,
+ "usage: %s [option]\n"
+ " -h, --help print this screen\n"
+ " -d, --debug prints debug messages\n"
+ " -m, --msg <text> message to send\n"
+ " -p, --port <num> service port\n", me);
+}
+
+
+int main(int argc, char **argv)
+{
+ struct sockaddr_in addr;
+ char buff[512],
+ *me;
+ int opt,
+ sock,
+ n;
+
+
+ me = strrchr(argv[0], '/');
+ if ( me ) me++; else me = argv[0];
+ while ( (opt = getopt_long(argc, argv,"p:m:hd", opts, NULL)) != EOF )
+ {
+ switch ( opt )
+ {
+ case 'm':
+ msg = strdup(optarg);
+ break;
+ case 'p':
+ port = atoi(optarg);
+ break;
+ case 'd': debug = 1; break;
+ case 'h': usage(me); return 0;
+ case '?': usage(me); return 1;
+ }
+ }
+
+ bzero((char *) &addr, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+ addr.sin_port = htons(port);
+ if ( (sock = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
+ {
+ perror("socket");
+ exit(1);
+ }
+ if ( connect(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0 )
+ {
+ perror("connect");
+ exit(1);
+ }
+ n = strlen(msg? msg: DEF_MSG);
+ if ( writen(sock, msg? msg: DEF_MSG, n) != n )
+ {
+ dprintf(("error writing message\n"));
+ exit(1);
+ }
+ printf("reply: "); fflush(stdout);
+ n = readln(sock, buff);
+ if ( n < 0 )
+ {
+ perror("read() reply error");
+ return 1;
+ }
+ writen(0, buff, n);
+ close(sock);
+
+ return 0;
+}
+
+int writen(int fd, char *ptr, int nbytes)
+{
+ int nleft, nwritten;
+
+ nleft = nbytes;
+ dprintf(("start writing %d bytes\n", nbytes));
+ while ( nleft > 0 )
+ {
+ nwritten = write(fd, ptr, nleft);
+ dprintf(("written %d bytes", nwritten));
+ if ( nwritten <= 0 )
+ return (nwritten);
+
+ nleft -= nwritten;
+ ptr += nwritten;
+ dprintf((" (left %d bytes)\n", nleft));
+ }
+
+ dprintf(("written %d bytes (return: %d)\n", nwritten, nbytes - nleft));
+ return (nbytes - nleft);
+}
+
+#define BUFFER_SZ 512
+
+int readln(int fd, char *out)
+{
+ static char buffer[BUFFER_SZ];
+ static char *buffer_end = buffer;
+ int n;
+
+
+ dprintf(("reading line\n"));
+ while ( 1 ) {
+ if ( buffer_end - buffer ) {
+ /* buffer contains data
+ */
+ char *endl;
+
+ dprintf(("nonempty buffer\n"));
+ if ( (endl = memchr(buffer, '\n', buffer_end-buffer)) ) {
+ int linesz = endl-buffer+1;
+
+ dprintf(("using buffer data\n"));
+ memcpy(out, buffer, linesz);
+ if ( endl+1 != buffer_end )
+ memmove(buffer, endl+1, buffer_end-endl-1);
+ buffer_end -= linesz;
+ return linesz;
+ }
+ }
+ dprintf(("reading...\n"));
+ n = read(fd, buffer_end, BUFFER_SZ-(buffer_end-buffer));
+ if ( n < 0 ) {
+ if ( errno == EAGAIN ) continue;
+ dprintf(("reading error\n"));
+ return n;
+ }
+ else if ( n == 0 ) {
+ int ret = buffer_end-buffer;
+ dprintf(("end of reading - returning %d bytes\n", ret));
+ memcpy(out, buffer, ret);
+ buffer_end = buffer;
+ return ret;
+ }
+
+ dprintf(("read %d bytes\n", n));
+ buffer_end += n;
+ }
+
+ return 0;
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "srvbones.h"
+
+#ifndef dprintf
+#define dprintf(x) { if (debug) printf x; fflush(stdout); }
+#endif
+
+#define sizofa(a) (sizeof(a)/sizeof((a)[0]))
+
+int debug = 1;
+
+static int writen(int fd, char *ptr, int nbytes);
+static int readln(int fd, char *out, int nbytes);
+static int echo(int, struct timeval, void *);
+static int upper_echo(int, struct timeval, void *);
+
+#define ECHO_PORT 9999
+#define UPPER_ECHO_PORT 9998
+
+#define SRV_ECHO 0
+#define SRV_UPPER_ECHO 1
+
+static struct glite_srvbones_service service_table[] = {
+ { "Echo Service", -1, NULL, echo, NULL, NULL },
+ { "Upper Echo Service", -1, NULL, upper_echo, NULL, NULL }
+};
+
+int main(void)
+{
+ struct sockaddr_in myaddr;
+
+
+ if ( ((service_table[SRV_ECHO].conn = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+ || ((service_table[SRV_UPPER_ECHO].conn = socket(AF_INET, SOCK_STREAM, 0)) == -1) )
+ {
+ perror("socket");
+ exit(1);
+ }
+
+ bzero((char *) &myaddr, sizeof(myaddr));
+ myaddr.sin_family = AF_INET;
+ myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ myaddr.sin_port = htons(ECHO_PORT);
+ if ( bind(service_table[SRV_ECHO].conn, (struct sockaddr *)&myaddr, sizeof(myaddr)) == -1 )
+ {
+ perror("bind");
+ exit(1);
+ }
+ bzero((char *) &myaddr, sizeof(myaddr));
+ myaddr.sin_family = AF_INET;
+ myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ myaddr.sin_port = htons(UPPER_ECHO_PORT);
+ if ( bind(service_table[SRV_UPPER_ECHO].conn, (struct sockaddr *)&myaddr, sizeof(myaddr)) == -1 )
+ {
+ perror("bind");
+ exit(1);
+ }
+
+ if ( listen(service_table[SRV_ECHO].conn, 10)
+ || listen(service_table[SRV_UPPER_ECHO].conn, 10) )
+ {
+ perror("listen()");
+ exit(1);
+ }
+
+ glite_srvbones_run(NULL, service_table, sizofa(service_table), 1);
+
+
+ return 0;
+}
+
+int upper_echo(int fd, struct timeval client_start, void *data)
+{
+ int n, i;
+ char line[80];
+
+ n = readln(fd, line, 80);
+ if ( n < 0 )
+ {
+ perror("read() message");
+ return n;
+ }
+ else if ( n == 0 )
+ return 0;
+
+ for ( i = 0; i < n; i++ )
+ line[i] = toupper(line[i]);
+
+ if ( writen(fd, line, n) != n )
+ {
+ perror("write() message back");
+ return -1;
+ }
+
+ return 0;
+}
+
+int echo(int fd, struct timeval client_start, void *data)
+{
+ int n;
+ char line[80];
+
+ n = readln(fd, line, 80);
+ dprintf(("%d bytes read\n", n));
+ if ( n < 0 )
+ {
+ perror("read() message");
+ return n;
+ }
+ else if ( n == 0 )
+ return 0;
+
+ if ( writen(fd, line, n) != n )
+ {
+ perror("write() message back");
+ return -1;
+ }
+
+ return 0;
+}
+
+int writen(int fd, char *ptr, int nbytes)
+{
+ int nleft, nwritten;
+
+ nleft = nbytes;
+ dprintf(("start writing %d bytes\n", nbytes));
+ while ( nleft > 0 ) {
+ nwritten = write(fd, ptr, nleft);
+ dprintf(("written %d bytes", nwritten));
+ if ( nwritten <= 0 )
+ return (nwritten);
+
+ nleft -= nwritten;
+ ptr += nwritten;
+ dprintf((" (left %d bytes)\n", nleft));
+ }
+
+ dprintf(("written %d bytes (return: %d)\n", nwritten, nbytes - nleft));
+ return (nbytes - nleft);
+}
+
+#define BUFFER_SZ 512
+
+int readln(int fd, char *out, int nbytes)
+{
+ static char buffer[BUFFER_SZ];
+ static char *buffer_end = buffer;
+ int n;
+
+
+ dprintf(("reading line\n"));
+ while ( 1 ) {
+ if ( buffer_end - buffer ) {
+ /* buffer contains data
+ */
+ char *endl;
+
+ dprintf(("nonempty buffer\n"));
+ if ( (endl = memchr(buffer, '\n', buffer_end-buffer)) ) {
+ int linesz = endl-buffer+1;
+
+ memcpy(out, buffer, linesz);
+ if ( endl+1 != buffer_end ) memmove(buffer, endl+1, buffer_end-endl-1);
+ buffer_end -= linesz;
+ return linesz;
+ }
+ }
+
+ dprintf(("reding...\n"));
+ n = read(fd, buffer_end, BUFFER_SZ-(buffer_end-buffer));
+ if ( n < 0 ) {
+ if ( errno == EAGAIN ) n = 0;
+ else return n;
+ }
+ if ( n == 0 ) {
+ int ret = buffer_end-buffer;
+ dprintf(("end of reading - returning %d bytes\n", ret));
+ memcpy(out, buffer, ret);
+ buffer_end = buffer;
+ return ret;
+ }
+ dprintf(("read %d bytes\n", n));
+
+ buffer_end += n;
+ }
+
+ return 0;
+}
extern "C" {
#endif
+typedef enum _glite_srvbones_param_t {
+ GLITE_SBPARAM_SLAVES_CT, /* default number of slaves */
+ GLITE_SBPARAM_SLAVE_OVERLOAD, /* queue items per slave */
+ GLITE_SBPARAM_SLAVE_CONNS_MAX, /* commit suicide after that many */
+ /* connections */
+ GLITE_SBPARAM_CLNT_TIMEOUT, /* keep idle connection that many */
+ /* seconds */
+ GLITE_SBPARAM_TOTAL_CLNT_TIMEOUT, /* client may ask one slave multiple */
+ /* times but only limited time to */
+ /* avoid DoS attacks */
+} glite_srvbones_param_t;
+
typedef int (*slave_data_init_hnd)(void **);
struct glite_srvbones_service {
int (*on_disconnect_hnd)(int conn, void *clnt_data);
};
+extern int glite_srvbones_set_param(glite_srvbones_param_t param, ...);
/*
* slaves_ct - forked slaves count
* slave_data_init_hnd - callback initializing client data on every slave
*/
extern int glite_srvbones_run(
- int slaves_ct,
slave_data_init_hnd slave_data_init,
struct glite_srvbones_service *service_table,
size_t table_sz,
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <getopt.h>
-#include <linux/limits.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-#include <netinet/in.h>
-#include <signal.h>
#include <errno.h>
#include <netdb.h>
-#include <limits.h>
#include <assert.h>
#include <syslog.h>
#include <sys/time.h>
#include <time.h>
-#include <arpa/inet.h>
-#include <arpa/nameser.h>
-#include <resolv.h>
-#include <sys/ipc.h>
-#include <sys/sem.h>
+#include <stdarg.h>
#include "srvbones.h"
+#define SLAVES_CT 5 /* default number of slaves */
#define SLAVE_OVERLOAD 10 /* queue items per slave */
+#define SLAVE_CONNS_MAX 500 /* commit suicide after that many connections */
+#define SLAVE_CHECK_SIGNALS 2 /* how often to check signals while waiting for recv_mesg */
#define CLNT_TIMEOUT 10 /* keep idle connection that many seconds */
#define TOTAL_CLNT_TIMEOUT 60 /* one client may ask one slave multiple times */
/* but only limited time to avoid DoS attacks */
-#define CLNT_REJECT_TIMEOUT 100000 /* time limit for client rejection in !usec! */
-#define SLAVE_CONNS_MAX 500 /* commit suicide after that many connections */
-#define SLAVE_CHECK_SIGNALS 2 /* how often to check signals while waiting for recv_mesg */
-#define WATCH_TIMEOUT 1800 /* wake up to check updated credentials */
#ifndef dprintf
#define dprintf(x) { if (debug) printf x; }
#endif
-static int debug = 0;
+static int running = 0;
+static int debug = 0;
static volatile int die = 0,
child_died = 0;
static unsigned long clnt_dispatched = 0,
clnt_accepted = 0;
-static int slaves;
+
static struct glite_srvbones_service *services;
static int services_ct;
+static int set_slaves_ct = SLAVES_CT;
+static int set_slave_overload = SLAVE_OVERLOAD;
+static int set_slave_conns_max = SLAVE_CONNS_MAX;
+static struct timeval set_clnt_to = {CLNT_TIMEOUT, 0};
+static struct timeval set_total_clnt_to = {TOTAL_CLNT_TIMEOUT, 0};
+
+
static int dispatchit(int, int, int);
static int do_sendmsg(int, int, unsigned long, int);
static int do_recvmsg(int, int *, unsigned long *, int *);
static void catch_chld(int sig);
static int slave(int (*)(void **), int);
+static void glite_srvbones_set_slaves_ct(int);
+static void glite_srvbones_set_slave_overload(int);
+static void glite_srvbones_set_slave_conns_max(int);
+static void glite_srvbones_set_clnt_to(struct timeval *);
+static void glite_srvbones_set_total_clnt_to(struct timeval *);
+
+
+int glite_srvbones_set_param(glite_srvbones_param_t param, ...)
+{
+ va_list ap;
+ if ( running ) {
+ dprintf(("Attempting to set srv-bones parameter on running server"));
+ return -1;
+ }
+
+ va_start(ap, param);
+ switch ( param ) {
+ case GLITE_SBPARAM_SLAVES_CT:
+ glite_srvbones_set_slaves_ct(va_arg(ap,int)); break;
+ case GLITE_SBPARAM_SLAVE_OVERLOAD:
+ glite_srvbones_set_slave_overload(va_arg(ap,int)); break;
+ case GLITE_SBPARAM_SLAVE_CONNS_MAX:
+ glite_srvbones_set_slave_conns_max(va_arg(ap,int)); break;
+ case GLITE_SBPARAM_CLNT_TIMEOUT:
+ glite_srvbones_set_clnt_to(va_arg(ap,struct timeval *)); break;
+ case GLITE_SBPARAM_TOTAL_CLNT_TIMEOUT:
+ glite_srvbones_set_total_clnt_to(va_arg(ap,struct timeval *)); break;
+ }
+ va_end(ap);
+
+ return 0;
+}
int glite_srvbones_run(
- int slaves_ct,
slave_data_init_hnd slave_data_init,
struct glite_srvbones_service *service_table,
size_t table_sz,
assert(service_table);
- assert(slaves_ct > 0);
+ assert(table_sz > 0);
services = service_table;
- slaves = slaves_ct;
services_ct = table_sz;
debug = dbg;
sigaddset(&sset, SIGINT);
sigprocmask(SIG_BLOCK, &sset, NULL);
- for ( i = 0; i < slaves; i++ )
+ for ( i = 0; i < set_slaves_ct; i++ )
slave(slave_data_init, sock_slave[1]);
while ( !die )
{
fd_set fds;
int ret, mx;
- struct timeval watch_to = { WATCH_TIMEOUT, 0 };
FD_ZERO(&fds);
}
sigprocmask(SIG_UNBLOCK, &sset, NULL);
- ret = select(mx+1, &fds, NULL, NULL, &watch_to);
+ ret = select(mx+1, &fds, NULL, NULL, NULL);
sigprocmask(SIG_BLOCK, &sset, NULL);
if ( ret == -1 && errno != EINTR )
{
- if ( debug )
- perror("select()");
- else
- syslog(LOG_CRIT,"select(): %m");
+ if ( debug ) perror("select()");
+ else syslog(LOG_CRIT,"select(): %m");
return 1;
}
}
dprintf(("[master] Terminating on signal %d\n", die));
- if (!debug)
- syslog(LOG_INFO, "Terminating on signal %d\n", die);
+ if (!debug) syslog(LOG_INFO, "Terminating on signal %d\n", die);
kill(0, die);
return 0;
ret = 0;
if ( ( clnt_dispatched < clnt_accepted /* wraparound */
- || clnt_dispatched - clnt_accepted < slaves * SLAVE_OVERLOAD)
+ || clnt_dispatched - clnt_accepted < set_slaves_ct * set_slave_overload)
&& !(ret = do_sendmsg(sock_slave, conn, clnt_dispatched++, sidx)) )
{
/* all done
*/
exit(1);
- while ( !die && (conn_cnt < SLAVE_CONNS_MAX || conn >= 0) )
+ while ( !die && (conn_cnt < set_slave_conns_max || conn >= 0) )
{
fd_set fds;
int max = sock,
kick_client = 0;
unsigned long seq;
struct timeval check_to = { SLAVE_CHECK_SIGNALS, 0},
- total_to = { TOTAL_CLNT_TIMEOUT, 0},
- client_to = { CLNT_TIMEOUT,0 },
+ total_to = set_total_clnt_to,
+ client_to = set_clnt_to,
now;
continue;
}
- if ( FD_ISSET(sock, &fds) && conn_cnt < SLAVE_CONNS_MAX )
+ if ( FD_ISSET(sock, &fds) && conn_cnt < set_slave_conns_max )
{
if ( conn >= 0 ) usleep(100000 + 1000 * (random() % 200));
if ( do_recvmsg(sock, &newconn, &seq, &newsrv) ) switch ( errno )
if ( kick_client && conn >= 0 )
{
- /*
- * XXX: neco jako on_disconnect_hnd
- *
- if ( ctx->connPool[ctx->connToUse].gss.context != GSS_C_NO_CONTEXT)
- {
- struct timeval to = { 0, CLNT_REJECT_TIMEOUT };
- edg_wll_gss_close(&ctx->connPool[ctx->connToUse].gss,&to);
- }
- edg_wll_FreeContext(ctx);
- */
if ( services[srv].on_disconnect_hnd )
services[srv].on_disconnect_hnd(conn, clnt_data);
close(conn);
return 0;
}
+
+static void glite_srvbones_set_slaves_ct(int n)
+{
+ set_slaves_ct = (n == -1)? SLAVES_CT: n;
+}
+
+static void glite_srvbones_set_slave_overload(int n)
+{
+ set_slave_overload = (n == -1)? SLAVE_OVERLOAD: n;
+}
+
+static void glite_srvbones_set_slave_conns_max(int n)
+{
+ set_slave_conns_max = (n == -1)? SLAVE_CONNS_MAX: n;
+}
+
+static void glite_srvbones_set_clnt_to(struct timeval *t)
+{
+ set_clnt_to = t? (struct timeval){CLNT_TIMEOUT, 0}: *t;
+}
+
+static void glite_srvbones_set_total_clnt_to(struct timeval *t)
+{
+ set_total_clnt_to = t? (struct timeval){TOTAL_CLNT_TIMEOUT, 0}: *t;
+}