• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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) */
37 COAP_STATIC_INLINE unsigned char
COAP_PSEUDOFP_ENCODE_8_4_DOWN(unsigned int v,int * ls)38 COAP_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 
46 static int quit = 0;
47 
48 /* SIGINT handler: set quit to 1 for graceful termination */
49 static void
handle_sigint(int signum COAP_UNUSED)50 handle_sigint(int signum COAP_UNUSED) {
51   quit = 1;
52 }
53 
54 static coap_pdu_t *
make_pdu(coap_session_t * session,unsigned int value)55 make_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 
73 static void
usage(const char * program)74 usage(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 
88 static coap_session_t *
get_session(coap_context_t * ctx,const char * group)89 get_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 
136 int
main(int argc,char ** argv)137 main(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