FreeCalypso > hg > freecalypso-tools
diff rvinterf/lowlevel/localsock.c @ 0:e7502631a0f9
initial import from freecalypso-sw rev 1033:5ab737ac3ad7
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 11 Jun 2016 00:13:35 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rvinterf/lowlevel/localsock.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,180 @@ +/* + * 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 "../include/localsock.h" +#include "client.h" + +int listener; + +extern struct client *client_head; +extern int max_fd; +extern char *socket_pathname; +extern int socketpair_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, socket_pathname, 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); + } + if (rc > max_fd) + max_fd = rc; + 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); + output_line("*** Client program connected"); + return(0); +} + +create_socketpair_client() +{ + struct client *cli; + + if (socketpair_fd > max_fd) + max_fd = socketpair_fd; + cli = malloc(sizeof(struct client)); + if (!cli) { + perror("rvinterf: malloc for socketpair client"); + exit(1); + } + bzero(cli, sizeof(struct client)); + cli->fd = socketpair_fd; + client_head = cli; + prep_for_length_rx(cli); + return(0); +} + +send_local_msg_to_client(cli, msg) + struct client *cli; + char *msg; +{ + int len, len1; + u_char hdr[3]; + + len = strlen(msg); + len1 = len + 1; + hdr[0] = len1 >> 8; + hdr[1] = len1 & 0xFF; + hdr[2] = RVI2CLI_LOCAL_CMD_RESP; + write(cli->fd, hdr, 3); + write(cli->fd, msg, len); +} + +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 */ + output_line("*** Client program disconnected"); +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 = cli->rx_buf[0] << 8 | cli->rx_buf[1]; + if (cli->rx_msglen < 1 || cli->rx_msglen > LOCALSOCK_MAX_MSG) { + send_local_msg_to_client(cli, + "-Invalid length, closing socket"); + goto close_socket; + } + prep_for_message_rx(cli); + } +}