FreeCalypso > hg > freecalypso-sw
changeset 177:fef035264dd4
rvinterf: beginning of local socket handling
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Sat, 23 Nov 2013 20:15:02 +0000 |
parents | 7f727aaf5cd4 |
children | 7ab6b29e76bb |
files | rvinterf/lowlevel/Makefile rvinterf/lowlevel/client.h rvinterf/lowlevel/localsock.c rvinterf/lowlevel/rvifmain.c |
diffstat | 4 files changed, 169 insertions(+), 5 deletions(-) [+] |
line wrap: on
line diff
--- a/rvinterf/lowlevel/Makefile Sat Nov 23 07:40:13 2013 +0000 +++ b/rvinterf/lowlevel/Makefile Sat Nov 23 20:15:02 2013 +0000 @@ -5,8 +5,8 @@ RVTDUMP_OBJS= format.o format_g23.o openport.o output.o packetrx.o rvtdump.o -RVINTERF_OBJS= format.o format_g23.o logsent.o openport.o output.o packetrx.o \ - packettx.o rvifmain.o +RVINTERF_OBJS= format.o format_g23.o localsock.o logsent.o openport.o output.o\ + packetrx.o packettx.o rvifmain.o all: ${PROGS}
--- a/rvinterf/lowlevel/client.h Sat Nov 23 07:40:13 2013 +0000 +++ b/rvinterf/lowlevel/client.h Sat Nov 23 20:15:02 2013 +0000 @@ -9,7 +9,6 @@ struct client { struct client *next; - struct client **backptr; int fd; int rx_state; u_char rx_buf[LOCALSOCK_MAX_MSG];
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/lowlevel/localsock.c Sat Nov 23 20:15:02 2013 +0000 @@ -0,0 +1,141 @@ +/* + * This rvinterf module handles the local UNIX domain socket interface + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <unistd.h> +#include "../localsock.h" +#include "client.h" + +static char sockpath[] = "/tmp/rvinterf_socket"; + +int listener; + +extern struct client *client_head; +extern int max_fd; + +create_listener_socket() +{ + /* local socket binding voodoo copied from osmocon */ + struct sockaddr_un local; + unsigned int namelen; + int rc; + + listener = socket(AF_UNIX, SOCK_STREAM, 0); + if (listener < 0) { + perror("socket(AF_UNIX, SOCK_STREAM, 0)"); + exit(1); + } + + local.sun_family = AF_UNIX; + strncpy(local.sun_path, sockpath, sizeof(local.sun_path)); + local.sun_path[sizeof(local.sun_path) - 1] = '\0'; + unlink(local.sun_path); + + /* we use the same magic that X11 uses in Xtranssock.c for + * calculating the proper length of the sockaddr */ +#if defined(BSD44SOCKETS) || defined(__UNIXWARE__) + local.sun_len = strlen(local.sun_path); +#endif +#if defined(BSD44SOCKETS) || defined(SUN_LEN) + namelen = SUN_LEN(&local); +#else + namelen = strlen(local.sun_path) + + offsetof(struct sockaddr_un, sun_path) + 1; +#endif + + rc = bind(listener, (struct sockaddr *) &local, namelen); + if (rc != 0) { + perror("bind on local socket"); + exit(1); + } + rc = listen(listener, 3); + if (rc != 0) { + perror("listen"); + exit(1); + } + + if (listener > max_fd) + max_fd = listener; + return(0); +} + +static void +prep_for_length_rx(cli) + struct client *cli; +{ + cli->rx_state = 0; + cli->rx_ptr = cli->rx_buf; + cli->rx_left = 2; +} + +static void +prep_for_message_rx(cli) + struct client *cli; +{ + cli->rx_state = 1; + cli->rx_ptr = cli->rx_buf; + cli->rx_left = cli->rx_msglen; +} + +handle_listener_select() +{ + struct sockaddr_un un_addr; + socklen_t len; + int rc; + struct client *newcli; + + len = sizeof(un_addr); + rc = accept(listener, (struct sockaddr *) &un_addr, &len); + if (rc < 0) { + perror("rvinterf: accept"); + exit(1); + } + newcli = malloc(sizeof(struct client)); + if (!newcli) { + perror("rvinterf: malloc for new client"); + exit(1); + } + bzero(newcli, sizeof(struct client)); + newcli->fd = rc; + newcli->next = client_head; + client_head = newcli; + prep_for_length_rx(newcli); + return(0); +} + +void +handle_client_select(cli) + struct client *cli; +{ + int cc; + + cc = read(cli->fd, cli->rx_ptr, cli->rx_left); + if (cc <= 0) { + /* normal client exit condition */ +close_socket: cli->rx_state = 2; + return; + } + cli->rx_ptr += cc; + cli->rx_left -= cc; + if (cli->rx_left) + return; + /* got the thing, process it */ + if (cli->rx_state) { + prep_for_length_rx(cli); + /* process_msg_from_client(cli); */ + } else { + cli->rx_msglen = *(u_short *)cli->rx_buf; + if (cli->rx_msglen < 1 || cli->rx_msglen > LOCALSOCK_MAX_MSG) { + /* TODO: report invalid length to the client */ + goto close_socket; + } + prep_for_message_rx(cli); + } +}
--- a/rvinterf/lowlevel/rvifmain.c Sat Nov 23 07:40:13 2013 +0000 +++ b/rvinterf/lowlevel/rvifmain.c Sat Nov 23 20:15:02 2013 +0000 @@ -9,17 +9,22 @@ #include <unistd.h> #include <time.h> #include "../pktmux.h" +#include "../localsock.h" +#include "client.h" -extern int target_fd; +extern int target_fd, listener; extern char *baudrate_name; extern u_char rxpkt[]; extern size_t rxpkt_len; +struct client *client_head; + char *logfname; FILE *logF; time_t logtime; int background; +int max_fd; main(argc, argv) char **argv; @@ -28,6 +33,7 @@ extern int optind; int c; fd_set fds; + struct client *cli, **clip; while ((c = getopt(argc, argv, "bB:d:l:")) != EOF) switch (c) { @@ -54,6 +60,7 @@ goto usage; open_target_serial(argv[optind]); } + max_fd = target_fd; set_serial_nonblock(0); setlinebuf(stdout); @@ -66,6 +73,7 @@ fprintf(logF, "*** Log of rvinterf session ***\n"); setlinebuf(logF); } + create_listener_socket(); if (background) { c = fork(); if (c < 0) { @@ -80,7 +88,18 @@ for (;;) { FD_ZERO(&fds); FD_SET(target_fd, &fds); - c = select(target_fd+1, &fds, 0, 0, 0); + FD_SET(listener, &fds); + for (clip = &client_head; cli = *clip; ) { + if (cli->rx_state == 2) { + close(cli->fd); + *clip = cli->next; + free(cli); + continue; + } + FD_SET(cli->fd, &fds); + clip = &cli->next; + } + c = select(max_fd+1, &fds, 0, 0, 0); time(&logtime); if (c < 0) { if (errno == EINTR) @@ -90,6 +109,11 @@ } if (FD_ISSET(target_fd, &fds)) process_serial_rx(); + if (FD_ISSET(listener, &fds)) + handle_listener_select(); + for (cli = client_head; cli; cli = cli->next) + if (FD_ISSET(cli->fd, &fds)) + handle_client_select(cli); } }