FreeCalypso > hg > freecalypso-sw
diff rvinterf/lowlevel/localsock.c @ 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 | rvinterf/old/rvtdump_tx.c@f42854da4563 |
children | 7ab6b29e76bb |
line wrap: on
line diff
--- /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); + } +}