Monthly Archive for June, 2016

If you caught my last post, you learned about compiling libnagios and using the Nagios library in your own code. This time we’re going to use that same Nagios library along with some borrowed NDOUtils code and build something super neat: a message passing system utilizing key-value vectors and buffers attached to the kernel messaging (IPC) utilities from NDO.

Just like last time, I’m going to assume you have a sane build environment set up (where tools like make and ./configure are working) before we go any further. If you are following along, now would be the time to get these in order.

First, open up queue.c in your favorite editor and delete the line that includes “../include/config.h” (we’ll manually include the headers we need in a bit). You’ll want to change the path to your queue.h file to reflect wherever you downloaded it. For the purposes of this post and the examples that follow, all of my source and header files will be in the root directory of the Nagios Core source code that we downloaded while following along with the last post.

So, the top of your queue.c should have looked like this when you downloaded it:

1

2

3

4

#include "../include/config.h"

#include "../include/queue.h"

#include <sys/ipc.h>

#include <sys/msg.h>

After you’ve made the changes I mentioned, it should look like this:

1

2

3

#include "queue.h"

#include <sys/ipc.h>

#include <sys/msg.h>

Save that file and open up queue.h. We’re going to add all of the necessary header files that would have been included with config.h in here. Find the line that defines NDOUTILS_INCLUDE_QUEUE_H, and directly after it add the following include directives:

1

2

3

4

5

6

7

#include <syslog.h>

#include <string.h>

#include <errno.h>

#include <stdio.h>

#include <signal.h>

#include <stdlib.h>

#include <unistd.h>

By now, the top of your queue.h file should look like this:

1

2

3

4

5

6

7

8

9

10

11

12

#ifndef NDOUTILS_INCLUDE_QUEUE_H

#define NDOUTILS_INCLUDE_QUEUE_H

#include <syslog.h>

#include <string.h>

#include <errno.h>

#include <stdio.h>

#include <signal.h>

#include <stdlib.h>

#include <unistd.h>

#define NDO_QUEUE_PATH "."

Perfect! Now we’re going to set up our main application. Last time I walked through the file as we were creating it, but this time it’s a tad more advanced so we’re going to look at it in its entirety and then step through the explanation. Create a file named test2.c, and fill it with the following content:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

#include "lib/libnagios.h"

#include "queue.h"

/* function for walking a kvv and performing this function on each key/value */

staticintwalker(structkey_value*kv,void*discard){

/* all we care about is printing the values to the screen */

printf("walking kvv,key:%s,value:%s\n",kv->key,kv->value);

return0;

}

intmain(void){

/* these will be used for distinguishing key/value pairs and sets */

charKEYVAL_SEP='=';

charPAIR_SEP=';';

intOVERALLOC=2;

/* some keys and values */

constchar*keyval[]={

"key1=value1",

"foo=bar",

"nagios=rules"

};

intkeyval_len=3;

/* setup some key value vectors and initialize 1, save the other 2 for later */

structkvvec*kvv,*kvv_from_msg_queue;

structkvvec_buf*kvv_buf;

kvv=kvvec_create(keyval_len);

/* add our keys and values to the vector */

inti;

for(i=0;i<keyval_len;i++){

char*arg=strdup(keyval[i]);

char*eq=strchr(arg,'=');

if(eq)

*eq++=0;

kvvec_addkv(kvv,strdup(arg),strdup(eq));

free(arg);/* eq is destroyed here as well */

}

/* lets print the keys and values */

printf("\nprinting keys andvalues of kvv\n");

kvvec_foreach(kvv,NULL,walker);

/* now lets sort it and print it one more time */

printf("\nsorting thenprinting keys andvalues of kvv\n");

kvvec_sort(kvv);

kvvec_foreach(kvv,NULL,walker);

/* now lets add kvv to kvv_buf so that we can put it in the kernel msg queue */

kvv_buf=kvvec2buf(kvv,KEYVAL_SEP,PAIR_SEP,OVERALLOC);

/* set up a queue using our borrowed ndo2db queue code */

ndo2db_queue_init(getpid());

/* initialize a message with our kvv_buf data and send it to the queue */

structndo2db_queue_msg msg;

strcpy(msg.text,kvv_buf->buf);

ndo2db_queue_send(&msg,kvv_buf->buflen);

/* get our message out of the queue and turn it back into a key value vector */

/* function for walking a kvv and performing this function on each key/value */

staticintwalker(structkey_value*kv,void*arg){

/* all we care about is printing the values to the screen */

printf("walking kvv,key:%s,value:%s\n",kv->key,kv->value);

return0;

}

Now we’re going to start our application and define a few parameters to be used later. KEYVAL_SEP will be the separating character used to determine key from values. PAIR_SEP will be the separating character to keep key-value pairs separate from each other. OVERALLOC will be used to determine how much extra space is allocated when we create our vector. Then we go ahead and set up a basic char * buffer with our key-value data and set keyval_len equal to how many [key-values] we have there.

Remember the function we defined that was going to “walk” through the key-value vector and perform a meaningful operation against each key-value pair? We’re going to call it now, and as it walks through each key-value, it will print both elements.