How to write a message logger in C

You are probably here because some demanding professor has ordered you to produce an example of a program that recieves messages and pulses and logs stuff about them.

Here I will provide the answer to all your questions. Well, some of your questions.

I can’t, for example, tell you why you decided to take this stupid degree in the first place.
I can’t tell you where to find true love, or the secret of happiness.

I can’t even tell you how to code – I can attempt to give you some information, but everyone basically has to teach themselves how to program. Also, I apologize for the formatting – wordpress’s text editor is literally the worst thing in the universe.

Oh well, read on if you must.
First, some inclusions. The usual suspects – we’ll need the ability to write to the command line, concatenate a string, make timestamps.

1

2

3

4

5

6

7

8

#include &lt;stdio.h&gt;

#include &lt;sys/neutrino.h&gt;

#include "msg.h"

#include &lt;stdlib.h&gt;

#include &lt;string.h&gt;

#include &lt;sys/netmgr.h&gt;

#include &lt;process.h&gt;

#include &lt;time.h&gt;

“msg.h” is a header file provided by my teacher. There’s a bunch of stuff in there, but the important bits are:

1

2

3

4

typedefstruct{

MSG_HEADER m_hdr;

MSG_TYPE m_data[MSG_SIZE];

}MESSAGE_CLIENT;

1

2

3

4

typedefunion{

MESSAGE_CLIENT client;

struct_pulse pulse;

}MESSAGE;

The message header can be accessed by theMessage.m_hdr. Pulses can send codes, and this particular pulse code can be accessed with theMessage.pulse.code. I can’t remember what the rest of the includes are for. I might’ve copied them from a different lab.

Begin!

1

intmain(intargc,char*argv[]){

1

printf("Server running.\n");

First, we’re going to need a bunch of variables.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

intchid;

//channel id - this is how you refer to the client

//program that's sending you messages.

struct_msg_info theClient;

//a structure for holding all other information about the client.

MESSAGE theMessage;

//That's teacher's header file being used.

charreply[512];

//a place to store the acknowledgement back to the client.

intrcvid;

//unique id generated by MsgRecieve, which you can use to

//reply to a message. that way the client knows which

//message you're talking about.

intrepBytes;

//Not sure about this one.

1

2

3

4

5

6

7

8

9

FILE *logfile;

//where you're going to log the messages you get.

FILE *pidfile;

//where the pid, nd, ad chid will be written, I can't

//remember why that's necessary.

char*pidFileName=malloc(strlen(argv[0])+5);

//just a handle to refer to the pidfile.

1

2

time_t timestruct;

//used for timestamping each log entry.

You could probably write a better usage message. This just means that the program was called with too few arguements – no logfile was specified, so it doesn’t know where to store logs.

1

2

3

4

if(argc!=2){

printf("Usage!");

exit(EXIT_FAILURE);

}

Establish a connection to whatever client program is trying to get ahold of you. This function will not execute until the client shows up.

1

chid=ChannelCreate(0);

When the client does show up, its process id, channel id and node descriptor will be recorded in the pidfile, via this bit:

1

2

3

4

5

6

strcpy(pidFileName,argv[0]);

strcat(pidFileName,".pid");

pidfile=fopen(pidFileName,"w");

fprintf(pidfile,"%d %d %d \n",ND_LOCAL_NODE,getpid(),chid);

fclose(pidfile);

free(pidFileName);

Then open the logfile to record whatever messages the client wants to send.

1

logfile=fopen(argv[1],"w");

At this point, you’re going to start an infinite while loop. It will keep running as long as the client wants to keep sending messages. It only terminates when the client sends a pulse.

In each iteration of the while loop, the logger looks for a new message and stores it at theMessage’s memory location. The timestruct initalization doesn’t have to be in the while loop, but there it is. It does have to exist though, cause if you don’t initialize the timestruct then it will just claim that it’s Jan 1 1970. You can pass arguments to specify a time format, or just send it null for the default.

Next is a switch to check the message header to see what sort of thing it is.

If it’s a regular message, it’ll have a unique rcvid.

If it’s a pulse, the rcvid will be 0, since you don’t need to reply to pulses. The whole idea of a pulse is that it’s non-blocking – it doesn’t wait for a reply. Kinda like HTTP, in that pulses sends out messages and hope for the best. If no acknowledgement arrives after while it just gives up./li>

1

2

3

4

5

6

7

8

9

switch(theMessage.m_hdr){

case(MSG_DATA):

fprintf(logfile,"%s %s \n",ctime(&amp;timestruct),theMessage.m_data);

printf("Message logged. \n");

strcpy(reply,"Message logged. \n");

repBytes=sizeof(reply);

MsgReply(rcvid,MSG_OK,reply,repBytes);

fflush(logfile);

break;

The first case, a proper message arrives. Report on the command line that something happened, and log the item and the date. Reply with an acknowledgement that the message is fine, flush the buffer, and carry on.

1

2

3

4

5

6

7

case(MSG_END):

fprintf(logfile,"%s Pulse recieved - server exited.\n",

ctime(&amp;timestruct));

MsgReply(rcvid,MSG_END,NULL,NULL);

fflush(logfile);

running=0;

break;

In this program, we’re using pulses to terminate the logger program. So if a pulse arrives,

You know it’s a pulse because the theMessage.m_hdr == 0, though it’s translated to the enum MSG_ENG for the sake of readability.

1

2

3

4

default:

fprintf(logfile,"Warning: invalid message format received.\n");

MsgReply(rcvid,MSG_INVALID,NULL,NULL);

break;

If anything other than a pulse or a valid message turns up, the logger just shrugs and carries on.

And that’s basically it – just clean up and exit.

1

2

3

4

5

6

7

8

9

}

}

fclose(logfile);

printf("Sever exited. \n\n");

return0;

}

The Complete Code

I hope it’s helpful. I also hope you actually understand it, rather than just turning it in as is.