-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdaemon.c
329 lines (278 loc) · 7.42 KB
/
daemon.c
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <pty.h>
#include <time.h>
#define TABLESIZE 10000000
#define DBLINESIZE 13 //this should be the real size of the db string without a newline or null termination character
#define BAUDRATE B9600
#define _POSIX_SOURCE 1
#define FALSE 0
#define TRUE 1
#define VERSION "0.1"
//#define TESTING 1
struct simple_rfid_access {
char *cardnum;
char hashval;
char collisioncnt;
struct simple_rfid_access *next;
} db[TABLESIZE];
char *ans;
char *device;
int fd, logp;
char *version = VERSION;
struct termios oldtio;
void signal_handler_IO(int status);
unsigned int
hash(char *ch) {
unsigned int hashvalue = 0;
if(!*ch) return 0;
do {
hashvalue += *ch++;
hashvalue *= 13;
} while (*ch);
return(hashvalue % TABLESIZE);
}
void
signal_handler_IO(int status) {
char buf[50];
char str[DBLINESIZE];
char logbuf[256];
int h,i,j;
char ans = '0';
char station_id = '0';
char ansstr[4];
memset(logbuf, '\0', sizeof(logbuf));
memset(buf, '\0', sizeof(buf));
memset(str, '\0', sizeof(str));
read(fd, buf, 50);
tcflush(fd, TCIFLUSH);
j=0;
for(i=0; j<DBLINESIZE; i++) {
if(buf[i]==3 || buf[i]==2 || buf[i]==10) { continue; }
if(i==2) { station_id = buf[i]; continue; }
str[j++] = buf[i];
}
str[DBLINESIZE-1] = '\0';
if(strlen(str) < DBLINESIZE-1) {
ans = '3';
goto error_condition;
}
h=hash(str);
if(h >= TABLESIZE) {
ans = '4';
goto error_condition;
}
struct simple_rfid_access rf = db[h];
while(1) {
if(strcmp(rf.cardnum,str) == 0) { ans = db[h].hashval; break; }
else if(rf.next != NULL) {
rf = *(rf.next);
}
else {
ans = '5';
break;
}
}
error_condition:
if(strcmp(str, "3400C2DF0B22") == 0){ans='1';}//this is the admin key in case the database is destroyed or unavailable
sprintf(logbuf, "IO HANDLER -- received: %s +++ answered with: %c", str, ans);
logdaemonevent(logbuf);
sprintf(ansstr, "%c@%c", ans, station_id);
write(fd, ansstr, 3);
}
void
clear() {
struct simple_rfid_access rfiddb;
int i;
rfiddb.cardnum = "";
rfiddb.hashval = 0;
rfiddb.next = NULL;
for(i=0; i<TABLESIZE; i++) {
db[i] = rfiddb;
}
}
int
load(int argc, char **argv) {
#ifdef TESTING
/* for testing only */
int i,h, collisioncnt;
for(i=1; i<5000; i++) {
char *n = calloc(5, sizeof(char));
sprintf(n, "%i", i);
h = hash(n);
if(strcmp(n, db[h].cardnum) == 0) {
//collision!
struct simple_rfid_access *rfiddb = calloc(1, sizeof(struct simple_rfid_access));
db[h].next = rfiddb;
rfiddb->cardnum = n;
rfiddb->collisioncnt++;
rfiddb->hashval = '1'; //just hardcoded to 'yes'
}
else {
db[h].cardnum = n;
db[h].hashval = '1';
db[h].collisioncnt = 0;
}
}
/* end test */
#else
FILE *fp;
char *str;
char buf[DBLINESIZE+1];
int h, collisioncnt;
char ans;
char logentry[256];
if(argc>2) {
fp = fopen(argv[2], "r");
device = argv[1];
}
else {
fp = fopen("./db_real.txt", "r");
device = "/dev/ttyS0";
}
if(fp == NULL) {
printf("failed to open database.\n");
exit(EXIT_FAILURE);
}
while(fgets(buf, sizeof(buf), fp)) {
if(*buf == '\n') continue;
//this memory never gets freed and shouldn't
str = calloc(DBLINESIZE, sizeof(char));
strncpy(str, buf, strlen(buf)-1);
ans = buf[strlen(buf)-1];
h=hash(str);
if(strcmp(db[h].cardnum, str) == 0) {
sprintf(logentry, "\nhash collision for hash: %i from card number: %s creating linked list member.\n", h, str);
logdaemonevent(logentry);
//this memory never gets freed and shouldn't
struct simple_rfid_access *rfiddb = calloc(1, sizeof(struct simple_rfid_access));
rfiddb->cardnum = str;
rfiddb->hashval = ans;
rfiddb->collisioncnt++;
db[h].next = rfiddb;
}
else {
db[h].cardnum = str; //need to allocate memory here!
db[h].hashval = ans;
db[h].collisioncnt = 0;
}
}
return fclose(fp);
#endif
}
int
opendaemonlog() {
logp = open("/var/log/rfid_daemon.log", O_RDWR | O_APPEND);
if(logp < 0) {
printf("failed to open log file: /var/log/rfid_daemon.log");
exit(EXIT_FAILURE);
}
return 1;
}
int closedaemonlog() {
close(logp);
return 1;
}
int
logdaemonevent(char *event) {
char log[256];
log[0] = '\0';
time_t t = time(NULL);
char *logtime = ctime(&t);
logtime[strlen(logtime)-1] = ' ';
logtime[strlen(logtime)] = '\0';
strcat(log, logtime);
strcat(log, event);
strcat(log, "\n");
write(logp, log, strlen(log));
return 1;
}
int
dumpdatabase() {
logdaemonevent("starting dump of db\n");
int i,n;
n=0;
for(i=0; i<TABLESIZE; i++) {
if(strcmp(db[i].cardnum,"") != 0) {
char s[100];
sprintf(s, "key: %i --- value: ( cardnum - %s, answer - %c, number of collisions - %i )", i, db[i].cardnum, db[i].hashval, db[i].collisioncnt);
logdaemonevent(s);
n++;
}
}
char f[256];
sprintf(f, "ending dump of db\n\nbrought in: %d records.\n\n", n);
logdaemonevent(f);
return 1;
}
void
cleanup(int sig) {
tcsetattr(fd,TCSANOW,&oldtio);
close(fd);
closedaemonlog();
system("killall daemon");
(void) signal(SIGINT, SIG_DFL);
}
int
main(int argc, char **argv) {
struct termios newtio;
struct sigaction saio;
pid_t pid, sid;
sigset_t st;
(void) signal(SIGINT, cleanup);
char logentry[256];
opendaemonlog(); //this could make the app fail if there is no log file, watch stdout
clear();
load(argc, argv);
sprintf(logentry, "Starting rfid serial daemon, version %s", version);
logdaemonevent(logentry);
dumpdatabase();
pid = fork();
if(pid < 0) { logdaemonevent("failed to fork daemon event handler process."); exit(EXIT_FAILURE); }
if(pid > 0) { logdaemonevent("forked daemon event handler process."); exit(EXIT_SUCCESS); }
umask(0);
sid = setsid();
if (sid < 0) { logdaemonevent("sid of daemon event handler less than 0."); exit(EXIT_FAILURE);}
if((chdir("/")) < 0) { logdaemonevent("daemon event handler: could not chdir to /."); exit(EXIT_FAILURE);}
close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO);
/* open the device to be non-blocking (read will return immediately) */
fd = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK);
if(fd<0) { logdaemonevent("failed to open serial device."); perror(device); exit(EXIT_FAILURE); }
/* install the signal handler before making the device asynchronous */
saio.sa_handler = signal_handler_IO;
saio.sa_mask = st;
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction(SIGIO,&saio,NULL);
/* allow the process to receive SIGIO */
char buff[10];
sprintf(buff, "pid of event handler: %i", getpid());
logdaemonevent(buff);
fcntl(fd, F_SETOWN, getpid());
fcntl(fd, F_SETFL, FASYNC);
tcgetattr(fd,&oldtio); /* save current port settings */
/* set new port settings for canonical input processing */
newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR | ICRNL;
newtio.c_oflag = 0;
newtio.c_lflag = ICANON;
newtio.c_cc[VMIN]=1;
newtio.c_cc[VTIME]=0;
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
while (1) {
usleep(100000);
}
exit(EXIT_SUCCESS);
}