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