114 lines
3.1 KiB
C
114 lines
3.1 KiB
C
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <netdb.h>
|
|
#include <osmocom/core/socket.h>
|
|
#include <osmocom/core/select.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <talloc.h>
|
|
#include <unistd.h>
|
|
#include "osmo_mcast_sock.h"
|
|
|
|
/* server socket is what we use for transmission. It is not subscribed
|
|
* to a multicast group or locally bound, but it is just a normal UDP
|
|
* socket that's connected to the remote mcast group + port */
|
|
int mcast_server_sock_setup(struct osmo_fd *ofd, const char* tx_mcast_group,
|
|
uint16_t tx_mcast_port, bool loopback)
|
|
{
|
|
int rc;
|
|
unsigned int flags = OSMO_SOCK_F_CONNECT | OSMO_SOCK_F_UDP_REUSEADDR;
|
|
|
|
if (!loopback)
|
|
flags |= OSMO_SOCK_F_NO_MCAST_LOOP;
|
|
|
|
/* setup mcast server socket */
|
|
rc = osmo_sock_init_ofd(ofd, AF_INET, SOCK_DGRAM, IPPROTO_UDP,
|
|
tx_mcast_group, tx_mcast_port, flags);
|
|
if (rc < 0) {
|
|
perror("Failed to create Multicast Server Socket");
|
|
return rc;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* the client socket is what we use for reception. It is a UDP socket
|
|
* that's bound to the GSMTAP UDP port and subscribed to the respective
|
|
* multicast group */
|
|
int mcast_client_sock_setup(struct osmo_fd *ofd, const char *mcast_group, uint16_t mcast_port,
|
|
int (*fd_rx_cb)(struct osmo_fd *ofd, unsigned int what),
|
|
void *osmo_fd_data)
|
|
{
|
|
int rc;
|
|
unsigned int flags = OSMO_SOCK_F_BIND | OSMO_SOCK_F_NO_MCAST_ALL | OSMO_SOCK_F_UDP_REUSEADDR;
|
|
|
|
ofd->cb = fd_rx_cb;
|
|
ofd->when = BSC_FD_READ;
|
|
ofd->data = osmo_fd_data;
|
|
|
|
/* Create mcast client socket */
|
|
rc = osmo_sock_init_ofd(ofd, AF_INET, SOCK_DGRAM, IPPROTO_UDP,
|
|
NULL, mcast_port, flags);
|
|
if (rc < 0) {
|
|
perror("Could not create mcast client socket");
|
|
return rc;
|
|
}
|
|
|
|
/* Configure and join the multicast group */
|
|
rc = osmo_sock_mcast_subscribe(ofd->fd, mcast_group);
|
|
if (rc < 0) {
|
|
perror("Failed to join to mcast goup");
|
|
osmo_fd_close(ofd);
|
|
return rc;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct mcast_bidir_sock *
|
|
mcast_bidir_sock_setup(void *ctx, const char *tx_mcast_group, uint16_t tx_mcast_port,
|
|
const char *rx_mcast_group, uint16_t rx_mcast_port, bool loopback,
|
|
int (*fd_rx_cb)(struct osmo_fd *ofd, unsigned int what),
|
|
void *osmo_fd_data)
|
|
{
|
|
struct mcast_bidir_sock *bidir_sock = talloc(ctx, struct mcast_bidir_sock);
|
|
int rc;
|
|
|
|
if (!bidir_sock)
|
|
return NULL;
|
|
|
|
rc = mcast_client_sock_setup(&bidir_sock->rx_ofd, rx_mcast_group, rx_mcast_port,
|
|
fd_rx_cb, osmo_fd_data);
|
|
if (rc < 0) {
|
|
talloc_free(bidir_sock);
|
|
return NULL;
|
|
}
|
|
rc = mcast_server_sock_setup(&bidir_sock->tx_ofd, tx_mcast_group, tx_mcast_port, loopback);
|
|
if (rc < 0) {
|
|
osmo_fd_close(&bidir_sock->rx_ofd);
|
|
talloc_free(bidir_sock);
|
|
return NULL;
|
|
}
|
|
return bidir_sock;
|
|
|
|
}
|
|
|
|
int mcast_bidir_sock_tx(struct mcast_bidir_sock *bidir_sock, const uint8_t *data,
|
|
unsigned int data_len)
|
|
{
|
|
return send(bidir_sock->tx_ofd.fd, data, data_len, 0);
|
|
}
|
|
|
|
int mcast_bidir_sock_rx(struct mcast_bidir_sock *bidir_sock, uint8_t *buf, unsigned int buf_len)
|
|
{
|
|
return recv(bidir_sock->rx_ofd.fd, buf, buf_len, 0);
|
|
}
|
|
|
|
void mcast_bidir_sock_close(struct mcast_bidir_sock *bidir_sock)
|
|
{
|
|
osmo_fd_close(&bidir_sock->tx_ofd);
|
|
osmo_fd_close(&bidir_sock->rx_ofd);
|
|
talloc_free(bidir_sock);
|
|
}
|