FreeCalypso > hg > freecalypso-tools
view rvinterf/lowlevel/localsock.c @ 21:10e0f8fdc37c
top README: lcdemu hack dropped
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 22 Oct 2016 05:31:14 +0000 |
parents | e7502631a0f9 |
children |
line wrap: on
line source
/* * 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); } }