Fix poll returning earlier than it should.
[supybot_NagiosLogger.git] / scripts / client.c
blob70a1ac611196d688e14a07174161c93201aa86d6
1 /* NagiosLogger C Client
2 * Version 0.91
3 * Author: Thomas Guyot-Sionnest <tguyot@gmail.com>
5 * Dev build:
6 * gcc -Wall -lzmq -o client client.c
8 * Normal build:
9 * gcc -O2 -DNDEBUG -lzmq -o client client.c && strip client
13 /* This is the send timeout in microseconds */
14 #define SEND_TIMEOUT 1000000 /* 1 second */
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <assert.h>
19 #include <string.h>
20 #include <sys/time.h>
21 #include <time.h>
22 #include <zmq.h>
25 /* wrapper around zmq_poll which may return zero without reaching the
26 * specified timeout */
27 int
28 my_zmqpoll(zmq_pollitem_t *items, const int nitems, const long timeout)
30 struct timeval tv, te;
31 int rc, ret;
32 long tmleft;
34 /* Populate te with timeout value */
35 te.tv_sec = timeout / 1000000;
36 te.tv_usec = timeout - (te.tv_sec * 1000000);
38 rc = gettimeofday(&tv, NULL);
39 assert(rc == 0);
41 /* Add current time to the timeout (end time) */
42 te.tv_sec += tv.tv_sec;
43 te.tv_usec += tv.tv_usec;
44 te.tv_sec += te.tv_usec / 1000000;
45 te.tv_usec %= 1000000;
47 /* Loop over, return either >0, or 0 after a timeout */
48 tmleft = timeout;
49 while (1) {
50 ret = zmq_poll(items, nitems, tmleft);
51 assert(ret >= 0);
53 rc = gettimeofday(&tv, NULL);
54 assert(rc == 0);
56 if (ret == 0) {
57 /* Keep on looping unless time's up */
58 if (te.tv_sec < tv.tv_sec ||
59 (te.tv_sec == tv.tv_sec && te.tv_usec <= tv.tv_usec))
60 return ret;
61 tmleft = ((te.tv_sec - tv.tv_sec) * 1000000) + (te.tv_usec - tv.tv_usec);
62 } else {
63 return ret;
69 /* Send formatted message to url */
70 int
71 logevent(const char *url, const char *message)
73 int rc, result;
74 void *ctx, *socket;
75 zmq_msg_t query;
76 zmq_pollitem_t items[1];
78 /* Send the message */
79 rc = zmq_msg_init_size(&query, strlen(message));
80 assert(rc == 0);
82 memcpy(zmq_msg_data(&query), message, strlen(message));
84 ctx = zmq_init (1, 1, ZMQ_POLL);
85 assert(ctx);
87 socket = zmq_socket(ctx, ZMQ_REQ);
88 assert(socket);
90 rc = zmq_connect(socket, url);
91 assert(rc == 0);
93 rc = zmq_send(socket, &query, 0);
94 assert(rc == 0);
96 zmq_msg_close(&query);
98 /* Wait for a reply */
99 rc = zmq_msg_init(&query);
100 assert(rc == 0);
102 items[0].socket = socket;
103 items[0].events = ZMQ_POLLIN;
104 rc = my_zmqpoll(items, 1, SEND_TIMEOUT);
105 assert(rc >= 0);
107 rc = zmq_recv(socket, &query, ZMQ_NOBLOCK);
108 if (rc == -1 && errno == EAGAIN) {
109 result = 0;
110 } else {
111 assert(rc == 0);
112 zmq_msg_close(&query);
113 result = 1;
116 /* Clean up - FIXME: random SEGV on zmq_term
117 zmq_close(socket);
118 zmq_term(ctx);
121 return result;
124 /* Print usage and exit */
125 void
126 usage(const char *progname, const char *error_msg)
129 assert(progname != NULL);
130 if (error_msg)
131 printf("Error: %s\n", error_msg);
133 printf("\n");
134 printf("Usage: %s <ZMQ_URL> <Server> <Notification Type> <Service State ID> <Host> <Service Desc> <Message>\n", progname);
135 printf("Usage: %s <ZMQ_URL> <Server> <Notification Type> <Host State ID> <Host> <Message>\n", progname);
137 if (error_msg)
138 exit(1);
140 exit(0);
143 /* Parse arguments and format message */
145 main(int argc, char **argv)
147 int i, rc;
148 char *url, *server, *notype, *stateid, *host, *message;
149 char *fmt_msg = NULL;
150 char *service = NULL;
151 const char *paramtype = "";
153 if (argc < 7 || argc > 8) {
154 for (i=1; i<argc; i++) {
155 if (strcmp(argv[i], "-h") == 0 ||
156 strcmp(argv[i], "--help") == 0) {
157 usage(argv[0], NULL);
160 usage(argv[0], "Wrong number of arguments");
163 for (i=1; i<argc; i++) {
164 switch (i) {
165 case 1:
166 url = strdup(argv[i]);
167 break;
168 case 2:
169 server = strdup(argv[i]);
170 break;
171 case 3:
172 notype = strdup(argv[i]);
173 break;
174 case 4:
175 stateid = strdup(argv[i]);
176 if (strlen(stateid) != strspn(stateid, "0123456789"))
177 usage(argv[0], "State ID is not a number");
178 break;
179 case 5:
180 host = strdup(argv[i]);
181 break;
182 case 6:
183 if (argc == 7) {
184 message = strdup(argv[i]);
185 paramtype = "Host";
186 } else {
187 service = strdup(argv[i]);
188 paramtype = "Service";
190 break;
191 case 7:
192 message = strdup(argv[i]);
193 break;
197 /* Format is: server(str)[Tab]notificationtype(str)[Tab]stateid(int)[Tab]host(str)[Tab]service(str)[Tab]message(str) */
198 i = strlen(server) + strlen(notype) + strlen(stateid) + strlen(host) + (service ? strlen(service) : 0) + strlen(message) + 5 ;
199 fmt_msg = malloc(i+1);
200 assert(fmt_msg != NULL);
201 rc = snprintf(fmt_msg, i+1, "%s\t%s\t%s\t%s\t%s\t%s", server, notype, stateid, host, service ? service : "", message);
202 assert(rc == i);
204 if (logevent(url, fmt_msg)) {
205 printf("Successfully sent %s Alert event to %s\n", paramtype, url);
206 exit(0);
208 printf("Failed sending %s Alert event to %s\n", paramtype, url);
209 exit(1);