durable_rules 0.31.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,64 @@
1
+ require "sinatra"
2
+ require "json"
3
+
4
+ module Interface
5
+ class Application < Sinatra::Base
6
+ @@host = nil
7
+
8
+ def self.set_host(value)
9
+ @@host = value
10
+ end
11
+
12
+ get "/:ruleset_name/:sid" do
13
+ begin
14
+ JSON.generate @@host.get_state(params["ruleset_name"], params["sid"])
15
+ rescue Exception => e
16
+ status 404
17
+ e.to_s
18
+ end
19
+ end
20
+
21
+ post "/:ruleset_name/:sid" do
22
+ begin
23
+ request.body.rewind
24
+ message = JSON.parse request.body.read
25
+ message["sid"] = params["sid"]
26
+ @@host.post params["ruleset_name"], message
27
+ rescue Exception => e
28
+ status 500
29
+ e.to_s
30
+ end
31
+ end
32
+
33
+ patch "/:ruleset_name/:sid" do
34
+ begin
35
+ request.body.rewind
36
+ state = JSON.parse request.body.read
37
+ state["id"] = params["sid"]
38
+ @@host.patch_state params["ruleset_name"], state
39
+ rescue Exception => e
40
+ status 500
41
+ e.to_s
42
+ end
43
+ end
44
+
45
+ get "/:ruleset_name" do
46
+ begin
47
+ @@host.get_ruleset(params["ruleset_name"]).to_json
48
+ rescue Exception => e
49
+ status 404
50
+ e.to_s
51
+ end
52
+ end
53
+
54
+ post "/:ruleset_name" do
55
+ begin
56
+ request.body.rewind
57
+ @@host.set_ruleset params["ruleset_name"], JSON.parse(request.body.read)
58
+ rescue Exception => e
59
+ status 500
60
+ e.to_s
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,55 @@
1
+ OBJ=events.o json.o net.o rete.o state.o
2
+ LIBNAME=rules
3
+
4
+ # Fallback to gcc when $CC is not in $PATH.
5
+ CC:=$(shell sh -c 'type $(CC) >/dev/null 2>/dev/null && echo $(CC) || echo gcc')
6
+ OPTIMIZATION?=-O3
7
+ WARNINGS=-Wall
8
+ DEBUG?= -g -ggdb
9
+ REAL_CFLAGS=$(OPTIMIZATION) -fPIC $(CFLAGS) $(WARNINGS) $(DEBUG) $(ARCH)
10
+ REAL_LDFLAGS=$(LDFLAGS) $(ARCH)
11
+
12
+ REAL_CFLAGS+= -I../../deps/hiredis
13
+ REAL_LDFLAGS+= ../deps/hiredis/libhiredis.a
14
+
15
+ STLIBSUFFIX=a
16
+ STLIBNAME=$(LIBNAME).$(STLIBSUFFIX)
17
+ STLIB_MAKE_CMD=ar rcs $(STLIBNAME)
18
+
19
+ # Platform-specific overrides
20
+ uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
21
+ ifeq ($(uname_S),SunOS)
22
+ REAL_LDFLAGS+= -ldl -lnsl -lsocket
23
+ INSTALL= cp -r
24
+ endif
25
+
26
+ all: $(STLIBNAME)
27
+
28
+ # Deps (use make dep to generate this)
29
+ events.o: events.c rules.h net.h json.h
30
+ json.o: json.c json.h rules.h
31
+ net.o: net.c net.h rules.h json.h rete.h
32
+ rete.o: rete.c rete.h net.h json.h state.h
33
+ state.o: state.c state.h json.h net.h
34
+
35
+ $(STLIBNAME): $(OBJ)
36
+ $(STLIB_MAKE_CMD) $(OBJ)
37
+
38
+ static: $(STLIBNAME)
39
+
40
+ rules-%: %.o $(STLIBNAME)
41
+ $(CC) -o $@ $(REAL_LDFLAGS) $< $(STLIBNAME)
42
+
43
+ .c.o:
44
+ $(CC) -std=c99 -c $(REAL_CFLAGS) $<
45
+
46
+ clean:
47
+ rm -rf $(STLIBNAME) $(BINS) *.o *.gcda *.gcno *.gcov
48
+
49
+ gprof:
50
+ $(MAKE) CFLAGS="-pg" LDFLAGS="-pg"
51
+
52
+ noopt:
53
+ $(MAKE) OPTIMIZATION=""
54
+
55
+ .PHONY: all clean gprof gcov noopt
@@ -0,0 +1,1848 @@
1
+
2
+ #include <stdio.h>
3
+ #include <stdlib.h>
4
+ #include <string.h>
5
+ #include "rules.h"
6
+ #include "net.h"
7
+ #include "json.h"
8
+
9
+ #define MAX_EVENT_PROPERTIES 64
10
+ #define MAX_RESULT_NODES 32
11
+ #define MAX_NODE_RESULTS 16
12
+ #define MAX_STACK_SIZE 64
13
+ #define MAX_STATE_PROPERTY_TIME 2
14
+ #define MAX_COMMAND_COUNT 5000
15
+ #define MAX_ADD_COUNT 1000
16
+ #define MAX_EVAL_COUNT 1000
17
+
18
+ #define OP_BOOL_BOOL 0x0404
19
+ #define OP_BOOL_INT 0x0402
20
+ #define OP_BOOL_DOUBLE 0x0403
21
+ #define OP_BOOL_STRING 0x0401
22
+ #define OP_INT_BOOL 0x0204
23
+ #define OP_INT_INT 0x0202
24
+ #define OP_INT_DOUBLE 0x0203
25
+ #define OP_INT_STRING 0x0201
26
+ #define OP_DOUBLE_BOOL 0x0304
27
+ #define OP_DOUBLE_INT 0x0302
28
+ #define OP_DOUBLE_DOUBLE 0x0303
29
+ #define OP_DOUBLE_STRING 0x0301
30
+ #define OP_STRING_BOOL 0x0104
31
+ #define OP_STRING_INT 0x0102
32
+ #define OP_STRING_DOUBLE 0x0103
33
+ #define OP_STRING_STRING 0x0101
34
+
35
+ typedef struct actionContext {
36
+ void *rulesBinding;
37
+ redisReply *reply;
38
+ } actionContext;
39
+
40
+ typedef struct jsonResult {
41
+ unsigned int hash;
42
+ char *firstName;
43
+ char *lastName;
44
+ char *messages[MAX_MESSAGE_BATCH];
45
+ unsigned short messagesLength;
46
+ unsigned char childrenCount;
47
+ unsigned char children[MAX_NODE_RESULTS];
48
+ } jsonResult;
49
+
50
+ static unsigned int handleMessage(ruleset *tree,
51
+ char *state,
52
+ char *message,
53
+ unsigned char actionType,
54
+ char **commands,
55
+ unsigned int *commandCount,
56
+ void **rulesBinding);
57
+
58
+ static unsigned int reduceStateIdiom(ruleset *tree,
59
+ char *sid,
60
+ unsigned int idiomOffset,
61
+ char **state,
62
+ unsigned char *releaseState,
63
+ jsonProperty **targetValue);
64
+
65
+ static unsigned char compareBool(unsigned char left,
66
+ unsigned char right,
67
+ unsigned char op) {
68
+ switch(op) {
69
+ case OP_LT:
70
+ return (left < right);
71
+ case OP_LTE:
72
+ return 1;
73
+ case OP_GT:
74
+ return (left > right);
75
+ case OP_GTE:
76
+ return 1;
77
+ case OP_EQ:
78
+ return (left == right);
79
+ case OP_NEQ:
80
+ return (left != right);
81
+ }
82
+
83
+ return 0;
84
+ }
85
+
86
+ static unsigned char compareInt(long left,
87
+ long right,
88
+ unsigned char op) {
89
+ switch(op) {
90
+ case OP_LT:
91
+ return (left < right);
92
+ case OP_LTE:
93
+ return (left <= right);
94
+ case OP_GT:
95
+ return (left > right);
96
+ case OP_GTE:
97
+ return (left >= right);
98
+ case OP_EQ:
99
+ return (left == right);
100
+ case OP_NEQ:
101
+ return (left != right);
102
+ }
103
+
104
+ return 0;
105
+ }
106
+
107
+ static unsigned char compareDouble(double left,
108
+ double right,
109
+ unsigned char op) {
110
+ switch(op) {
111
+ case OP_LT:
112
+ return (left < right);
113
+ case OP_LTE:
114
+ return (left <= right);
115
+ case OP_GT:
116
+ return (left > right);
117
+ case OP_GTE:
118
+ return (left >= right);
119
+ case OP_EQ:
120
+ return (left == right);
121
+ case OP_NEQ:
122
+ return (left != right);
123
+ }
124
+
125
+ return 0;
126
+ }
127
+
128
+ static unsigned char compareString(char *leftFirst,
129
+ unsigned short leftLength,
130
+ char *right,
131
+ unsigned char op) {
132
+ char temp = leftFirst[leftLength];
133
+ leftFirst[leftLength] = '\0';
134
+ int result = strcmp(leftFirst, right);
135
+ leftFirst[leftLength] = temp;
136
+ switch(op) {
137
+ case OP_LT:
138
+ return (result < 0);
139
+ case OP_LTE:
140
+ return (result <= 0);
141
+ case OP_GT:
142
+ return (result > 0);
143
+ case OP_GTE:
144
+ return (result >= 0);
145
+ case OP_EQ:
146
+ return (result == 0);
147
+ case OP_NEQ:
148
+ return (result != 0);
149
+ }
150
+
151
+ return 0;
152
+ }
153
+
154
+ static unsigned char compareStringProperty(char *left,
155
+ char *rightFirst,
156
+ unsigned short rightLength,
157
+ unsigned char op) {
158
+ char temp = rightFirst[rightLength];
159
+ rightFirst[rightLength] = '\0';
160
+ int result = strcmp(left, rightFirst);
161
+ rightFirst[rightLength] = temp;
162
+ switch(op) {
163
+ case OP_LT:
164
+ return (result < 0);
165
+ case OP_LTE:
166
+ return (result <= 0);
167
+ case OP_GT:
168
+ return (result > 0);
169
+ case OP_GTE:
170
+ return (result >= 0);
171
+ case OP_EQ:
172
+ return (result == 0);
173
+ case OP_NEQ:
174
+ return (result != 0);
175
+ }
176
+
177
+ return 0;
178
+ }
179
+
180
+ static unsigned char compareStringAndStringProperty(char *leftFirst,
181
+ unsigned short leftLength,
182
+ char *rightFirst,
183
+ unsigned short rightLength,
184
+ unsigned char op) {
185
+
186
+ char rightTemp = rightFirst[rightLength];
187
+ rightFirst[rightLength] = '\0';
188
+ char leftTemp = leftFirst[leftLength];
189
+ leftFirst[leftLength] = '\0';
190
+ int result = strcmp(leftFirst, rightFirst);
191
+ rightFirst[rightLength] = rightTemp;
192
+ leftFirst[leftLength] = leftTemp;
193
+
194
+ switch(op) {
195
+ case OP_LT:
196
+ return (result < 0);
197
+ case OP_LTE:
198
+ return (result <= 0);
199
+ case OP_GT:
200
+ return (result > 0);
201
+ case OP_GTE:
202
+ return (result >= 0);
203
+ case OP_EQ:
204
+ return (result == 0);
205
+ case OP_NEQ:
206
+ return (result != 0);
207
+ }
208
+
209
+ return 0;
210
+
211
+ }
212
+
213
+ static long reduceInt(long left,
214
+ long right,
215
+ unsigned char op) {
216
+ switch(op) {
217
+ case OP_ADD:
218
+ return left + right;
219
+ case OP_SUB:
220
+ return left - right;
221
+ case OP_MUL:
222
+ return left * right;
223
+ case OP_DIV:
224
+ return left / right;
225
+ }
226
+
227
+ return 0;
228
+ }
229
+
230
+ static double reduceDouble(double left,
231
+ double right,
232
+ unsigned char op) {
233
+ switch(op) {
234
+ case OP_ADD:
235
+ return left + right;
236
+ case OP_SUB:
237
+ return left - right;
238
+ case OP_MUL:
239
+ return left * right;
240
+ case OP_DIV:
241
+ return left / right;
242
+ }
243
+
244
+ return 0;
245
+ }
246
+
247
+ static void freeCommands(char **commands,
248
+ unsigned int commandCount) {
249
+ for (unsigned int i = 0; i < commandCount; ++i) {
250
+ free(commands[i]);
251
+ }
252
+ }
253
+
254
+ static unsigned int handleAction(ruleset *tree,
255
+ char *sid,
256
+ char *mid,
257
+ char *prefix,
258
+ node *node,
259
+ unsigned char actionType,
260
+ char **evalKeys,
261
+ unsigned short *evalPriorities,
262
+ unsigned int *evalCount,
263
+ char **addKeys,
264
+ unsigned int *addCount,
265
+ char **removeCommand,
266
+ void **rulesBinding) {
267
+ unsigned int result = ERR_UNEXPECTED_VALUE;
268
+ if (*rulesBinding == NULL) {
269
+ result = resolveBinding(tree,
270
+ sid,
271
+ rulesBinding);
272
+ if (result != RULES_OK) {
273
+ return result;
274
+ }
275
+ }
276
+
277
+ switch (actionType) {
278
+ case ACTION_ASSERT_EVENT:
279
+ case ACTION_ASSERT_FACT:
280
+ case ACTION_RETRACT_EVENT:
281
+ case ACTION_RETRACT_FACT:
282
+ if (*evalCount == MAX_EVAL_COUNT) {
283
+ return ERR_MAX_EVAL_COUNT;
284
+ }
285
+
286
+ char *evalKey = malloc((strlen(prefix) + 1) * sizeof(char));
287
+ if (evalKey == NULL) {
288
+ return ERR_OUT_OF_MEMORY;
289
+ }
290
+
291
+ strcpy(evalKey, prefix);
292
+ unsigned int index = *evalCount;
293
+ while (index > 0 && node->value.c.priority < evalPriorities[index - 1]) {
294
+ evalKeys[index] = evalKeys[index - 1];
295
+ evalPriorities[index] = evalPriorities[index - 1];
296
+ --index;
297
+ }
298
+
299
+ evalKeys[index] = evalKey;
300
+ evalPriorities[index] = node->value.c.priority;
301
+ ++*evalCount;
302
+ break;
303
+
304
+ case ACTION_ADD_EVENT:
305
+ case ACTION_ADD_FACT:
306
+ if (*addCount == MAX_ADD_COUNT) {
307
+ return ERR_MAX_ADD_COUNT;
308
+ }
309
+ char *addKey = malloc((strlen(prefix) + 1) * sizeof(char));
310
+ if (addKey == NULL) {
311
+ return ERR_OUT_OF_MEMORY;
312
+ }
313
+
314
+ strcpy(addKey, prefix);
315
+ addKeys[*addCount] = addKey;
316
+ *addCount = *addCount + 1;
317
+ break;
318
+
319
+ case ACTION_REMOVE_EVENT:
320
+ case ACTION_REMOVE_FACT:
321
+ if (*removeCommand == NULL) {
322
+ result = formatRemoveMessage(*rulesBinding,
323
+ sid,
324
+ mid,
325
+ actionType == ACTION_REMOVE_FACT ? 1 : 0,
326
+ removeCommand);
327
+
328
+ if (result != RULES_OK) {
329
+ return result;
330
+ }
331
+ }
332
+ break;
333
+ }
334
+ return RULES_OK;
335
+ }
336
+
337
+ static unsigned int handleBeta(ruleset *tree,
338
+ char *sid,
339
+ char *mid,
340
+ node *betaNode,
341
+ unsigned short actionType,
342
+ char **evalKeys,
343
+ unsigned short *evalPriorities,
344
+ unsigned int *evalCount,
345
+ char **addKeys,
346
+ unsigned int *addCount,
347
+ char **removeCommand,
348
+ void **rulesBinding) {
349
+ int prefixLength = 0;
350
+ node *currentNode = betaNode;
351
+ while (currentNode != NULL) {
352
+ int nameLength = strlen(&tree->stringPool[currentNode->nameOffset]);
353
+ prefixLength += nameLength + 1;
354
+
355
+ if (currentNode->type == NODE_ACTION) {
356
+ currentNode = NULL;
357
+ } else {
358
+ if (currentNode->value.b.not) {
359
+ switch (actionType) {
360
+ case ACTION_ASSERT_FACT:
361
+ actionType = ACTION_ADD_FACT;
362
+ break;
363
+ case ACTION_ASSERT_EVENT:
364
+ actionType = ACTION_ADD_EVENT;
365
+ break;
366
+ case ACTION_REMOVE_FACT:
367
+ actionType = ACTION_RETRACT_FACT;
368
+ break;
369
+ case ACTION_REMOVE_EVENT:
370
+ actionType = ACTION_RETRACT_EVENT;
371
+ break;
372
+ }
373
+ }
374
+ currentNode = &tree->nodePool[currentNode->value.b.nextOffset];
375
+ }
376
+ }
377
+
378
+ node *actionNode = NULL;
379
+ #ifdef _WIN32
380
+ char *prefix = (char *)_alloca(sizeof(char)*(prefixLength));
381
+ #else
382
+ char prefix[prefixLength];
383
+ #endif
384
+ char *currentPrefix = prefix;
385
+ currentNode = betaNode;
386
+ while (currentNode != NULL) {
387
+ char *name = &tree->stringPool[currentNode->nameOffset];
388
+ int nameLength = strlen(&tree->stringPool[currentNode->nameOffset]);
389
+ strncpy(currentPrefix, name, nameLength);
390
+
391
+ if (currentNode->type == NODE_ACTION) {
392
+ currentPrefix[nameLength] = '\0';
393
+ actionNode = currentNode;
394
+ currentNode = NULL;
395
+ }
396
+ else {
397
+ currentPrefix[nameLength] = '!';
398
+ currentPrefix = &currentPrefix[nameLength + 1];
399
+ currentNode = &tree->nodePool[currentNode->value.b.nextOffset];
400
+ }
401
+ }
402
+ return handleAction(tree,
403
+ sid,
404
+ mid,
405
+ prefix,
406
+ actionNode,
407
+ actionType,
408
+ evalKeys,
409
+ evalPriorities,
410
+ evalCount,
411
+ addKeys,
412
+ addCount,
413
+ removeCommand,
414
+ rulesBinding);
415
+ }
416
+
417
+
418
+ static unsigned int valueToProperty(ruleset *tree,
419
+ char *sid,
420
+ jsonValue *sourceValue,
421
+ char **state,
422
+ unsigned char *releaseState,
423
+ jsonProperty **targetProperty) {
424
+
425
+ unsigned int result = RULES_OK;
426
+ *releaseState = 0;
427
+ switch(sourceValue->type) {
428
+ case JSON_STATE_IDIOM:
429
+ result = reduceStateIdiom(tree,
430
+ sid,
431
+ sourceValue->value.idiomOffset,
432
+ state,
433
+ releaseState,
434
+ targetProperty);
435
+
436
+ return result;
437
+ case JSON_STATE_PROPERTY:
438
+ if (sourceValue->value.property.idOffset) {
439
+ sid = &tree->stringPool[sourceValue->value.property.idOffset];
440
+ }
441
+ result = fetchStateProperty(tree,
442
+ sid,
443
+ sourceValue->value.property.hash,
444
+ MAX_STATE_PROPERTY_TIME,
445
+ 0,
446
+ state,
447
+ targetProperty);
448
+
449
+ if (result == ERR_STATE_NOT_LOADED || result == ERR_STALE_STATE) {
450
+ result = refreshState(tree,sid);
451
+ if (result != RULES_OK) {
452
+ return result;
453
+ }
454
+
455
+ result = fetchStateProperty(tree,
456
+ sid,
457
+ sourceValue->value.property.hash,
458
+ MAX_STATE_PROPERTY_TIME,
459
+ 0,
460
+ state,
461
+ targetProperty);
462
+ }
463
+
464
+ return result;
465
+ case JSON_STRING:
466
+ *state = &tree->stringPool[sourceValue->value.stringOffset];
467
+ (*targetProperty)->valueLength = strlen(*state);
468
+ (*targetProperty)->valueOffset = 0;
469
+ break;
470
+ case JSON_INT:
471
+ (*targetProperty)->value.i = sourceValue->value.i;
472
+ break;
473
+ case JSON_DOUBLE:
474
+ (*targetProperty)->value.d = sourceValue->value.d;
475
+ break;
476
+ case JSON_BOOL:
477
+ (*targetProperty)->value.b = sourceValue->value.b;
478
+ break;
479
+ }
480
+
481
+ (*targetProperty)->isMaterial = 1;
482
+ (*targetProperty)->type = sourceValue->type;
483
+ return result;
484
+ }
485
+
486
+ static unsigned int reduceProperties(unsigned char operator,
487
+ jsonProperty *leftProperty,
488
+ char *leftState,
489
+ jsonProperty *rightProperty,
490
+ char *rightState,
491
+ jsonProperty *targetValue,
492
+ char **state) {
493
+ *state = NULL;
494
+ unsigned short type = leftProperty->type << 8;
495
+ type = type + rightProperty->type;
496
+ char leftTemp = 0;
497
+ char rightTemp = 0;
498
+ if (leftProperty->type == JSON_STRING || rightProperty->type == JSON_STRING) {
499
+ if (operator != OP_ADD) {
500
+ asprintf(state, "");
501
+ return RULES_OK;
502
+ }
503
+
504
+ if (leftProperty->type == JSON_STRING) {
505
+ leftTemp = leftState[leftProperty->valueOffset + leftProperty->valueLength];
506
+ leftState[leftProperty->valueOffset + leftProperty->valueLength] = '\0';
507
+ }
508
+
509
+ if (rightProperty->type == JSON_STRING) {
510
+ rightTemp = rightState[rightProperty->valueOffset + rightProperty->valueLength];
511
+ rightState[rightProperty->valueOffset + rightProperty->valueLength] = '\0';
512
+ }
513
+ }
514
+
515
+ switch(type) {
516
+ case OP_BOOL_BOOL:
517
+ targetValue->value.i = reduceInt(leftProperty->value.b, rightProperty->value.b, operator);
518
+ targetValue->type = JSON_INT;
519
+ break;
520
+ case OP_BOOL_INT:
521
+ targetValue->value.i = reduceInt(leftProperty->value.b, rightProperty->value.i, operator);
522
+ targetValue->type = JSON_INT;
523
+ break;
524
+ case OP_BOOL_DOUBLE:
525
+ targetValue->value.d = reduceDouble(leftProperty->value.b, rightProperty->value.d, operator);
526
+ targetValue->type = JSON_DOUBLE;
527
+ break;
528
+ case OP_BOOL_STRING:
529
+ if (asprintf(state,
530
+ "%s%s",
531
+ leftProperty->value.b ? "true" : "false",
532
+ rightState + rightProperty->valueOffset) == -1) {
533
+ return ERR_OUT_OF_MEMORY;
534
+ }
535
+ break;
536
+ case OP_INT_BOOL:
537
+ targetValue->value.i = reduceInt(leftProperty->value.i, rightProperty->value.b, operator);
538
+ targetValue->type = JSON_INT;
539
+ break;
540
+ case OP_INT_INT:
541
+ targetValue->value.i = reduceInt(leftProperty->value.i, rightProperty->value.i, operator);
542
+ targetValue->type = JSON_INT;
543
+ break;
544
+ case OP_INT_DOUBLE:
545
+ targetValue->value.d = reduceDouble(leftProperty->value.i, rightProperty->value.d, operator);
546
+ targetValue->type = JSON_DOUBLE;
547
+ break;
548
+ case OP_INT_STRING:
549
+ if (asprintf(state,
550
+ "%ld%s",
551
+ leftProperty->value.i,
552
+ rightState + rightProperty->valueOffset) == -1) {
553
+ return ERR_OUT_OF_MEMORY;
554
+ }
555
+ break;
556
+ case OP_DOUBLE_BOOL:
557
+ targetValue->value.d = reduceDouble(leftProperty->value.d, rightProperty->value.b, operator);
558
+ targetValue->type = JSON_DOUBLE;
559
+ break;
560
+ case OP_DOUBLE_INT:
561
+ targetValue->value.d = reduceDouble(leftProperty->value.d, rightProperty->value.i, operator);
562
+ targetValue->type = JSON_DOUBLE;
563
+ break;
564
+ case OP_DOUBLE_DOUBLE:
565
+ targetValue->value.d = reduceDouble(leftProperty->value.d, rightProperty->value.d, operator);
566
+ targetValue->type = JSON_DOUBLE;
567
+ break;
568
+ case OP_DOUBLE_STRING:
569
+ if (asprintf(state,
570
+ "%g%s",
571
+ leftProperty->value.d,
572
+ rightState + rightProperty->valueOffset) == -1) {
573
+ return ERR_OUT_OF_MEMORY;
574
+ }
575
+
576
+ break;
577
+ case OP_STRING_BOOL:
578
+ if (asprintf(state,
579
+ "%s%s",
580
+ leftState + leftProperty->valueOffset,
581
+ rightProperty->value.b ? "true" : "false") == -1) {
582
+ return ERR_OUT_OF_MEMORY;
583
+ }
584
+ break;
585
+ case OP_STRING_INT:
586
+ if (asprintf(state,
587
+ "%s%ld",
588
+ leftState + leftProperty->valueOffset,
589
+ rightProperty->value.i) == -1) {
590
+ return ERR_OUT_OF_MEMORY;
591
+ }
592
+ break;
593
+ case OP_STRING_DOUBLE:
594
+ if (asprintf(state,
595
+ "%s%ld",
596
+ leftState + leftProperty->valueOffset,
597
+ rightProperty->value.i) == -1) {
598
+ return ERR_OUT_OF_MEMORY;
599
+ }
600
+ break;
601
+ case OP_STRING_STRING:
602
+ if (asprintf(state,
603
+ "%s%s",
604
+ leftState + leftProperty->valueOffset,
605
+ rightState + rightProperty->valueOffset) == -1) {
606
+ return ERR_OUT_OF_MEMORY;
607
+ }
608
+ break;
609
+ }
610
+
611
+ if (leftProperty->type == JSON_STRING || rightProperty->type == JSON_STRING) {
612
+ targetValue->type = JSON_STRING;
613
+ targetValue->valueOffset = 0;
614
+ targetValue->valueLength = strlen(*state);
615
+
616
+ if (leftTemp) {
617
+ leftState[leftProperty->valueOffset + leftProperty->valueLength] = leftTemp;
618
+ }
619
+
620
+ if (rightTemp) {
621
+ rightState[rightProperty->valueOffset + rightProperty->valueLength] = rightTemp;
622
+ }
623
+ }
624
+
625
+ return RULES_OK;
626
+ }
627
+
628
+ static unsigned int reduceStateIdiom(ruleset *tree,
629
+ char *sid,
630
+ unsigned int idiomOffset,
631
+ char **state,
632
+ unsigned char *releaseState,
633
+ jsonProperty **targetValue) {
634
+ unsigned int result = RULES_OK;
635
+ *releaseState = 0;
636
+ idiom *currentIdiom = &tree->idiomPool[idiomOffset];
637
+ jsonProperty leftValue;
638
+ jsonProperty *leftProperty = &leftValue;
639
+ unsigned char releaseLeftState = 0;
640
+ char *leftState = NULL;
641
+ result = valueToProperty(tree,
642
+ sid,
643
+ &currentIdiom->left,
644
+ &leftState,
645
+ &releaseLeftState,
646
+ &leftProperty);
647
+ if (result != RULES_OK) {
648
+ return result;
649
+ }
650
+
651
+ jsonProperty rightValue;
652
+ jsonProperty *rightProperty = &rightValue;
653
+ unsigned char releaseRightState = 0;
654
+ char *rightState = NULL;
655
+ result = valueToProperty(tree,
656
+ sid,
657
+ &currentIdiom->right,
658
+ &rightState,
659
+ &releaseRightState,
660
+ &rightProperty);
661
+ if (result != RULES_OK) {
662
+ if (releaseLeftState) {
663
+ free(leftState);
664
+ }
665
+
666
+ return result;
667
+ }
668
+
669
+ result = reduceProperties(currentIdiom->operator,
670
+ leftProperty,
671
+ leftState,
672
+ rightProperty,
673
+ rightState,
674
+ *targetValue,
675
+ state);
676
+
677
+ if (releaseLeftState) {
678
+ free(leftState);
679
+ }
680
+
681
+ if (releaseRightState) {
682
+ free(rightState);
683
+ }
684
+
685
+ if (state) {
686
+ *releaseState = 1;
687
+ }
688
+
689
+ return result;
690
+ }
691
+
692
+ static unsigned int isMatch(ruleset *tree,
693
+ char *sid,
694
+ char *message,
695
+ jsonProperty *currentProperty,
696
+ alpha *currentAlpha,
697
+ unsigned char *propertyMatch,
698
+ void **rulesBinding) {
699
+ unsigned char alphaOp = currentAlpha->operator;
700
+ unsigned char propertyType = currentProperty->type;
701
+ unsigned int result = RULES_OK;
702
+
703
+ *propertyMatch = 0;
704
+ if (alphaOp == OP_EX) {
705
+ *propertyMatch = 1;
706
+ return RULES_OK;
707
+ }
708
+
709
+ rehydrateProperty(currentProperty, message);
710
+ jsonProperty rightValue;
711
+ jsonProperty *rightProperty = &rightValue;
712
+ unsigned char releaseRightState = 0;
713
+ char *rightState = NULL;
714
+ result = valueToProperty(tree,
715
+ sid,
716
+ &currentAlpha->right,
717
+ &rightState,
718
+ &releaseRightState,
719
+ &rightProperty);
720
+ if (result != RULES_OK) {
721
+ if (releaseRightState) {
722
+ free(rightState);
723
+ }
724
+
725
+ if (result != ERR_NEW_SESSION && result != ERR_PROPERTY_NOT_FOUND) {
726
+ return result;
727
+ }
728
+
729
+ return RULES_OK;
730
+ }
731
+
732
+ int leftLength;
733
+ int rightLength;
734
+ unsigned short type = propertyType << 8;
735
+ type = type + rightProperty->type;
736
+ switch(type) {
737
+ case OP_BOOL_BOOL:
738
+ *propertyMatch = compareBool(currentProperty->value.b, rightProperty->value.b, alphaOp);
739
+ break;
740
+ case OP_BOOL_INT:
741
+ *propertyMatch = compareInt(currentProperty->value.b, rightProperty->value.i, alphaOp);
742
+ break;
743
+ case OP_BOOL_DOUBLE:
744
+ *propertyMatch = compareDouble(currentProperty->value.b, rightProperty->value.d, alphaOp);
745
+ break;
746
+ case OP_BOOL_STRING:
747
+ if (currentProperty->value.b) {
748
+ *propertyMatch = compareStringProperty("true",
749
+ rightState + rightProperty->valueOffset,
750
+ rightProperty->valueLength,
751
+ alphaOp);
752
+ }
753
+ else {
754
+ *propertyMatch = compareStringProperty("false",
755
+ rightState + rightProperty->valueOffset,
756
+ rightProperty->valueLength,
757
+ alphaOp);
758
+ }
759
+
760
+ break;
761
+ case OP_INT_BOOL:
762
+ *propertyMatch = compareInt(currentProperty->value.i, rightProperty->value.b, alphaOp);
763
+ break;
764
+ case OP_INT_INT:
765
+ *propertyMatch = compareInt(currentProperty->value.i, rightProperty->value.i, alphaOp);
766
+ break;
767
+ case OP_INT_DOUBLE:
768
+ *propertyMatch = compareDouble(currentProperty->value.i, rightProperty->value.d, alphaOp);
769
+ break;
770
+ case OP_INT_STRING:
771
+ {
772
+ rightLength = rightProperty->valueLength + 1;
773
+ #ifdef _WIN32
774
+ char *leftStringInt = (char *)_alloca(sizeof(char)*(rightLength));
775
+ sprintf_s(leftStringInt, rightLength, "%ld", currentProperty->value.i);
776
+ #else
777
+ char leftStringInt[rightLength];
778
+ snprintf(leftStringInt, rightLength, "%ld", currentProperty->value.i);
779
+ #endif
780
+ *propertyMatch = compareStringProperty(leftStringInt,
781
+ rightState + rightProperty->valueOffset,
782
+ rightProperty->valueLength,
783
+ alphaOp);
784
+ }
785
+ break;
786
+ case OP_DOUBLE_BOOL:
787
+ *propertyMatch = compareDouble(currentProperty->value.i, rightProperty->value.b, alphaOp);
788
+ break;
789
+ case OP_DOUBLE_INT:
790
+ *propertyMatch = compareDouble(currentProperty->value.i, rightProperty->value.i, alphaOp);
791
+ break;
792
+ case OP_DOUBLE_DOUBLE:
793
+ *propertyMatch = compareDouble(currentProperty->value.i, rightProperty->value.d, alphaOp);
794
+ break;
795
+ case OP_DOUBLE_STRING:
796
+ {
797
+ rightLength = rightProperty->valueLength + 1;
798
+ #ifdef _WIN32
799
+ char *leftStringDouble = (char *)_alloca(sizeof(char)*(rightLength));
800
+ sprintf_s(leftStringDouble, rightLength, "%f", currentProperty->value.d);
801
+ #else
802
+ char leftStringDouble[rightLength];
803
+ snprintf(leftStringDouble, rightLength, "%f", currentProperty->value.d);
804
+ #endif
805
+ *propertyMatch = compareStringProperty(leftStringDouble,
806
+ rightState + rightProperty->valueOffset,
807
+ rightProperty->valueLength,
808
+ alphaOp);
809
+ }
810
+ break;
811
+ case OP_STRING_BOOL:
812
+ if (rightProperty->value.b) {
813
+ *propertyMatch = compareString(message + currentProperty->valueOffset,
814
+ currentProperty->valueLength,
815
+ "true",
816
+ alphaOp);
817
+ }
818
+ else {
819
+ *propertyMatch = compareString(message + currentProperty->valueOffset,
820
+ currentProperty->valueLength,
821
+ "false",
822
+ alphaOp);
823
+ }
824
+ break;
825
+ case OP_STRING_INT:
826
+ {
827
+ leftLength = currentProperty->valueLength + 1;
828
+ #ifdef _WIN32
829
+ char *rightStringInt = (char *)_alloca(sizeof(char)*(leftLength));
830
+ sprintf_s(rightStringInt, leftLength, "%ld", rightProperty->value.i);
831
+ #else
832
+ char rightStringInt[leftLength];
833
+ snprintf(rightStringInt, leftLength, "%ld", rightProperty->value.i);
834
+ #endif
835
+ *propertyMatch = compareString(message + currentProperty->valueOffset,
836
+ currentProperty->valueLength,
837
+ rightStringInt,
838
+ alphaOp);
839
+ }
840
+ break;
841
+ case OP_STRING_DOUBLE:
842
+ {
843
+ leftLength = currentProperty->valueLength + 1;
844
+ #ifdef _WIN32
845
+ char *rightStringDouble = (char *)_alloca(sizeof(char)*(leftLength));
846
+ sprintf_s(rightStringDouble, leftLength, "%f", rightProperty->value.d);
847
+ #else
848
+ char rightStringDouble[leftLength];
849
+ snprintf(rightStringDouble, leftLength, "%f", rightProperty->value.d);
850
+ #endif
851
+ *propertyMatch = compareString(message + currentProperty->valueOffset,
852
+ currentProperty->valueLength,
853
+ rightStringDouble,
854
+ alphaOp);
855
+ }
856
+ break;
857
+ case OP_STRING_STRING:
858
+ *propertyMatch = compareStringAndStringProperty(message + currentProperty->valueOffset,
859
+ currentProperty->valueLength,
860
+ rightState + rightProperty->valueOffset,
861
+ rightProperty->valueLength,
862
+ alphaOp);
863
+ break;
864
+ }
865
+
866
+ if (releaseRightState) {
867
+ free(rightState);
868
+ }
869
+
870
+ return result;
871
+ }
872
+
873
+ static unsigned int handleAlpha(ruleset *tree,
874
+ char *sid,
875
+ char *mid,
876
+ char *message,
877
+ jsonProperty *allProperties,
878
+ unsigned int propertiesLength,
879
+ alpha *alphaNode,
880
+ unsigned char actionType,
881
+ char **evalKeys,
882
+ unsigned short *evalPriorities,
883
+ unsigned int *evalCount,
884
+ char **addKeys,
885
+ unsigned int *addCount,
886
+ char **removeCommand,
887
+ void **rulesBinding) {
888
+ unsigned int result = ERR_EVENT_NOT_HANDLED;
889
+ unsigned short top = 1;
890
+ unsigned int entry;
891
+ alpha *stack[MAX_STACK_SIZE];
892
+ stack[0] = alphaNode;
893
+ alpha *currentAlpha;
894
+ while (top) {
895
+ --top;
896
+ currentAlpha = stack[top];
897
+ if (currentAlpha->nextListOffset) {
898
+ unsigned int *nextList = &tree->nextPool[currentAlpha->nextListOffset];
899
+ for (entry = 0; nextList[entry] != 0; ++entry) {
900
+ node *listNode = &tree->nodePool[nextList[entry]];
901
+ char exists = 0;
902
+ for(unsigned int propertyIndex = 0; propertyIndex < propertiesLength; ++propertyIndex) {
903
+ if (listNode->value.a.hash == allProperties[propertyIndex].hash) {
904
+ exists = 1;
905
+ break;
906
+ }
907
+ }
908
+
909
+ if (!exists) {
910
+ if (top == MAX_STACK_SIZE) {
911
+ return ERR_MAX_STACK_SIZE;
912
+ }
913
+
914
+ stack[top] = &listNode->value.a;
915
+ ++top;
916
+ }
917
+ }
918
+ }
919
+
920
+ if (currentAlpha->nextOffset) {
921
+ unsigned int *nextHashset = &tree->nextPool[currentAlpha->nextOffset];
922
+ for(unsigned int propertyIndex = 0; propertyIndex < propertiesLength; ++propertyIndex) {
923
+ jsonProperty *currentProperty = &allProperties[propertyIndex];
924
+ for (entry = currentProperty->hash & HASH_MASK; nextHashset[entry] != 0; entry = (entry + 1) % NEXT_BUCKET_LENGTH) {
925
+ node *hashNode = &tree->nodePool[nextHashset[entry]];
926
+ if (currentProperty->hash == hashNode->value.a.hash) {
927
+ if (hashNode->value.a.right.type == JSON_EVENT_PROPERTY || hashNode->value.a.right.type == JSON_EVENT_IDIOM) {
928
+ if (top == MAX_STACK_SIZE) {
929
+ return ERR_MAX_STACK_SIZE;
930
+ }
931
+
932
+ stack[top] = &hashNode->value.a;
933
+ ++top;
934
+ } else {
935
+ unsigned char match = 0;
936
+ unsigned int mresult = isMatch(tree,
937
+ sid,
938
+ message,
939
+ currentProperty,
940
+ &hashNode->value.a,
941
+ &match,
942
+ rulesBinding);
943
+ if (mresult != RULES_OK){
944
+ return mresult;
945
+ }
946
+ if (match) {
947
+ if (top == MAX_STACK_SIZE) {
948
+ return ERR_MAX_STACK_SIZE;
949
+ }
950
+
951
+ stack[top] = &hashNode->value.a;
952
+ ++top;
953
+ }
954
+ }
955
+ }
956
+ }
957
+ }
958
+ }
959
+
960
+ if (currentAlpha->betaListOffset) {
961
+ unsigned int *betaList = &tree->nextPool[currentAlpha->betaListOffset];
962
+ for (unsigned int entry = 0; betaList[entry] != 0; ++entry) {
963
+ unsigned int bresult = handleBeta(tree,
964
+ sid,
965
+ mid,
966
+ &tree->nodePool[betaList[entry]],
967
+ actionType,
968
+ evalKeys,
969
+ evalPriorities,
970
+ evalCount,
971
+ addKeys,
972
+ addCount,
973
+ removeCommand,
974
+ rulesBinding);
975
+ if (bresult != RULES_OK && bresult != ERR_NEW_SESSION) {
976
+ return result;
977
+ }
978
+
979
+ if (result != ERR_NEW_SESSION) {
980
+ result = bresult;
981
+ }
982
+ }
983
+ }
984
+ }
985
+
986
+ return result;
987
+ }
988
+
989
+ static unsigned int getId(jsonProperty *allProperties,
990
+ unsigned int idIndex,
991
+ jsonProperty **idProperty,
992
+ int *idLength) {
993
+ jsonProperty *currentProperty;
994
+ if (idIndex == UNDEFINED_INDEX) {
995
+ return ERR_NO_ID_DEFINED;
996
+ }
997
+
998
+ currentProperty = &allProperties[idIndex];
999
+ *idLength = currentProperty->valueLength;
1000
+ switch(currentProperty->type) {
1001
+ case JSON_INT:
1002
+ case JSON_DOUBLE:
1003
+ *idLength = *idLength + 1;
1004
+ case JSON_STRING:
1005
+ break;
1006
+ default:
1007
+ return ERR_INVALID_ID;
1008
+ }
1009
+
1010
+ *idProperty = currentProperty;
1011
+ return RULES_OK;
1012
+ }
1013
+
1014
+ static unsigned int handleMessageCore(ruleset *tree,
1015
+ char *state,
1016
+ char *message,
1017
+ jsonProperty *properties,
1018
+ unsigned int propertiesLength,
1019
+ unsigned int midIndex,
1020
+ unsigned int sidIndex,
1021
+ unsigned char actionType,
1022
+ char **commands,
1023
+ unsigned int *commandCount,
1024
+ void **rulesBinding) {
1025
+ jsonProperty *midProperty;
1026
+ int midLength;
1027
+ jsonProperty *sidProperty;
1028
+ int sidLength;
1029
+ char *storeCommand;
1030
+ int result = getId(properties, sidIndex, &sidProperty, &sidLength);
1031
+ if (result != RULES_OK) {
1032
+ return result;
1033
+ }
1034
+ #ifdef _WIN32
1035
+ char *sid = (char *)_alloca(sizeof(char)*(sidLength + 1));
1036
+ #else
1037
+ char sid[sidLength + 1];
1038
+ #endif
1039
+ strncpy(sid, message + sidProperty->valueOffset, sidLength);
1040
+ sid[sidLength] = '\0';
1041
+
1042
+ result = getId(properties, midIndex, &midProperty, &midLength);
1043
+ if (result != RULES_OK) {
1044
+ return result;
1045
+ }
1046
+ #ifdef _WIN32
1047
+ char *mid = (char *)_alloca(sizeof(char)*(midLength + 1));
1048
+ #else
1049
+ char mid[midLength + 1];
1050
+ #endif
1051
+ strncpy(mid, message + midProperty->valueOffset, midLength);
1052
+ mid[midLength] = '\0';
1053
+ if (*commandCount == MAX_COMMAND_COUNT) {
1054
+ return ERR_MAX_COMMAND_COUNT;
1055
+ }
1056
+
1057
+ if (state) {
1058
+ if (!*rulesBinding) {
1059
+ result = resolveBinding(tree, sid, rulesBinding);
1060
+ if (result != RULES_OK) {
1061
+ return result;
1062
+ }
1063
+ }
1064
+
1065
+ if (*commandCount == MAX_COMMAND_COUNT) {
1066
+ return ERR_MAX_COMMAND_COUNT;
1067
+ }
1068
+
1069
+ result = formatStoreSession(*rulesBinding, sid, state, 0, &storeCommand);
1070
+ if (result != RULES_OK) {
1071
+ return result;
1072
+ }
1073
+
1074
+ commands[*commandCount] = storeCommand;
1075
+ ++*commandCount;
1076
+ }
1077
+
1078
+ char *removeCommand = NULL;
1079
+ char *addKeys[MAX_ADD_COUNT];
1080
+ unsigned int addCount = 0;
1081
+ char *evalKeys[MAX_EVAL_COUNT];
1082
+ unsigned short evalPriorities[MAX_EVAL_COUNT];
1083
+ unsigned int evalCount = 0;
1084
+ result = handleAlpha(tree,
1085
+ sid,
1086
+ mid,
1087
+ message,
1088
+ properties,
1089
+ propertiesLength,
1090
+ &tree->nodePool[NODE_M_OFFSET].value.a,
1091
+ actionType,
1092
+ evalKeys,
1093
+ evalPriorities,
1094
+ &evalCount,
1095
+ addKeys,
1096
+ &addCount,
1097
+ &removeCommand,
1098
+ rulesBinding);
1099
+ if (result == RULES_OK) {
1100
+ if (*commandCount == MAX_COMMAND_COUNT - 3) {
1101
+ for (unsigned int i = 0; i < addCount; ++i) {
1102
+ free(addKeys[i]);
1103
+ }
1104
+
1105
+ for (unsigned int i = 0; i < evalCount; ++i) {
1106
+ free(evalKeys[i]);
1107
+ }
1108
+
1109
+ return ERR_MAX_COMMAND_COUNT;
1110
+ }
1111
+
1112
+ if (removeCommand) {
1113
+ commands[*commandCount] = removeCommand;
1114
+ ++*commandCount;
1115
+ }
1116
+
1117
+ if (addCount > 0) {
1118
+ char *addCommand = NULL;
1119
+ result = formatStoreMessage(*rulesBinding,
1120
+ sid,
1121
+ message,
1122
+ properties,
1123
+ propertiesLength,
1124
+ actionType == ACTION_ASSERT_FACT ? 1 : 0,
1125
+ addKeys,
1126
+ addCount,
1127
+ &addCommand);
1128
+
1129
+ for (unsigned int i = 0; i < addCount; ++i) {
1130
+ free(addKeys[i]);
1131
+ }
1132
+
1133
+ if (result != RULES_OK) {
1134
+ for (unsigned int i = 0; i < evalCount; ++i) {
1135
+ free(evalKeys[i]);
1136
+ }
1137
+
1138
+ return result;
1139
+ }
1140
+
1141
+ commands[*commandCount] = addCommand;
1142
+ ++*commandCount;
1143
+ }
1144
+
1145
+ if (evalCount > 0) {
1146
+ char *evalCommand = NULL;
1147
+ result = formatEvalMessage(*rulesBinding,
1148
+ sid,
1149
+ mid,
1150
+ message,
1151
+ properties,
1152
+ propertiesLength,
1153
+ actionType,
1154
+ evalKeys,
1155
+ evalCount,
1156
+ &evalCommand);
1157
+
1158
+ for (unsigned int i = 0; i < evalCount; ++i) {
1159
+ free(evalKeys[i]);
1160
+ }
1161
+
1162
+ if (result != RULES_OK) {
1163
+ return result;
1164
+ }
1165
+
1166
+ commands[*commandCount] = evalCommand;
1167
+ ++*commandCount;
1168
+ }
1169
+
1170
+ if (!state) {
1171
+ // try creating state if doesn't exist
1172
+ jsonProperty *targetProperty;
1173
+ char *targetState;
1174
+ result = fetchStateProperty(tree,
1175
+ sid,
1176
+ HASH_SID,
1177
+ MAX_STATE_PROPERTY_TIME,
1178
+ 1,
1179
+ &targetState,
1180
+ &targetProperty);
1181
+ if (result != ERR_STATE_NOT_LOADED && result != ERR_PROPERTY_NOT_FOUND) {
1182
+ return result;
1183
+ }
1184
+
1185
+ // this sid has been tried by this process already
1186
+ if (result == ERR_PROPERTY_NOT_FOUND) {
1187
+ return RULES_OK;
1188
+ }
1189
+
1190
+ result = refreshState(tree,sid);
1191
+ if (result != ERR_NEW_SESSION) {
1192
+ return result;
1193
+ }
1194
+ #ifdef _WIN32
1195
+ char *stateMessage = (char *)_alloca(sizeof(char)*(36 + sidLength));
1196
+ char *newState = (char *)_alloca(sizeof(char)*(12 + sidLength));
1197
+ if (sidProperty->type == JSON_STRING) {
1198
+ sprintf_s(stateMessage, 36 + sidLength, "{\"id\":\"$s\", \"sid\":\"%s\", \"$s\":1}", sid);
1199
+ sprintf_s(newState, 12 + sidLength, "{\"sid\":\"%s\"}", sid);
1200
+ }
1201
+ else {
1202
+ sprintf_s(stateMessage, 36 + sidLength, "{\"id\":\"$s\", \"sid\":%s, \"$s\":1}", sid);
1203
+ sprintf_s(newState, 12 + sidLength, "{\"sid\":%s}", sid);
1204
+ }
1205
+ #else
1206
+ char stateMessage[36 + sidLength];
1207
+ char newState[12 + sidLength];
1208
+ if (sidProperty->type == JSON_STRING) {
1209
+ snprintf(stateMessage, 36 + sidLength, "{\"id\":\"$s\", \"sid\":\"%s\", \"$s\":1}", sid);
1210
+ snprintf(newState, 12 + sidLength, "{\"sid\":\"%s\"}", sid);
1211
+ }
1212
+ else {
1213
+ snprintf(stateMessage, 36 + sidLength, "{\"id\":\"$s\", \"sid\":%s, \"$s\":1}", sid);
1214
+ snprintf(newState, 12 + sidLength, "{\"sid\":%s}", sid);
1215
+ }
1216
+ #endif
1217
+
1218
+ if (*commandCount == MAX_COMMAND_COUNT) {
1219
+ return ERR_MAX_COMMAND_COUNT;
1220
+ }
1221
+
1222
+ result = formatStoreSession(*rulesBinding, sid, newState, 1, &storeCommand);
1223
+ if (result != RULES_OK) {
1224
+ return result;
1225
+ }
1226
+
1227
+ commands[*commandCount] = storeCommand;
1228
+ ++*commandCount;
1229
+
1230
+ result = handleMessage(tree,
1231
+ NULL,
1232
+ stateMessage,
1233
+ ACTION_ASSERT_EVENT,
1234
+ commands,
1235
+ commandCount,
1236
+ rulesBinding);
1237
+ if (result != RULES_OK && result != ERR_EVENT_NOT_HANDLED) {
1238
+ return result;
1239
+ }
1240
+
1241
+ if (result == ERR_EVENT_NOT_HANDLED) {
1242
+ return RULES_OK;
1243
+ }
1244
+ }
1245
+
1246
+ return RULES_OK;
1247
+ }
1248
+
1249
+ return result;
1250
+ }
1251
+
1252
+ static unsigned int handleMessage(ruleset *tree,
1253
+ char *state,
1254
+ char *message,
1255
+ unsigned char actionType,
1256
+ char **commands,
1257
+ unsigned int *commandCount,
1258
+ void **rulesBinding) {
1259
+ char *next;
1260
+ unsigned int propertiesLength = 0;
1261
+ unsigned int midIndex = UNDEFINED_INDEX;
1262
+ unsigned int sidIndex = UNDEFINED_INDEX;
1263
+ jsonProperty properties[MAX_EVENT_PROPERTIES];
1264
+ int result = constructObject(NULL,
1265
+ message,
1266
+ 0,
1267
+ MAX_EVENT_PROPERTIES,
1268
+ properties,
1269
+ &propertiesLength,
1270
+ &midIndex,
1271
+ &sidIndex,
1272
+ &next);
1273
+ if (result != RULES_OK) {
1274
+ return result;
1275
+ }
1276
+
1277
+ return handleMessageCore(tree,
1278
+ state,
1279
+ message,
1280
+ properties,
1281
+ propertiesLength,
1282
+ midIndex,
1283
+ sidIndex,
1284
+ actionType,
1285
+ commands,
1286
+ commandCount,
1287
+ rulesBinding);
1288
+ }
1289
+
1290
+ static unsigned int handleMessages(void *handle,
1291
+ unsigned char actionType,
1292
+ char *messages,
1293
+ char **commands,
1294
+ unsigned int *commandCount,
1295
+ unsigned int *resultsLength,
1296
+ unsigned int **results,
1297
+ void **rulesBinding) {
1298
+ unsigned int messagesLength = 64;
1299
+ unsigned int *resultsArray = malloc(sizeof(unsigned int) * messagesLength);
1300
+ if (!resultsArray) {
1301
+ return ERR_OUT_OF_MEMORY;
1302
+ }
1303
+
1304
+ *results = resultsArray;
1305
+ *resultsLength = 0;
1306
+ unsigned int result;
1307
+ jsonProperty properties[MAX_EVENT_PROPERTIES];
1308
+ unsigned int propertiesLength = 0;
1309
+ unsigned int propertiesMidIndex = UNDEFINED_INDEX;
1310
+ unsigned int propertiesSidIndex = UNDEFINED_INDEX;
1311
+
1312
+ char *first = messages;
1313
+ char *last = NULL;
1314
+ char lastTemp;
1315
+
1316
+ while (*first != '{' && *first != '\0' ) {
1317
+ ++first;
1318
+ }
1319
+
1320
+ while (constructObject(NULL,
1321
+ first,
1322
+ 0,
1323
+ MAX_EVENT_PROPERTIES,
1324
+ properties,
1325
+ &propertiesLength,
1326
+ &propertiesMidIndex,
1327
+ &propertiesSidIndex,
1328
+ &last) == RULES_OK) {
1329
+
1330
+ while (*last != ',' && *last != ']' ) {
1331
+ ++last;
1332
+ }
1333
+
1334
+ lastTemp = *last;
1335
+ *last = '\0';
1336
+ result = handleMessageCore(handle,
1337
+ NULL,
1338
+ first,
1339
+ properties,
1340
+ propertiesLength,
1341
+ propertiesMidIndex,
1342
+ propertiesSidIndex,
1343
+ actionType,
1344
+ commands,
1345
+ commandCount,
1346
+ rulesBinding);
1347
+
1348
+ *last = lastTemp;
1349
+ if (result != RULES_OK && result != ERR_EVENT_NOT_HANDLED) {
1350
+ free(resultsArray);
1351
+ return result;
1352
+ }
1353
+
1354
+ if (*resultsLength >= messagesLength) {
1355
+ messagesLength = messagesLength * 2;
1356
+ resultsArray = realloc(resultsArray, sizeof(unsigned int) * messagesLength);
1357
+ if (!resultsArray) {
1358
+ return ERR_OUT_OF_MEMORY;
1359
+ }
1360
+ *results = resultsArray;
1361
+ }
1362
+
1363
+ resultsArray[*resultsLength] = result;
1364
+ ++*resultsLength;
1365
+ propertiesLength = 0;
1366
+ propertiesMidIndex = UNDEFINED_INDEX;
1367
+ propertiesSidIndex = UNDEFINED_INDEX;
1368
+
1369
+ first = last;
1370
+ while (*first != '{' && *first != '\0' ) {
1371
+ ++first;
1372
+ }
1373
+ }
1374
+
1375
+ return RULES_OK;
1376
+ }
1377
+
1378
+ static unsigned int handleState(ruleset *tree,
1379
+ char *state,
1380
+ char **commands,
1381
+ unsigned int *commandCount,
1382
+ void **rulesBinding) {
1383
+ int stateLength = strlen(state);
1384
+ if (stateLength < 2) {
1385
+ return ERR_PARSE_OBJECT;
1386
+ }
1387
+
1388
+ if (state[0] != '{') {
1389
+ return ERR_PARSE_OBJECT;
1390
+ }
1391
+
1392
+ char *stateMessagePostfix = state + 1;
1393
+ #ifdef _WIN32
1394
+ char *stateMessage = (char *)_alloca(sizeof(char)*(30 + stateLength - 1));
1395
+ #else
1396
+ char stateMessage[30 + stateLength - 1];
1397
+ #endif
1398
+ int randomMid = rand();
1399
+ #ifdef _WIN32
1400
+ sprintf_s(stateMessage, 30 + stateLength - 1, "{\"id\":%d, \"$s\":1, %s", randomMid, stateMessagePostfix);
1401
+ #else
1402
+ snprintf(stateMessage, 30 + stateLength - 1, "{\"id\":%d, \"$s\":1, %s", randomMid, stateMessagePostfix);
1403
+ #endif
1404
+ unsigned int result = handleMessage(tree,
1405
+ state,
1406
+ stateMessage,
1407
+ ACTION_ASSERT_EVENT,
1408
+ commands,
1409
+ commandCount,
1410
+ rulesBinding);
1411
+
1412
+ return result;
1413
+ }
1414
+
1415
+ static unsigned int handleTimers(void *handle,
1416
+ char **commands,
1417
+ unsigned int *commandCount,
1418
+ void **rulesBinding) {
1419
+ redisReply *reply;
1420
+ unsigned int result = peekTimers(handle, rulesBinding, &reply);
1421
+ if (result != RULES_OK) {
1422
+ return result;
1423
+ }
1424
+
1425
+ for (unsigned long i = 0; i < reply->elements; ++i) {
1426
+ if (*commandCount == MAX_COMMAND_COUNT) {
1427
+ return ERR_MAX_COMMAND_COUNT;
1428
+ }
1429
+
1430
+ char *command;
1431
+ result = formatRemoveTimer(*rulesBinding, reply->element[i]->str, &command);
1432
+ if (result != RULES_OK) {
1433
+ freeReplyObject(reply);
1434
+ return result;
1435
+ }
1436
+
1437
+ commands[*commandCount] = command;
1438
+ ++*commandCount;
1439
+
1440
+ result = handleMessage(handle,
1441
+ NULL,
1442
+ reply->element[i]->str,
1443
+ ACTION_ASSERT_EVENT,
1444
+ commands,
1445
+ commandCount,
1446
+ rulesBinding);
1447
+ if (result != RULES_OK && result != ERR_EVENT_NOT_HANDLED) {
1448
+ freeReplyObject(reply);
1449
+ return result;
1450
+ }
1451
+ }
1452
+
1453
+ freeReplyObject(reply);
1454
+ return RULES_OK;
1455
+ }
1456
+
1457
+ static unsigned int startHandleMessage(void *handle,
1458
+ char *message,
1459
+ unsigned char actionType,
1460
+ void **rulesBinding,
1461
+ unsigned int *replyCount) {
1462
+ char *commands[MAX_COMMAND_COUNT];
1463
+ unsigned int commandCount = 0;
1464
+ unsigned int result = handleMessage(handle,
1465
+ NULL,
1466
+ message,
1467
+ actionType,
1468
+ commands,
1469
+ &commandCount,
1470
+ rulesBinding);
1471
+ if (result != RULES_OK && result != ERR_EVENT_NOT_HANDLED) {
1472
+ freeCommands(commands, commandCount);
1473
+ return result;
1474
+ }
1475
+
1476
+ unsigned int batchResult = startNonBlockingBatch(*rulesBinding, commands, commandCount, replyCount);
1477
+ if (batchResult != RULES_OK) {
1478
+ return batchResult;
1479
+ }
1480
+
1481
+ return result;
1482
+ }
1483
+
1484
+ static unsigned int executeHandleMessage(void *handle,
1485
+ char *message,
1486
+ unsigned char actionType) {
1487
+ char *commands[MAX_COMMAND_COUNT];
1488
+ unsigned int commandCount = 0;
1489
+ void *rulesBinding = NULL;
1490
+ unsigned int result = handleMessage(handle,
1491
+ NULL,
1492
+ message,
1493
+ actionType,
1494
+ commands,
1495
+ &commandCount,
1496
+ &rulesBinding);
1497
+ if (result != RULES_OK && result != ERR_EVENT_NOT_HANDLED) {
1498
+ freeCommands(commands, commandCount);
1499
+ return result;
1500
+ }
1501
+
1502
+ unsigned int batchResult = executeBatch(rulesBinding, commands, commandCount);
1503
+ if (batchResult != RULES_OK) {
1504
+ return batchResult;
1505
+ }
1506
+
1507
+ return result;
1508
+ }
1509
+
1510
+ static unsigned int startHandleMessages(void *handle,
1511
+ char *messages,
1512
+ unsigned char actionType,
1513
+ unsigned int *resultsLength,
1514
+ unsigned int **results,
1515
+ void **rulesBinding,
1516
+ unsigned int *replyCount) {
1517
+ char *commands[MAX_COMMAND_COUNT];
1518
+ unsigned int commandCount = 0;
1519
+ unsigned int result = handleMessages(handle,
1520
+ actionType,
1521
+ messages,
1522
+ commands,
1523
+ &commandCount,
1524
+ resultsLength,
1525
+ results,
1526
+ rulesBinding);
1527
+ if (result != RULES_OK && result != ERR_EVENT_NOT_HANDLED) {
1528
+ freeCommands(commands, commandCount);
1529
+ return result;
1530
+ }
1531
+
1532
+ unsigned int batchResult = startNonBlockingBatch(*rulesBinding, commands, commandCount, replyCount);
1533
+ if (batchResult != RULES_OK) {
1534
+ return batchResult;
1535
+ }
1536
+
1537
+ return result;
1538
+ }
1539
+
1540
+ static unsigned int executeHandleMessages(void *handle,
1541
+ char *messages,
1542
+ unsigned char actionType,
1543
+ unsigned int *resultsLength,
1544
+ unsigned int **results) {
1545
+ char *commands[MAX_COMMAND_COUNT];
1546
+ unsigned int commandCount = 0;
1547
+ void *rulesBinding = NULL;
1548
+ unsigned int result = handleMessages(handle,
1549
+ actionType,
1550
+ messages,
1551
+ commands,
1552
+ &commandCount,
1553
+ resultsLength,
1554
+ results,
1555
+ &rulesBinding);
1556
+ if (result != RULES_OK && result != ERR_EVENT_NOT_HANDLED) {
1557
+ freeCommands(commands, commandCount);
1558
+ return result;
1559
+ }
1560
+
1561
+ unsigned int batchResult = executeBatch(rulesBinding, commands, commandCount);
1562
+ if (batchResult != RULES_OK) {
1563
+ return batchResult;
1564
+ }
1565
+
1566
+ return result;
1567
+ }
1568
+
1569
+ unsigned int complete(void *rulesBinding, unsigned int replyCount) {
1570
+ return completeNonBlockingBatch(rulesBinding, replyCount);
1571
+ }
1572
+
1573
+ unsigned int assertEvent(void *handle, char *message) {
1574
+ return executeHandleMessage(handle, message, ACTION_ASSERT_EVENT);
1575
+ }
1576
+
1577
+ unsigned int startAssertEvent(void *handle,
1578
+ char *message,
1579
+ void **rulesBinding,
1580
+ unsigned int *replyCount) {
1581
+ return startHandleMessage(handle, message, ACTION_ASSERT_EVENT, rulesBinding, replyCount);
1582
+ }
1583
+
1584
+ unsigned int assertEvents(void *handle,
1585
+ char *messages,
1586
+ unsigned int *resultsLength,
1587
+ unsigned int **results) {
1588
+ return executeHandleMessages(handle, messages, ACTION_ASSERT_EVENT, resultsLength, results);
1589
+ }
1590
+
1591
+ unsigned int startAssertEvents(void *handle,
1592
+ char *messages,
1593
+ unsigned int *resultsLength,
1594
+ unsigned int **results,
1595
+ void **rulesBinding,
1596
+ unsigned int *replyCount) {
1597
+ return startHandleMessages(handle, messages, ACTION_ASSERT_EVENT, resultsLength, results, rulesBinding, replyCount);
1598
+ }
1599
+
1600
+ unsigned int retractEvent(void *handle, char *message) {
1601
+ return executeHandleMessage(handle, message, ACTION_REMOVE_EVENT);
1602
+ }
1603
+
1604
+ unsigned int startAssertFact(void *handle,
1605
+ char *message,
1606
+ void **rulesBinding,
1607
+ unsigned int *replyCount) {
1608
+ return startHandleMessage(handle, message, ACTION_ASSERT_FACT, rulesBinding, replyCount);
1609
+ }
1610
+
1611
+ unsigned int assertFact(void *handle, char *message) {
1612
+ return executeHandleMessage(handle, message, ACTION_ASSERT_FACT);
1613
+ }
1614
+
1615
+ unsigned int startAssertFacts(void *handle,
1616
+ char *messages,
1617
+ unsigned int *resultsLength,
1618
+ unsigned int **results,
1619
+ void **rulesBinding,
1620
+ unsigned int *replyCount) {
1621
+ return startHandleMessages(handle, messages, ACTION_ASSERT_FACT, resultsLength, results, rulesBinding, replyCount);
1622
+ }
1623
+
1624
+ unsigned int assertFacts(void *handle,
1625
+ char *messages,
1626
+ unsigned int *resultsLength,
1627
+ unsigned int **results) {
1628
+ return executeHandleMessages(handle, messages, ACTION_ASSERT_FACT, resultsLength, results);
1629
+ }
1630
+
1631
+ unsigned int retractFact(void *handle, char *message) {
1632
+ return executeHandleMessage(handle, message, ACTION_REMOVE_FACT);
1633
+ }
1634
+
1635
+ unsigned int startRetractFact(void *handle,
1636
+ char *message,
1637
+ void **rulesBinding,
1638
+ unsigned int *replyCount) {
1639
+ return startHandleMessage(handle, message, ACTION_REMOVE_FACT, rulesBinding, replyCount);
1640
+ }
1641
+
1642
+ unsigned int retractFacts(void *handle,
1643
+ char *messages,
1644
+ unsigned int *resultsLength,
1645
+ unsigned int **results) {
1646
+ return executeHandleMessages(handle, messages, ACTION_REMOVE_FACT, resultsLength, results);
1647
+ }
1648
+
1649
+ unsigned int startRetractFacts(void *handle,
1650
+ char *messages,
1651
+ unsigned int *resultsLength,
1652
+ unsigned int **results,
1653
+ void **rulesBinding,
1654
+ unsigned int *replyCount) {
1655
+ return startHandleMessages(handle, messages, ACTION_REMOVE_FACT, resultsLength, results, rulesBinding, replyCount);
1656
+ }
1657
+
1658
+ unsigned int assertState(void *handle, char *state) {
1659
+ char *commands[MAX_COMMAND_COUNT];
1660
+ unsigned int commandCount = 0;
1661
+ void *rulesBinding = NULL;
1662
+ unsigned int result = handleState(handle,
1663
+ state,
1664
+ commands,
1665
+ &commandCount,
1666
+ &rulesBinding);
1667
+ if (result != RULES_OK && result != ERR_EVENT_NOT_HANDLED) {
1668
+ freeCommands(commands, commandCount);
1669
+ return result;
1670
+ }
1671
+
1672
+ unsigned int batchResult = executeBatch(rulesBinding, commands, commandCount);
1673
+ if (batchResult != RULES_OK) {
1674
+ return batchResult;
1675
+ }
1676
+
1677
+ return result;
1678
+ }
1679
+
1680
+ unsigned int assertTimers(void *handle) {
1681
+ char *commands[MAX_COMMAND_COUNT];
1682
+ unsigned int commandCount = 0;
1683
+ void *rulesBinding = NULL;
1684
+ unsigned int result = handleTimers(handle,
1685
+ commands,
1686
+ &commandCount,
1687
+ &rulesBinding);
1688
+ if (result != RULES_OK) {
1689
+ freeCommands(commands, commandCount);
1690
+ return result;
1691
+ }
1692
+
1693
+ return executeBatch(rulesBinding, commands, commandCount);
1694
+ }
1695
+
1696
+ unsigned int startAction(void *handle,
1697
+ char **state,
1698
+ char **messages,
1699
+ void **actionHandle,
1700
+ void **actionBinding) {
1701
+ redisReply *reply;
1702
+ void *rulesBinding;
1703
+ unsigned int result = peekAction(handle, &rulesBinding, &reply);
1704
+ if (result != RULES_OK) {
1705
+ return result;
1706
+ }
1707
+
1708
+ *state = reply->element[1]->str;
1709
+ *messages = reply->element[2]->str;
1710
+ actionContext *context = malloc(sizeof(actionContext));
1711
+ context->reply = reply;
1712
+ context->rulesBinding = rulesBinding;
1713
+ *actionHandle = context;
1714
+ *actionBinding = rulesBinding;
1715
+ return RULES_OK;
1716
+ }
1717
+
1718
+ unsigned int startUpdateState(void *handle,
1719
+ void *actionHandle,
1720
+ char *state,
1721
+ void **rulesBinding,
1722
+ unsigned int *replyCount) {
1723
+ char *commands[MAX_COMMAND_COUNT];
1724
+ unsigned int result = RULES_OK;
1725
+ unsigned int commandCount = 0;
1726
+ result = handleState(handle,
1727
+ state,
1728
+ commands,
1729
+ &commandCount,
1730
+ rulesBinding);
1731
+ if (result != RULES_OK && result != ERR_EVENT_NOT_HANDLED) {
1732
+ //reply object should be freed by the app during abandonAction
1733
+ freeCommands(commands, commandCount);
1734
+ return result;
1735
+ }
1736
+
1737
+ result = startNonBlockingBatch(*rulesBinding, commands, commandCount, replyCount);
1738
+ return result;
1739
+
1740
+ }
1741
+
1742
+ unsigned int completeAction(void *handle,
1743
+ void *actionHandle,
1744
+ char *state) {
1745
+ char *commands[MAX_COMMAND_COUNT];
1746
+ unsigned int commandCount = 0;
1747
+ actionContext *context = (actionContext*)actionHandle;
1748
+ redisReply *reply = context->reply;
1749
+ void *rulesBinding = context->rulesBinding;
1750
+
1751
+ unsigned int result = formatRemoveAction(rulesBinding,
1752
+ reply->element[0]->str,
1753
+ &commands[commandCount]);
1754
+ if (result != RULES_OK) {
1755
+ //reply object should be freed by the app during abandonAction
1756
+ return result;
1757
+ }
1758
+
1759
+ ++commandCount;
1760
+ result = handleState(handle,
1761
+ state,
1762
+ commands,
1763
+ &commandCount,
1764
+ &rulesBinding);
1765
+ if (result != RULES_OK && result != ERR_EVENT_NOT_HANDLED) {
1766
+ //reply object should be freed by the app during abandonAction
1767
+ freeCommands(commands, commandCount);
1768
+ return result;
1769
+ }
1770
+
1771
+ result = executeBatch(rulesBinding, commands, commandCount);
1772
+ freeReplyObject(reply);
1773
+ free(actionHandle);
1774
+ return result;
1775
+ }
1776
+
1777
+ unsigned int completeAndStartAction(void *handle,
1778
+ unsigned int expectedReplies,
1779
+ void *actionHandle,
1780
+ char **messages) {
1781
+ char *commands[MAX_COMMAND_COUNT];
1782
+ unsigned int commandCount = 0;
1783
+ actionContext *context = (actionContext*)actionHandle;
1784
+ redisReply *reply = context->reply;
1785
+ void *rulesBinding = context->rulesBinding;
1786
+
1787
+ unsigned int result = formatRemoveAction(rulesBinding,
1788
+ reply->element[0]->str,
1789
+ &commands[commandCount]);
1790
+ if (result != RULES_OK) {
1791
+ //reply object should be freed by the app during abandonAction
1792
+ return result;
1793
+ }
1794
+
1795
+ ++commandCount;
1796
+ if (commandCount == MAX_COMMAND_COUNT) {
1797
+ //reply object should be freed by the app during abandonAction
1798
+ freeCommands(commands, commandCount);
1799
+ return ERR_MAX_COMMAND_COUNT;
1800
+ }
1801
+
1802
+ result = formatPeekAction(rulesBinding,
1803
+ reply->element[0]->str,
1804
+ &commands[commandCount]);
1805
+ if (result != RULES_OK) {
1806
+ //reply object should be freed by the app during abandonAction
1807
+ freeCommands(commands, commandCount);
1808
+ return result;
1809
+ }
1810
+
1811
+ ++commandCount;
1812
+ redisReply *newReply;
1813
+ result = executeBatchWithReply(rulesBinding,
1814
+ expectedReplies,
1815
+ commands,
1816
+ commandCount,
1817
+ &newReply);
1818
+ if (result != RULES_OK) {
1819
+ //reply object should be freed by the app during abandonAction
1820
+ return result;
1821
+ }
1822
+
1823
+ freeReplyObject(reply);
1824
+ if (newReply == NULL) {
1825
+ free(actionHandle);
1826
+ return ERR_NO_ACTION_AVAILABLE;
1827
+ }
1828
+
1829
+ *messages = newReply->element[1]->str;
1830
+ context->reply = newReply;
1831
+ return RULES_OK;
1832
+ }
1833
+
1834
+ unsigned int abandonAction(void *handle, void *actionHandle) {
1835
+ freeReplyObject(((actionContext*)actionHandle)->reply);
1836
+ free(actionHandle);
1837
+ return RULES_OK;
1838
+ }
1839
+
1840
+ unsigned int startTimer(void *handle, char *sid, unsigned int duration, char *timer) {
1841
+ void *rulesBinding;
1842
+ unsigned int result = resolveBinding(handle, sid, &rulesBinding);
1843
+ if (result != RULES_OK) {
1844
+ return result;
1845
+ }
1846
+
1847
+ return registerTimer(rulesBinding, duration, timer);
1848
+ }