Add DTLS 1.2 Mulicast Example.
parent
a9d5b45b15
commit
dfed0437ab
|
|
@ -0,0 +1,26 @@
|
|||
# DTLS Multicast Examples Makefile
|
||||
CC = gcc
|
||||
WOLFSSL_INSTALL_DIR = /usr/local
|
||||
CFLAGS = -Wall -I$(WOLFSSL_INSTALL_DIR)/include
|
||||
LIBS = -L$(WOLFSSL_INSTALL_DIR)/lib -lwolfssl -lm
|
||||
|
||||
# build targets
|
||||
TARGETS = mcast-peer
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
mcast-peer: mcast-peer.c
|
||||
$(CC) -o $@ $< $(CFLAGS) $(LIBS)
|
||||
|
||||
clean:
|
||||
rm -f $(TARGETS)
|
||||
|
||||
# Helper targets for running the example
|
||||
run-node0:
|
||||
./mcast-peer 0
|
||||
|
||||
run-node1:
|
||||
./mcast-peer 1
|
||||
|
||||
run-node2:
|
||||
./mcast-peer 2
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
# DTLS 1.2 Multicast Example
|
||||
|
||||
This example demonstrates DTLS 1.2 multicast communication using wolfSSL's multicast APIs. Three peer applications can securely communicate with each other over UDP multicast.
|
||||
|
||||
## Overview
|
||||
|
||||
DTLS multicast allows multiple peers to share encrypted/authenticated communication over IP multicast. Unlike traditional TLS/DTLS which uses a handshake to establish keys, multicast DTLS uses pre-shared secrets that are distributed out-of-band to all participants.
|
||||
|
||||
This example uses:
|
||||
- **WDM-NULL-SHA256** cipher suite (NULL encryption with SHA-256 for message authentication)
|
||||
- Pre-shared secret material (PMS, client random, server random)
|
||||
- Multicast group `239.255.0.1:12345`
|
||||
|
||||
NOTE: Since this is using NULL encryption, all messages going over the wire are plaintext. This example provides no confidentiality.
|
||||
|
||||
## Requirements
|
||||
|
||||
wolfSSL must be built with multicast support:
|
||||
|
||||
```bash
|
||||
cd /path/to/wolfssl
|
||||
./configure --enable-dtls --enable-mcast
|
||||
make
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
```bash
|
||||
make
|
||||
```
|
||||
## Usage
|
||||
|
||||
Run each peer in a separate terminal with a unique node ID (0, 1, or 2):
|
||||
|
||||
```bash
|
||||
# Terminal 1
|
||||
./mcast-peer 0
|
||||
|
||||
# Terminal 2
|
||||
./mcast-peer 1
|
||||
|
||||
# Terminal 3
|
||||
./mcast-peer 2
|
||||
```
|
||||
|
||||
Each peer will:
|
||||
1. Join the multicast group
|
||||
2. Send a message every 3 seconds
|
||||
3. Receive and display messages from other peers
|
||||
4. Exit cleanly on Ctrl+C
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
=== DTLS Multicast Peer - Node 0 ===
|
||||
Node 0: Sockets ready, joined multicast group 239.255.0.1:12345
|
||||
Node 0: Added peer 1 to receive tracking
|
||||
Node 0: Added peer 2 to receive tracking
|
||||
Node 0: Ready. Press Ctrl+C to exit.
|
||||
Node 0: Sending messages every 3 seconds...
|
||||
|
||||
Node 0: Sent: "Hello from node 0, message #1"
|
||||
Node 0: Received from peer 1: "Hello from node 1, message #1"
|
||||
Node 0: Received from peer 2: "Hello from node 2, message #1"
|
||||
```
|
||||
|
||||
## API Usage Notes
|
||||
|
||||
The wolfSSL multicast APIs must be called in a specific order:
|
||||
|
||||
1. `wolfSSL_CTX_mcast_set_member_id()` - Set this node's ID
|
||||
2. `wolfSSL_CTX_set_cipher_list()` - Set multicast cipher suite
|
||||
3. `wolfSSL_new()` - Create SSL objects
|
||||
4. `wolfSSL_mcast_peer_add()` - Register expected peers (**before** setting secret)
|
||||
5. `wolfSSL_set_secret()` - Set the pre-shared secret (**after** adding peers)
|
||||
6. `wolfSSL_write()` / `wolfSSL_mcast_read()` - Send/receive messages
|
||||
|
||||
**Important**: `wolfSSL_mcast_peer_add()` must be called BEFORE `wolfSSL_set_secret()` because `wolfSSL_mcast_peer_add()` zeros the peer entry (including the epoch), and `wolfSSL_set_secret()` sets the epoch for all registered peers.
|
||||
|
||||
## Key Concepts
|
||||
|
||||
### Multicast Member ID
|
||||
Each peer has a unique ID (0-255) set via `wolfSSL_CTX_mcast_set_member_id()`. This ID is embedded in outgoing DTLS records and used by receivers to identify the sender.
|
||||
|
||||
### Pre-Shared Secret
|
||||
All peers must use identical secret material:
|
||||
- Pre-master secret (PMS)
|
||||
- Client random
|
||||
- Server random
|
||||
- Cipher suite identifier
|
||||
|
||||
In production, this material would be distributed securely out-of-band (e.g., via a key server).
|
||||
|
||||
### NULL Encryption
|
||||
This example is using NULL encryption. That means all messages going over the wire are plaintext. This example provides no confidentiality.
|
||||
|
||||
## References
|
||||
|
||||
- [wolfSSL Manual - DTLS](https://www.wolfssl.com/documentation/manuals/wolfssl/chapter02.html)
|
||||
- [RFC 6347 - DTLS 1.2](https://tools.ietf.org/html/rfc6347)
|
||||
|
|
@ -0,0 +1,457 @@
|
|||
/* mcast-peer.c
|
||||
*
|
||||
* Copyright (C) 2006-2025 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL. (formerly known as CyaSSL)
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*
|
||||
*=============================================================================
|
||||
*
|
||||
* Example of DTLS 1.2 multicast with PSK using wolfSSL.
|
||||
* Three peers can communicate with each other over multicast.
|
||||
*
|
||||
* Usage: ./mcast-peer <node_id>
|
||||
* where node_id is 0, 1, or 2
|
||||
*
|
||||
* Requires wolfSSL built with: ./configure --enable-dtls --enable-mcast
|
||||
*/
|
||||
|
||||
#include <wolfssl/options.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
#include <wolfssl/error-ssl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
|
||||
/* Multicast group settings */
|
||||
#define MCAST_GROUP "239.255.0.1"
|
||||
#define MCAST_PORT 12345
|
||||
#define MSGLEN 256
|
||||
|
||||
/* Number of peers in the multicast group */
|
||||
#define NUM_PEERS 3
|
||||
|
||||
/* Pre-shared secret components (must be same for all peers) */
|
||||
#define PMS_SIZE 48
|
||||
#define RANDOM_SIZE 32
|
||||
|
||||
/* Epoch for the multicast session */
|
||||
#define MCAST_EPOCH 1
|
||||
|
||||
#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_MULTICAST)
|
||||
|
||||
/* Global flag for clean shutdown */
|
||||
static volatile sig_atomic_t running = 1;
|
||||
|
||||
static void sig_handler(int sig)
|
||||
{
|
||||
(void)sig;
|
||||
running = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup a multicast UDP socket for sending to the group
|
||||
*/
|
||||
static int setup_tx_socket(struct sockaddr_in* txAddr)
|
||||
{
|
||||
int sd;
|
||||
unsigned char ttl = 1;
|
||||
int on = 1;
|
||||
|
||||
sd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sd < 0) {
|
||||
perror("socket (tx)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set TTL for multicast */
|
||||
if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
|
||||
perror("setsockopt IP_MULTICAST_TTL");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Enable loopback so other processes on same host can receive */
|
||||
if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP, &on, sizeof(on)) < 0) {
|
||||
perror("setsockopt IP_MULTICAST_LOOP");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Setup destination address */
|
||||
memset(txAddr, 0, sizeof(*txAddr));
|
||||
txAddr->sin_family = AF_INET;
|
||||
txAddr->sin_addr.s_addr = inet_addr(MCAST_GROUP);
|
||||
txAddr->sin_port = htons(MCAST_PORT);
|
||||
|
||||
/* Connect to multicast address for sending */
|
||||
if (connect(sd, (struct sockaddr*)txAddr, sizeof(*txAddr)) < 0) {
|
||||
perror("connect (tx)");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup a multicast UDP socket for receiving from the group
|
||||
*/
|
||||
static int setup_rx_socket(void)
|
||||
{
|
||||
int sd;
|
||||
int on = 1;
|
||||
struct sockaddr_in addr;
|
||||
struct ip_mreq mreq;
|
||||
|
||||
sd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sd < 0) {
|
||||
perror("socket (rx)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Allow multiple sockets to use the same port */
|
||||
if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
|
||||
perror("setsockopt SO_REUSEADDR");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef SO_REUSEPORT
|
||||
if (setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) < 0) {
|
||||
perror("setsockopt SO_REUSEPORT");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Bind to multicast port */
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
addr.sin_port = htons(MCAST_PORT);
|
||||
|
||||
if (bind(sd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
perror("bind (rx)");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Join the multicast group */
|
||||
mreq.imr_multiaddr.s_addr = inet_addr(MCAST_GROUP);
|
||||
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
if (setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
|
||||
perror("setsockopt IP_ADD_MEMBERSHIP");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set non-blocking for receive */
|
||||
{
|
||||
int flags = fcntl(sd, F_GETFL, 0);
|
||||
if (flags < 0 || fcntl(sd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||
perror("fcntl");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return sd;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int ret;
|
||||
int myId;
|
||||
int txSd = -1;
|
||||
int rxSd = -1;
|
||||
WOLFSSL_CTX* ctx = NULL;
|
||||
WOLFSSL* sslTx = NULL;
|
||||
WOLFSSL* sslRx = NULL;
|
||||
struct sockaddr_in txAddr;
|
||||
int i;
|
||||
|
||||
/* Pre-shared secret components - same for all peers */
|
||||
unsigned char pms[PMS_SIZE];
|
||||
unsigned char clientRandom[RANDOM_SIZE];
|
||||
unsigned char serverRandom[RANDOM_SIZE];
|
||||
/* WDM-NULL-SHA256 cipher suite bytes */
|
||||
unsigned char suite[2] = { 0x00, 0xFE };
|
||||
|
||||
time_t lastSend = 0;
|
||||
int msgCount = 0;
|
||||
|
||||
/* Parse arguments */
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s <node_id>\n", argv[0]);
|
||||
fprintf(stderr, " node_id: 0, 1, or 2\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
myId = atoi(argv[1]);
|
||||
if (myId < 0 || myId >= NUM_PEERS) {
|
||||
fprintf(stderr, "Error: node_id must be 0, 1, or 2\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Setup signal handler */
|
||||
signal(SIGINT, sig_handler);
|
||||
signal(SIGTERM, sig_handler);
|
||||
|
||||
printf("=== DTLS Multicast Peer - Node %d ===\n", myId);
|
||||
|
||||
/* Enable debug output if built with --enable-debug */
|
||||
#ifdef DEBUG_WOLFSSL
|
||||
wolfSSL_Debugging_ON();
|
||||
#endif
|
||||
|
||||
/* Initialize the pre-shared secrets (same for all peers) */
|
||||
memset(pms, 0x23, sizeof(pms));
|
||||
memset(clientRandom, 0xA5, sizeof(clientRandom));
|
||||
memset(serverRandom, 0x5A, sizeof(serverRandom));
|
||||
|
||||
/* Initialize wolfSSL */
|
||||
ret = wolfSSL_Init();
|
||||
if (ret != WOLFSSL_SUCCESS) {
|
||||
fprintf(stderr, "Error: wolfSSL_Init failed: %d\n", ret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Create DTLS 1.2 context */
|
||||
ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method());
|
||||
if (ctx == NULL) {
|
||||
fprintf(stderr, "Error: wolfSSL_CTX_new failed\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Set multicast member ID */
|
||||
ret = wolfSSL_CTX_mcast_set_member_id(ctx, (unsigned short)myId);
|
||||
if (ret != WOLFSSL_SUCCESS) {
|
||||
fprintf(stderr, "Error: wolfSSL_CTX_mcast_set_member_id failed: %d\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Set multicast cipher suite (NULL cipher with SHA256 for integrity) */
|
||||
ret = wolfSSL_CTX_set_cipher_list(ctx, "WDM-NULL-SHA256");
|
||||
if (ret != WOLFSSL_SUCCESS) {
|
||||
fprintf(stderr, "Error: wolfSSL_CTX_set_cipher_list failed: %d\n", ret);
|
||||
fprintf(stderr, "Make sure wolfSSL is built with --enable-mcast\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Setup sockets */
|
||||
txSd = setup_tx_socket(&txAddr);
|
||||
if (txSd < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rxSd = setup_rx_socket();
|
||||
if (rxSd < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
printf("Node %d: Sockets ready, joined multicast group %s:%d\n",
|
||||
myId, MCAST_GROUP, MCAST_PORT);
|
||||
|
||||
/* Create SSL object for transmitting */
|
||||
sslTx = wolfSSL_new(ctx);
|
||||
if (sslTx == NULL) {
|
||||
fprintf(stderr, "Error: wolfSSL_new (tx) failed\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Create SSL object for receiving */
|
||||
sslRx = wolfSSL_new(ctx);
|
||||
if (sslRx == NULL) {
|
||||
fprintf(stderr, "Error: wolfSSL_new (rx) failed\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Set socket file descriptors */
|
||||
wolfSSL_set_fd(sslTx, txSd);
|
||||
wolfSSL_set_fd(sslRx, rxSd);
|
||||
|
||||
/* Set using nonblock for receive */
|
||||
wolfSSL_dtls_set_using_nonblock(sslRx, 1);
|
||||
|
||||
/* Add peers for receive tracking BEFORE setting secret.
|
||||
* IMPORTANT: wolfSSL_mcast_peer_add() zeros the peer entry, including
|
||||
* nextEpoch. wolfSSL_set_secret() sets nextEpoch for all entries.
|
||||
* So peers must be added first, then secret set afterward. */
|
||||
for (i = 0; i < NUM_PEERS; i++) {
|
||||
if (i != myId) {
|
||||
ret = wolfSSL_mcast_peer_add(sslRx, (unsigned short)i, 0);
|
||||
if (ret != WOLFSSL_SUCCESS) {
|
||||
fprintf(stderr, "Error: wolfSSL_mcast_peer_add(%d) failed: %d\n",
|
||||
i, ret);
|
||||
goto cleanup;
|
||||
}
|
||||
printf("Node %d: Added peer %d to receive tracking\n", myId, i);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the pre-shared secret for both SSL objects.
|
||||
* This must be called AFTER adding peers so their nextEpoch gets set. */
|
||||
ret = wolfSSL_set_secret(sslTx, MCAST_EPOCH, pms, sizeof(pms),
|
||||
clientRandom, serverRandom, suite);
|
||||
if (ret != WOLFSSL_SUCCESS) {
|
||||
fprintf(stderr, "Error: wolfSSL_set_secret (tx) failed: %d\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = wolfSSL_set_secret(sslRx, MCAST_EPOCH, pms, sizeof(pms),
|
||||
clientRandom, serverRandom, suite);
|
||||
if (ret != WOLFSSL_SUCCESS) {
|
||||
fprintf(stderr, "Error: wolfSSL_set_secret (rx) failed: %d\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Flush any stale packets from previous runs */
|
||||
{
|
||||
char discard[MSGLEN];
|
||||
struct timeval tv_flush = {0, 0};
|
||||
fd_set fds;
|
||||
while (1) {
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(rxSd, &fds);
|
||||
if (select(rxSd + 1, &fds, NULL, NULL, &tv_flush) <= 0)
|
||||
break;
|
||||
if (recv(rxSd, discard, sizeof(discard), 0) <= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Node %d: Ready. Press Ctrl+C to exit.\n", myId);
|
||||
printf("Node %d: Sending messages every 3 seconds...\n\n", myId);
|
||||
|
||||
/* Main loop */
|
||||
while (running) {
|
||||
fd_set readfds;
|
||||
struct timeval tv;
|
||||
time_t now;
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(rxSd, &readfds);
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
ret = select(rxSd + 1, &readfds, NULL, NULL, &tv);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
perror("select");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check for incoming messages */
|
||||
if (ret > 0 && FD_ISSET(rxSd, &readfds)) {
|
||||
unsigned char buf[MSGLEN];
|
||||
unsigned short peerId = 0;
|
||||
int recvLen;
|
||||
|
||||
recvLen = wolfSSL_mcast_read(sslRx, &peerId, buf, sizeof(buf) - 1);
|
||||
if (recvLen > 0) {
|
||||
/* Ignore our own messages (loopback) */
|
||||
if (peerId != (unsigned short)myId) {
|
||||
buf[recvLen] = '\0';
|
||||
printf("Node %d: Received from peer %d: \"%s\"\n",
|
||||
myId, peerId, buf);
|
||||
}
|
||||
}
|
||||
else if (recvLen < 0) {
|
||||
int err = wolfSSL_get_error(sslRx, recvLen);
|
||||
if (err != WOLFSSL_ERROR_WANT_READ) {
|
||||
/* Ignore decryption errors from our own packets */
|
||||
if (err != DECRYPT_ERROR && err != VERIFY_MAC_ERROR) {
|
||||
char errStr[80];
|
||||
wolfSSL_ERR_error_string(err, errStr);
|
||||
fprintf(stderr, "Node %d: Read error: %s (%d)\n",
|
||||
myId, errStr, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Send a message every 3 seconds */
|
||||
now = time(NULL);
|
||||
if (now - lastSend >= 3) {
|
||||
char msg[MSGLEN];
|
||||
int writeLen;
|
||||
|
||||
snprintf(msg, sizeof(msg), "Hello from node %d, message #%d",
|
||||
myId, ++msgCount);
|
||||
|
||||
writeLen = wolfSSL_write(sslTx, msg, (int)strlen(msg));
|
||||
if (writeLen > 0) {
|
||||
printf("Node %d: Sent: \"%s\"\n", myId, msg);
|
||||
}
|
||||
else {
|
||||
int err = wolfSSL_get_error(sslTx, writeLen);
|
||||
char errStr[80];
|
||||
wolfSSL_ERR_error_string(err, errStr);
|
||||
fprintf(stderr, "Node %d: Write error: %s (%d)\n",
|
||||
myId, errStr, err);
|
||||
}
|
||||
|
||||
lastSend = now;
|
||||
}
|
||||
}
|
||||
|
||||
printf("\nNode %d: Shutting down...\n", myId);
|
||||
|
||||
cleanup:
|
||||
if (sslTx != NULL) {
|
||||
wolfSSL_free(sslTx);
|
||||
}
|
||||
if (sslRx != NULL) {
|
||||
wolfSSL_free(sslRx);
|
||||
}
|
||||
if (ctx != NULL) {
|
||||
wolfSSL_CTX_free(ctx);
|
||||
}
|
||||
if (rxSd >= 0) {
|
||||
/* Leave multicast group */
|
||||
struct ip_mreq mreq;
|
||||
mreq.imr_multiaddr.s_addr = inet_addr(MCAST_GROUP);
|
||||
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
setsockopt(rxSd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
|
||||
close(rxSd);
|
||||
}
|
||||
if (txSd >= 0) {
|
||||
close(txSd);
|
||||
}
|
||||
wolfSSL_Cleanup();
|
||||
|
||||
printf("Node %d: Goodbye!\n", myId);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int main()
|
||||
{
|
||||
fprintf(stderr, "Please configure the wolfssl library with --enable-dtls --enable-mcast.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS && WOLFSSL_MULTICAST */
|
||||
Loading…
Reference in New Issue