1c87c5fbaSopenharmony_ci/* tiny -- tiny sender
2c87c5fbaSopenharmony_ci *
3c87c5fbaSopenharmony_ci * Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
4c87c5fbaSopenharmony_ci *
5c87c5fbaSopenharmony_ci * SPDX-License-Identifier: BSD-2-Clause
6c87c5fbaSopenharmony_ci *
7c87c5fbaSopenharmony_ci * This file is part of the CoAP library libcoap. Please see
8c87c5fbaSopenharmony_ci * README for terms of use.
9c87c5fbaSopenharmony_ci */
10c87c5fbaSopenharmony_ci
11c87c5fbaSopenharmony_ci#include <string.h>
12c87c5fbaSopenharmony_ci#include <stdlib.h>
13c87c5fbaSopenharmony_ci#include <stdio.h>
14c87c5fbaSopenharmony_ci#include <ctype.h>
15c87c5fbaSopenharmony_ci#include <limits.h>
16c87c5fbaSopenharmony_ci#include <sys/select.h>
17c87c5fbaSopenharmony_ci#include <sys/types.h>
18c87c5fbaSopenharmony_ci#include <sys/socket.h>
19c87c5fbaSopenharmony_ci#include <netinet/in.h>
20c87c5fbaSopenharmony_ci#include <arpa/inet.h>
21c87c5fbaSopenharmony_ci#include <netdb.h>
22c87c5fbaSopenharmony_ci#include <signal.h>
23c87c5fbaSopenharmony_ci
24c87c5fbaSopenharmony_ci#include <coap3/coap.h>
25c87c5fbaSopenharmony_ci
26c87c5fbaSopenharmony_ci#define Nn 8  /* duplicate definition of N if built on sky motes */
27c87c5fbaSopenharmony_ci#define ENCODE_HEADER_SIZE 4
28c87c5fbaSopenharmony_ci#define HIBIT (1 << (Nn - 1))
29c87c5fbaSopenharmony_ci#define EMASK ((1 << ENCODE_HEADER_SIZE) - 1)
30c87c5fbaSopenharmony_ci#define MMASK ((1 << Nn) - 1 - EMASK)
31c87c5fbaSopenharmony_ci#define MAX_VALUE ( (1 << Nn) - (1 << ENCODE_HEADER_SIZE) ) * (1 << ((1 << ENCODE_HEADER_SIZE) - 1))
32c87c5fbaSopenharmony_ci
33c87c5fbaSopenharmony_ci#define COAP_PSEUDOFP_DECODE_8_4(r) (r < HIBIT ? r : (r & MMASK) << (r & EMASK))
34c87c5fbaSopenharmony_ci
35c87c5fbaSopenharmony_ci/* ls and s must be integer variables */
36c87c5fbaSopenharmony_ci/* #define COAP_PSEUDOFP_ENCODE_8_4_DOWN(v,ls) (v < HIBIT ? v : (ls = coap_fls(v) - Nn, (v >> ls) & MMASK) + ls) */
37c87c5fbaSopenharmony_ciCOAP_STATIC_INLINE unsigned char
38c87c5fbaSopenharmony_ciCOAP_PSEUDOFP_ENCODE_8_4_DOWN(unsigned int v, int *ls) {
39c87c5fbaSopenharmony_ci  if (v < HIBIT)
40c87c5fbaSopenharmony_ci    return v;
41c87c5fbaSopenharmony_ci  *ls = coap_fls(v) - Nn;
42c87c5fbaSopenharmony_ci  return ((v >> *ls) & MMASK) + *ls;
43c87c5fbaSopenharmony_ci}
44c87c5fbaSopenharmony_ci#define COAP_PSEUDOFP_ENCODE_8_4_UP(v,ls,s) (v < HIBIT ? v : (ls = coap_fls(v) - Nn, (s = (((v + ((1<<ENCODE_HEADER_SIZE<<ls)-1)) >> ls) & MMASK)), s == 0 ? HIBIT + ls + 1 : s + ls))
45c87c5fbaSopenharmony_ci
46c87c5fbaSopenharmony_cistatic int quit = 0;
47c87c5fbaSopenharmony_ci
48c87c5fbaSopenharmony_ci/* SIGINT handler: set quit to 1 for graceful termination */
49c87c5fbaSopenharmony_cistatic void
50c87c5fbaSopenharmony_cihandle_sigint(int signum COAP_UNUSED) {
51c87c5fbaSopenharmony_ci  quit = 1;
52c87c5fbaSopenharmony_ci}
53c87c5fbaSopenharmony_ci
54c87c5fbaSopenharmony_cistatic coap_pdu_t *
55c87c5fbaSopenharmony_cimake_pdu(coap_session_t *session, unsigned int value) {
56c87c5fbaSopenharmony_ci  coap_pdu_t *pdu;
57c87c5fbaSopenharmony_ci  unsigned char enc;
58c87c5fbaSopenharmony_ci  static unsigned char buf[20];
59c87c5fbaSopenharmony_ci  int len, ls;
60c87c5fbaSopenharmony_ci
61c87c5fbaSopenharmony_ci  if (!(pdu = coap_pdu_init(COAP_MESSAGE_NON, COAP_REQUEST_CODE_POST,
62c87c5fbaSopenharmony_ci                            coap_new_message_id(session), COAP_DEFAULT_MTU)))
63c87c5fbaSopenharmony_ci    return NULL;
64c87c5fbaSopenharmony_ci
65c87c5fbaSopenharmony_ci  enc = COAP_PSEUDOFP_ENCODE_8_4_DOWN(value, &ls);
66c87c5fbaSopenharmony_ci
67c87c5fbaSopenharmony_ci  len = sprintf((char *)buf, "%c%u", enc, COAP_PSEUDOFP_DECODE_8_4(enc));
68c87c5fbaSopenharmony_ci  coap_add_data(pdu, len, buf);
69c87c5fbaSopenharmony_ci
70c87c5fbaSopenharmony_ci  return pdu;
71c87c5fbaSopenharmony_ci}
72c87c5fbaSopenharmony_ci
73c87c5fbaSopenharmony_cistatic void
74c87c5fbaSopenharmony_ciusage(const char *program) {
75c87c5fbaSopenharmony_ci  const char *p;
76c87c5fbaSopenharmony_ci
77c87c5fbaSopenharmony_ci  p = strrchr(program, '/');
78c87c5fbaSopenharmony_ci  if (p)
79c87c5fbaSopenharmony_ci    program = ++p;
80c87c5fbaSopenharmony_ci
81c87c5fbaSopenharmony_ci  fprintf(stderr, "%s -- tiny fake sensor\n"
82c87c5fbaSopenharmony_ci          "(c) 2010 Olaf Bergmann <bergmann@tzi.org>\n\n"
83c87c5fbaSopenharmony_ci          "usage: %s [group address]\n"
84c87c5fbaSopenharmony_ci          "\n\nSends some fake sensor values to specified multicast group\n",
85c87c5fbaSopenharmony_ci          program, program);
86c87c5fbaSopenharmony_ci}
87c87c5fbaSopenharmony_ci
88c87c5fbaSopenharmony_cistatic coap_session_t *
89c87c5fbaSopenharmony_ciget_session(coap_context_t *ctx, const char *group) {
90c87c5fbaSopenharmony_ci  int s;
91c87c5fbaSopenharmony_ci  struct addrinfo hints;
92c87c5fbaSopenharmony_ci  struct addrinfo *result, *rp;
93c87c5fbaSopenharmony_ci  coap_session_t *session;
94c87c5fbaSopenharmony_ci  int hops = 16;
95c87c5fbaSopenharmony_ci
96c87c5fbaSopenharmony_ci  if (!ctx)
97c87c5fbaSopenharmony_ci    return NULL;
98c87c5fbaSopenharmony_ci
99c87c5fbaSopenharmony_ci  memset(&hints, 0, sizeof(struct addrinfo));
100c87c5fbaSopenharmony_ci  hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
101c87c5fbaSopenharmony_ci  hints.ai_socktype = SOCK_DGRAM; /* Coap uses UDP */
102c87c5fbaSopenharmony_ci  hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST | AI_NUMERICSERV | AI_ALL;
103c87c5fbaSopenharmony_ci
104c87c5fbaSopenharmony_ci  s = getaddrinfo(group, NULL, &hints, &result);
105c87c5fbaSopenharmony_ci  if (s != 0) {
106c87c5fbaSopenharmony_ci    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
107c87c5fbaSopenharmony_ci    return NULL;
108c87c5fbaSopenharmony_ci  }
109c87c5fbaSopenharmony_ci
110c87c5fbaSopenharmony_ci  /* iterate through results until success */
111c87c5fbaSopenharmony_ci  for (rp = result; rp != NULL; rp = rp->ai_next) {
112c87c5fbaSopenharmony_ci    coap_address_t addr;
113c87c5fbaSopenharmony_ci    coap_address_init(&addr);
114c87c5fbaSopenharmony_ci    addr.size = rp->ai_addrlen;
115c87c5fbaSopenharmony_ci    memcpy(&addr.addr, rp->ai_addr, rp->ai_addrlen);
116c87c5fbaSopenharmony_ci
117c87c5fbaSopenharmony_ci    session = coap_new_client_session(ctx, NULL, &addr, COAP_PROTO_UDP);
118c87c5fbaSopenharmony_ci    if (!session)
119c87c5fbaSopenharmony_ci      continue;
120c87c5fbaSopenharmony_ci
121c87c5fbaSopenharmony_ci    if (coap_is_mcast(&addr)) {
122c87c5fbaSopenharmony_ci      /* set socket options for multicast */
123c87c5fbaSopenharmony_ci      if (!coap_mcast_set_hops(session, hops))
124c87c5fbaSopenharmony_ci        perror("setsockopt: IPV6_MULTICAST_HOPS");
125c87c5fbaSopenharmony_ci
126c87c5fbaSopenharmony_ci    }
127c87c5fbaSopenharmony_ci    freeaddrinfo(result);
128c87c5fbaSopenharmony_ci    return session;
129c87c5fbaSopenharmony_ci  }
130c87c5fbaSopenharmony_ci
131c87c5fbaSopenharmony_ci  fprintf(stderr, "no session available for group '%s'\n", group);
132c87c5fbaSopenharmony_ci  freeaddrinfo(result);
133c87c5fbaSopenharmony_ci  return NULL;
134c87c5fbaSopenharmony_ci}
135c87c5fbaSopenharmony_ci
136c87c5fbaSopenharmony_ciint
137c87c5fbaSopenharmony_cimain(int argc, char **argv) {
138c87c5fbaSopenharmony_ci  struct timeval tv;
139c87c5fbaSopenharmony_ci  coap_pdu_t  *pdu;
140c87c5fbaSopenharmony_ci  coap_session_t *session;
141c87c5fbaSopenharmony_ci  struct sigaction sa;
142c87c5fbaSopenharmony_ci  coap_context_t *ctx;
143c87c5fbaSopenharmony_ci
144c87c5fbaSopenharmony_ci  /* Initialize libcoap library */
145c87c5fbaSopenharmony_ci  coap_startup();
146c87c5fbaSopenharmony_ci
147c87c5fbaSopenharmony_ci  if (argc > 1 && strncmp(argv[1], "-h", 2) == 0) {
148c87c5fbaSopenharmony_ci    usage(argv[0]);
149c87c5fbaSopenharmony_ci    exit(1);
150c87c5fbaSopenharmony_ci  }
151c87c5fbaSopenharmony_ci
152c87c5fbaSopenharmony_ci  ctx = coap_new_context(NULL);
153c87c5fbaSopenharmony_ci  if (!ctx)
154c87c5fbaSopenharmony_ci    return -1;
155c87c5fbaSopenharmony_ci
156c87c5fbaSopenharmony_ci  session = get_session(ctx, argc > 1 ? argv[1] : "::1");
157c87c5fbaSopenharmony_ci
158c87c5fbaSopenharmony_ci  if (!session)
159c87c5fbaSopenharmony_ci    return -1;
160c87c5fbaSopenharmony_ci
161c87c5fbaSopenharmony_ci  memset(&sa, 0, sizeof(sa));
162c87c5fbaSopenharmony_ci  sigemptyset(&sa.sa_mask);
163c87c5fbaSopenharmony_ci  sa.sa_handler = handle_sigint;
164c87c5fbaSopenharmony_ci  sa.sa_flags = 0;
165c87c5fbaSopenharmony_ci  sigaction(SIGINT, &sa, NULL);
166c87c5fbaSopenharmony_ci  sigaction(SIGTERM, &sa, NULL);
167c87c5fbaSopenharmony_ci  /* So we do not exit on a SIGPIPE */
168c87c5fbaSopenharmony_ci  sa.sa_handler = SIG_IGN;
169c87c5fbaSopenharmony_ci  sigaction(SIGPIPE, &sa, NULL);
170c87c5fbaSopenharmony_ci
171c87c5fbaSopenharmony_ci  while (!quit) {
172c87c5fbaSopenharmony_ci
173c87c5fbaSopenharmony_ci    if (!(pdu = make_pdu(session, rand() & 0xfff)))
174c87c5fbaSopenharmony_ci      break;
175c87c5fbaSopenharmony_ci
176c87c5fbaSopenharmony_ci    coap_send(session, pdu);
177c87c5fbaSopenharmony_ci
178c87c5fbaSopenharmony_ci    tv.tv_sec = 5;
179c87c5fbaSopenharmony_ci    tv.tv_usec = 0;
180c87c5fbaSopenharmony_ci
181c87c5fbaSopenharmony_ci    select(0, 0, 0, 0, &tv);
182c87c5fbaSopenharmony_ci
183c87c5fbaSopenharmony_ci  }
184c87c5fbaSopenharmony_ci
185c87c5fbaSopenharmony_ci  coap_free_context(ctx);
186c87c5fbaSopenharmony_ci  coap_cleanup();
187c87c5fbaSopenharmony_ci
188c87c5fbaSopenharmony_ci  return 0;
189c87c5fbaSopenharmony_ci}
190