From 33fbad18c814e13bd7ba2053525d8959fee437d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Sousa?= <48479050+joaodasousa@users.noreply.github.com> Date: Mon, 31 Aug 2020 00:56:03 +0100 Subject: Implement DLTClient for UDP multicast (#240) * Add UDP multicast support on client side UDP multicast support is already present on server side. This patch add seemless support for UDP multicast on client side in dlt-receive. Signed-off-by: Joao Sousa --- include/dlt/dlt_client.h | 22 ++++++++++-- include/dlt/dlt_common.h | 11 +++--- src/console/dlt-receive.c | 19 +++++++++-- src/examples/CMakeLists.txt | 4 +-- src/lib/dlt_client.c | 82 ++++++++++++++++++++++++++++++++++++++++++++- src/shared/dlt_common.c | 15 ++++++++- 6 files changed, 140 insertions(+), 13 deletions(-) diff --git a/include/dlt/dlt_client.h b/include/dlt/dlt_client.h index 1fac86a..f649b83 100644 --- a/include/dlt/dlt_client.h +++ b/include/dlt/dlt_client.h @@ -81,14 +81,16 @@ typedef enum DLT_CLIENT_MODE_UNDEFINED = -1, DLT_CLIENT_MODE_TCP, DLT_CLIENT_MODE_SERIAL, - DLT_CLIENT_MODE_UNIX + DLT_CLIENT_MODE_UNIX, + DLT_CLIENT_MODE_UDP_MULTICAST } DltClientMode; typedef struct { DltReceiver receiver; /**< receiver pointer to dlt receiver structure */ int sock; /**< sock Connection handle/socket */ - char *servIP; /**< servIP IP adress/Hostname of TCP/IP interface */ + char *servIP; /**< servIP IP adress/Hostname of interface */ + char *hostip; /**< hostip IP address of UDP host receiver interface */ int port; /**< Port for TCP connections (optional) */ char *serialDevice; /**< serialDevice Devicename of serial device */ char *socketPath; /**< socketPath Unix socket path */ @@ -269,6 +271,14 @@ DltReturnValue dlt_client_send_reset_to_factory_default(DltClient *client); */ DltReturnValue dlt_client_setbaudrate(DltClient *client, int baudrate); +/** + * Set mode within dlt client structure + * @param client pointer to dlt client structure + * @param mode DltClientMode + * @return Value from DltReturnValue enum + */ +DltReturnValue dlt_client_set_mode(DltClient *client, DltClientMode mode); + /** * Set server ip * @param client pointer to dlt client structure @@ -277,6 +287,14 @@ DltReturnValue dlt_client_setbaudrate(DltClient *client, int baudrate); */ int dlt_client_set_server_ip(DltClient *client, char *ipaddr); +/** + * Set server UDP host receiver interface address + * @param client pointer to dlt client structure + * @param hostip pointer to multicast group address + * @return negative value if there was an error + */ +int dlt_client_set_host_if_address(DltClient *client, char *hostip); + /** * Set serial device * @param client pointer to dlt client structure diff --git a/include/dlt/dlt_common.h b/include/dlt/dlt_common.h index 9f4096b..166395e 100644 --- a/include/dlt/dlt_common.h +++ b/include/dlt/dlt_common.h @@ -77,6 +77,7 @@ # include # ifdef __linux__ # include +# include # else # include # endif @@ -402,6 +403,7 @@ enum { typedef enum { DLT_RECEIVE_SOCKET, + DLT_RECEIVE_UDP_SOCKET, DLT_RECEIVE_FD } DltReceiverType; @@ -767,11 +769,12 @@ typedef struct int32_t lastBytesRcvd; /**< bytes received in last receive call */ int32_t bytesRcvd; /**< received bytes */ int32_t totalBytesRcvd; /**< total number of received bytes */ - char *buffer; /**< pointer to receiver buffer */ - char *buf; /**< pointer to position within receiver buffer */ - char *backup_buf; /** pointer to the buffer with partial messages if any **/ - int fd; /**< connection handle */ + char *buffer; /**< pointer to receiver buffer */ + char *buf; /**< pointer to position within receiver buffer */ + char *backup_buf; /** pointer to the buffer with partial messages if any **/ + int fd; /**< connection handle */ int32_t buffersize; /**< size of receiver buffer */ + struct sockaddr_in addr; /**< socket address information */ } DltReceiver; typedef struct diff --git a/src/console/dlt-receive.c b/src/console/dlt-receive.c index 24280ee..cdfa274 100644 --- a/src/console/dlt-receive.c +++ b/src/console/dlt-receive.c @@ -96,6 +96,7 @@ typedef struct { int mflag; int vflag; int yflag; + int uflag; char *ovalue; char *ovaluebase; /* ovalue without ".dlt" */ char *fvalue; @@ -131,6 +132,7 @@ void usage() printf(" -v Verbose mode\n"); printf(" -h Usage\n"); printf(" -y Serial device mode\n"); + printf(" -u UDP multicast mode\n"); printf(" -b baudrate Serial device baudrate (Default: 115200)\n"); printf(" -e ecuid Set ECU ID (Default: RECV)\n"); printf(" -o filename Output messages in new DLT file\n"); @@ -300,6 +302,7 @@ int main(int argc, char *argv[]) dltdata.mflag = 0; dltdata.vflag = 0; dltdata.yflag = 0; + dltdata.uflag = 0; dltdata.ovalue = 0; dltdata.ovaluebase = 0; dltdata.fvalue = 0; @@ -313,7 +316,7 @@ int main(int argc, char *argv[]) /* Fetch command line arguments */ opterr = 0; - while ((c = getopt (argc, argv, "vashyxmf:o:e:b:c:")) != -1) + while ((c = getopt (argc, argv, "vashyuxmf:o:e:b:c:")) != -1) switch (c) { case 'v': { @@ -350,6 +353,11 @@ int main(int argc, char *argv[]) dltdata.yflag = 1; break; } + case 'u': + { + dltdata.uflag = 1; + break; + } case 'f': { dltdata.fvalue = optarg; @@ -425,9 +433,14 @@ int main(int argc, char *argv[]) dlt_client_register_message_callback(dlt_receive_message_callback); /* Setup DLT Client structure */ - dltclient.mode = dltdata.yflag; + if(dltdata.uflag) { + dltclient.mode = DLT_CLIENT_MODE_UDP_MULTICAST; + } + else { + dltclient.mode = dltdata.yflag; + } - if (dltclient.mode == DLT_CLIENT_MODE_TCP) { + if (dltclient.mode == DLT_CLIENT_MODE_TCP || dltclient.mode == DLT_CLIENT_MODE_UDP_MULTICAST) { for (index = optind; index < argc; index++) if (dlt_client_set_server_ip(&dltclient, argv[index]) == -1) { fprintf(stderr, "set server ip didn't succeed\n"); diff --git a/src/examples/CMakeLists.txt b/src/examples/CMakeLists.txt index 93f76a8..013700d 100644 --- a/src/examples/CMakeLists.txt +++ b/src/examples/CMakeLists.txt @@ -40,8 +40,8 @@ if(WITH_UDP_CONNECTION) set_target_properties(dlt-example-multicast-clientmsg-view PROPERTIES LINKER_LANGUAGE C) install(TARGETS dlt-example-multicast-clientmsg-view - RUNTIME DESTINATION bin - COMPONENT base) + RUNTIME DESTINATION bin + COMPONENT base) endif(WITH_UDP_CONNECTION) diff --git a/src/lib/dlt_client.c b/src/lib/dlt_client.c index 5c18c0e..0b44d6e 100644 --- a/src/lib/dlt_client.c +++ b/src/lib/dlt_client.c @@ -121,6 +121,7 @@ DltReturnValue dlt_client_init_port(DltClient *client, int port, int verbose) client->receiver.buffer = NULL; client->receiver.buf = NULL; client->receiver.backup_buf = NULL; + client->hostip = NULL; return DLT_RETURN_OK; } @@ -153,16 +154,17 @@ DltReturnValue dlt_client_init(DltClient *client, int verbose) dlt_vlog(LOG_INFO, "Init dlt client struct with default port: %hu.\n", servPort); - return dlt_client_init_port(client, servPort, verbose); } DltReturnValue dlt_client_connect(DltClient *client, int verbose) { + const int yes = 1; char portnumbuffer[33]; struct addrinfo hints, *servinfo, *p; struct sockaddr_un addr; int rv; + struct ip_mreq mreq; memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; @@ -265,6 +267,58 @@ DltReturnValue dlt_client_connect(DltClient *client, int verbose) return DLT_RETURN_ERROR; } + break; + case DLT_CLIENT_MODE_UDP_MULTICAST: + + if ((client->sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + fprintf(stderr, "ERROR: socket error: %s\n", strerror(errno)); + return DLT_RETURN_ERROR; + } + + /* allow multiple sockets to use the same PORT number */ + if (setsockopt(client->sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) + { + fprintf(stderr, "ERROR: Reusing address failed: %s\n", strerror(errno)); + return DLT_RETURN_ERROR; + } + + memset(&client->receiver.addr, 0, sizeof(client->receiver.addr)); + client->receiver.addr.sin_family = AF_INET; + client->receiver.addr.sin_addr.s_addr = htonl(INADDR_ANY); + client->receiver.addr.sin_port = htons(client->port); + + /* bind to receive address */ + if (bind(client->sock, (struct sockaddr*) &client->receiver.addr, sizeof(client->receiver.addr)) < 0) + { + fprintf(stderr, "ERROR: bind failed: %s\n", strerror(errno)); + return DLT_RETURN_ERROR; + } + + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + if (client->hostip) + { + mreq.imr_interface.s_addr = inet_addr(client->hostip); + } + if (client->servIP == NULL) + { + fprintf(stderr, "ERROR: server address not set\n"); + return DLT_RETURN_ERROR; + } + + mreq.imr_multiaddr.s_addr = inet_addr(client->servIP); + if (mreq.imr_multiaddr.s_addr == (in_addr_t)-1) + { + fprintf(stderr, "ERROR: server address not not valid %s\n", client->servIP); + return DLT_RETURN_ERROR; + } + + if (setsockopt(client->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0) + { + fprintf(stderr, "ERROR: setsockopt add membership failed: %s\n", strerror(errno)); + return DLT_RETURN_ERROR; + } + break; default: @@ -315,6 +369,10 @@ DltReturnValue dlt_client_cleanup(DltClient *client, int verbose) client->socketPath = NULL; } + if (client->hostip) { + free(client->hostip); + client->hostip = NULL; + } return ret; } @@ -875,6 +933,16 @@ DltReturnValue dlt_client_setbaudrate(DltClient *client, int baudrate) return DLT_RETURN_OK; } +DltReturnValue dlt_client_set_mode(DltClient *client, DltClientMode mode) +{ + if (client == 0) + return DLT_RETURN_ERROR; + + client->mode = mode; + return DLT_RETURN_OK; + +} + int dlt_client_set_server_ip(DltClient *client, char *ipaddr) { client->servIP = strdup(ipaddr); @@ -887,6 +955,18 @@ int dlt_client_set_server_ip(DltClient *client, char *ipaddr) return DLT_RETURN_OK; } +int dlt_client_set_host_if_address(DltClient *client, char *hostip) +{ + client->hostip = strdup(hostip); + + if (client->hostip == NULL) { + dlt_log(LOG_ERR, "ERROR: failed to duplicate UDP interface address\n"); + return DLT_RETURN_ERROR; + } + + return DLT_RETURN_OK; +} + int dlt_client_set_serial_device(DltClient *client, char *serial_device) { client->serialDevice = strdup(serial_device); diff --git a/src/shared/dlt_common.c b/src/shared/dlt_common.c index eb620f5..823bca7 100644 --- a/src/shared/dlt_common.c +++ b/src/shared/dlt_common.c @@ -2014,6 +2014,8 @@ DltReturnValue dlt_receiver_free_unix_socket(DltReceiver *receiver) int dlt_receiver_receive(DltReceiver *receiver, DltReceiverType from_src) { + socklen_t addrlen; + if (receiver == NULL) return -1; @@ -2035,12 +2037,23 @@ int dlt_receiver_receive(DltReceiver *receiver, DltReceiverType from_src) receiver->buf + receiver->lastBytesRcvd, receiver->buffersize - receiver->lastBytesRcvd, 0); - else + else if (from_src == DLT_RECEIVE_FD) /* wait for data from fd */ receiver->bytesRcvd = read(receiver->fd, receiver->buf + receiver->lastBytesRcvd, receiver->buffersize - receiver->lastBytesRcvd); + else { + /* wait for data from UDP socket */ + addrlen = sizeof(receiver->addr); + receiver->bytesRcvd = recvfrom(receiver->fd, + receiver->buf + receiver->lastBytesRcvd, + receiver->buffersize - receiver->lastBytesRcvd, + 0, + (struct sockaddr *)&(receiver->addr), + &addrlen); + } + if (receiver->bytesRcvd <= 0) { receiver->bytesRcvd = 0; -- cgit v1.2.1