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