/**************************************************************/ /* Multicast listener (server) */ /* */ /* Activation using: {program name} {Multicast IP} {port} */ /* {program name} - This program name */ /* {Multicast IP} - The IP address to listen to (Class D) */ /* {port} - The port hnumber to listen on */ /* {gpio} - gpio pin number for output */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* This is free software released under the GPL license. */ /* See the GNU GPL for details. */ /* */ /* (c) Juan-Mariano de Goyeneche. 1998, 1999. */ /**************************************************************/ #include /* printf(), snprintf() */ #include /* strtol(), exit() */ #include #include /* perror() */ #include /* fork(), sleep() */ #include /* uname() */ #include /* memset() */ #include /* openlog(), syslog() */ #include "gpiosysfs.h" #include //signal(3) #include //umask(3) #include #include #include #include #include "mosquitto.h" #define DEBUG #define MAXLEN 1024 #ifdef DEBUG #define LOG(...) do { printf(__VA_ARGS__); } while (0) #else #define LOG(...) #endif /* How many seconds the broker should wait between sending out * keep-alive messages. */ #define KEEPALIVE_SECONDS 60 /* Hostname and port for the MQTT broker. */ char *mqtt_host; int port; char *topic; char *pin; int timeout; bool debug=false; int daemonize(char* name, char* path, char* outfile, char* errfile, char* infile , char* pidfile) { char filename[64]; FILE *pf; if(!path) { path="/"; } if(!name) { name="medaemon"; } if(!infile) { infile="/dev/null"; } if(!outfile) { outfile="/dev/null"; } if(!errfile) { errfile="/dev/null"; } if(!pidfile) { snprintf(filename,63,"/var/run/%s.pid",name); pidfile = filename; } //printf("%s %s %s %s\n",name,path,outfile,infile); pid_t child; //fork, detach from process group leader if( (child=fork())<0 ) { //failed fork fprintf(stderr,"error: failed fork\n"); exit(EXIT_FAILURE); } if (child>0) { //parent exit(EXIT_SUCCESS); } if( setsid()<0 ) { //failed to become session leader fprintf(stderr,"error: failed setsid\n"); exit(EXIT_FAILURE); } //catch/ignore signals signal(SIGCHLD,SIG_IGN); signal(SIGHUP,SIG_IGN); //fork second time if ( (child=fork())<0) { //failed fork fprintf(stderr,"error: failed fork\n"); exit(EXIT_FAILURE); } if( child>0 ) { //parent exit(EXIT_SUCCESS); } //new file permissions umask(0); //change to path directory chdir(path); // open pid file pf = fopen(pidfile,"w+"); if (pf == NULL) { fprintf(stderr,"error: failed open pid file\n"); exit(EXIT_FAILURE); } else { fprintf(pf,"%d",getpid()); fclose(pf); } //Close all open file descriptors int fd; for( fd=sysconf(_SC_OPEN_MAX); fd>0; --fd ) { close(fd); } //reopen stdin, stdout, stderr freopen(infile,"r",stdin); //fd=0 freopen(outfile,"w+",stdout); //fd=1 freopen(errfile,"w+",stderr); //fd=2 //open syslog openlog(name,LOG_PID,LOG_DAEMON); syslog (LOG_DAEMON, "Program started by User %d", getuid ()); return(0); } void beep() { gpioWrite(pin,"1"); msleep(timeout); gpioWrite(pin,"0"); msleep(timeout); } struct client_info { struct mosquitto *m; pid_t pid; uint32_t tick_ct; }; static void die(const char *msg); static struct mosquitto *init(struct client_info *info); static bool set_callbacks(struct mosquitto *m); static bool connect(struct mosquitto *m); static int run_loop(struct client_info *info); /* Fail with an error message. */ static void die(const char *msg) { fprintf(stderr, "%s", msg); exit(1); } /* Initialize a mosquitto client. */ static struct mosquitto *init(struct client_info *info) { void *udata = (void *)info; size_t buf_sz = 32; char buf[buf_sz]; if (buf_sz < snprintf(buf, buf_sz, "bellrecv_%d", info->pid)) { return NULL; /* snprintf buffer failure */ } /* Create a new mosquitto client, with the name "client_#{PID}". */ LOG("Init\n"); mosquitto_lib_init(); struct mosquitto *m = mosquitto_new(buf, true, udata); return m; } /* Callback for successful connection: add subscriptions. */ static void on_connect(struct mosquitto *m, void *udata, int res) { if (res == 0) { /* success */ LOG("connecion successfull\n"); //struct client_info *info = (struct client_info *)udata; mosquitto_subscribe(m, NULL, topic, 0); } else { die("connection refused\n"); } } /* A message was successfully published. */ static void on_publish(struct mosquitto *m, void *udata, int m_id) { LOG("-- published successfully\n"); } static bool match(const char *topic, const char *key) { return 0 == strncmp(topic, key, strlen(key)); } /* Handle a message that just arrived via one of the subscriptions. */ static void on_message(struct mosquitto *m, void *udata, const struct mosquitto_message *msg) { if (msg == NULL) { LOG("-- message NULL\n"); return; } LOG("-- got message @ %s: (%d, QoS %d, %s) '%s'\n", msg->topic, msg->payloadlen, msg->qos, msg->retain ? "R" : "!r", (char *)msg->payload); struct client_info *info = (struct client_info *)udata; syslog(LOG_DAEMON, "Bell message recived: '%s' -> '%s'", msg->topic, (char *)msg->payload); if (match(msg->topic, topic)) { if (0 == strncmp(msg->payload, "BELL:", 5)) { LOG("%s %d\n",(char *)msg->payload, info->pid); syslog (LOG_DAEMON, "Bell ringing by message: %s",(char *)msg->payload); if (debug == false) beep(); } else { LOG("invalid message: '%s' excepted 'BELL:'\n",(char *)msg->payload); } } } /* Successful subscription hook. */ static void on_subscribe(struct mosquitto *m, void *udata, int mid, int qos_count, const int *granted_qos) { LOG("-- subscribed successfully on topic: '%s'\n",topic); syslog (LOG_DAEMON, "Bell subscibed on topic %s" ,topic); } /* Register the callbacks that the mosquitto connection will use. */ static bool set_callbacks(struct mosquitto *m) { mosquitto_connect_callback_set(m, on_connect); mosquitto_publish_callback_set(m, on_publish); mosquitto_subscribe_callback_set(m, on_subscribe); mosquitto_message_callback_set(m, on_message); return true; } /* Connect to the network. */ static bool connect(struct mosquitto *m) { int res = mosquitto_connect(m, mqtt_host, port, KEEPALIVE_SECONDS); return res == MOSQ_ERR_SUCCESS; } /* Loop until it is explicitly halted or the network is lost, then clean up. */ static int run_loop(struct client_info *info) { int res = mosquitto_loop_forever(info->m, 1000, 1000 /* unused */); mosquitto_destroy(info->m); (void)mosquitto_lib_cleanup(); closelog(); if (res == MOSQ_ERR_SUCCESS) { return 0; } else { return 1; } } int main(int argc, char* argv[]) { int res; if (argc < 6) { fprintf(stderr, "Usage: %s mqtt_host port topic gpio seconds [debug]\n", argv[0]); exit(1); } mqtt_host = argv[1]; port = atoi(argv[2]); topic = argv[3]; pin = argv[4]; timeout = atoi(argv[5])*1000; //To milis if (argc == 6) { if( (res=daemonize("bellring","/tmp",NULL,NULL,NULL,NULL)) != 0 ) { fprintf(stderr,"error: daemonize failed\n"); exit(EXIT_FAILURE); } } else { debug = true ;}; if (debug == false) gpioSetup(pin); pid_t pid = getpid(); struct client_info info; memset(&info, 0, sizeof(info)); info.pid = pid; struct mosquitto *m = init(&info); if (m == NULL) { die("init() failure\n"); } info.m = m; if (!set_callbacks(m)) { die("set_callbacks() failure\n"); } if (!connect(m)) { die("connect() failure\n"); } return run_loop(&info); }