durable_rules 0.31.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+ }