sync/gen_statemachine.ysl2
author Volker Birk <vb@pep.foundation>
Sat, 11 Aug 2018 00:46:58 +0200
branchsync
changeset 2838 7eef15a2c61e
parent 2836 0172fc10599f
child 2839 d9f7cb22f1d1
permissions -rw-r--r--
...
krista@2271
     1
// This file is under GNU General Public License 3.0
krista@2271
     2
// see LICENSE.txt
krista@2271
     3
krista@2271
     4
// generate state machine code
krista@2271
     5
vb@2829
     6
// Copyleft (c) 2016, 2017, p≡p foundation
krista@2271
     7
krista@2271
     8
// Written by Volker Birk
krista@2271
     9
krista@2271
    10
include yslt.yml2
krista@2271
    11
krista@2271
    12
tstylesheet {
krista@2271
    13
    include standardlib.ysl2
krista@2271
    14
    include ./functions.ysl2
krista@2271
    15
krista@2271
    16
    template "/protocol" {
vb@2838
    17
        document "generated/{@name}_event.h", "text"
vb@2838
    18
        ||
vb@2838
    19
        // This file is under GNU General Public License 3.0
vb@2838
    20
        // see LICENSE.txt
vb@2838
    21
vb@2838
    22
        #pragma once
vb@2838
    23
vb@2838
    24
        #include "dynamic_api.h"
vb@2838
    25
vb@2838
    26
        #ifdef __cplusplus
vb@2838
    27
        extern "C" {
vb@2838
    28
        #endif
vb@2838
    29
vb@2838
    30
        #include "../asn.1/«@name».h"
vb@2838
    31
vb@2838
    32
vb@2838
    33
        typedef struct _«@name»_event {
vb@2838
    34
            «@name»_PR fsm;
vb@2838
    35
            int event;
vb@2838
    36
            «@name»_t *msg;
vb@2838
    37
        } «@name»_event_t;
vb@2838
    38
vb@2838
    39
 
vb@2838
    40
        // new_«@name»_event() - allocate a new «@name»_event
vb@2838
    41
        //
vb@2838
    42
        //  parameters:
vb@2838
    43
        //      fsm (in)        finite state machine the event is for
vb@2838
    44
        //      event (in)      event or None
vb@2838
    45
        //      msg (in)        message to compute event from
vb@2838
    46
        //
vb@2838
    47
        //  return value:
vb@2838
    48
        //      pointer to new event or NULL in case of failure
vb@2838
    49
        //
vb@2838
    50
        //  caveat:
vb@2838
    51
        //      event must be valid for fsm or None
vb@2838
    52
        //      in case msg is given event will be calculated out of message
vb@2838
    53
vb@2838
    54
        DYNAMIC_API «@name»_event_t *new_«@name»_event(«@name»_PR fsm, int event, «@name»_t *msg);
vb@2838
    55
vb@2838
    56
vb@2838
    57
        // free_«@name»_event() - free memory occupied by event
vb@2838
    58
        //
vb@2838
    59
        //  parameters:
vb@2838
    60
        //      ev (in)         event to free
vb@2838
    61
vb@2838
    62
        DYNAMIC_API void free_«@name»_event(«@name»_event_t *ev);
vb@2838
    63
vb@2838
    64
vb@2838
    65
        #ifdef __cplusplus
vb@2838
    66
        }
vb@2838
    67
        #endif
vb@2838
    68
vb@2838
    69
        ||
vb@2838
    70
vb@2838
    71
        document "generated/{@name}_event.c", "text"
vb@2838
    72
        ||
vb@2838
    73
        // This file is under GNU General Public License 3.0
vb@2838
    74
        // see LICENSE.txt
vb@2838
    75
vb@2838
    76
        #include "pEp_internal.h"
vb@2838
    77
        #include "«@name»_event.h"
vb@2838
    78
        #include "«@name»_func.h"
vb@2838
    79
vb@2838
    80
        DYNAMIC_API «@name»_event_t *new_«@name»_event(«@name»_PR fsm, int event, «@name»_t *msg)
vb@2838
    81
        {
vb@2838
    82
            assert(fsm > 0 && (event >= 0 |`> |` msg));
vb@2838
    83
            if (!(fsm > 0 && (event >= 0 |`> |` msg)))
vb@2838
    84
                return NULL;
vb@2838
    85
vb@2838
    86
            «@name»_event_t *ev = («@name»_event_t *) calloc(1, sizeof(«@name»_event_t));
vb@2838
    87
            assert(ev);
vb@2838
    88
            if (!ev)
vb@2838
    89
                return NULL;
vb@2838
    90
vb@2838
    91
            ev->fsm = fsm;
vb@2838
    92
            ev->event = event;
vb@2838
    93
            ev->msg = msg;
vb@2838
    94
vb@2838
    95
            if (msg) {
vb@2838
    96
                switch (fsm) {
vb@2838
    97
                    `` apply "fsm", 3, mode=event
vb@2838
    98
                    default:
vb@2838
    99
                        // unknown protocol
vb@2838
   100
                        free(ev);
vb@2838
   101
                        return NULL;
vb@2838
   102
                }
vb@2838
   103
            }
vb@2838
   104
vb@2838
   105
            return ev;
vb@2838
   106
        }
vb@2838
   107
vb@2838
   108
        DYNAMIC_API void free_«@name»_event(«@name»_event_t *ev)
vb@2838
   109
        {
vb@2838
   110
            if (ev) {
vb@2838
   111
                free_«@name»_message(ev->msg);
vb@2838
   112
                free(ev);
vb@2838
   113
            }
vb@2838
   114
        }
vb@2838
   115
vb@2838
   116
        ||
vb@2838
   117
vb@2829
   118
        document "generated/{@name}_impl.h", "text" {
vb@2829
   119
        ||
vb@2829
   120
        // This file is under GNU General Public License 3.0
vb@2829
   121
        // see LICENSE.txt
krista@2271
   122
krista@2271
   123
        #pragma once
krista@2271
   124
vb@2829
   125
        #include "fsm_common.h"
krista@2271
   126
        #include "message_api.h"
vb@2829
   127
        #include "../asn.1/Sync.h"
krista@2271
   128
        
krista@2271
   129
        #ifdef __cplusplus
krista@2271
   130
        extern "C" {
krista@2271
   131
        #endif
krista@2271
   132
krista@2271
   133
        // conditions
krista@2271
   134
vb@2829
   135
        ||
vb@2829
   136
        for "func:distinctName(*//condition)"
vb@2829
   137
            | PEP_STATUS «@name»(PEP_SESSION session, bool *result);
vb@2829
   138
        ||
vb@2834
   139
vb@2829
   140
        // actions
vb@2829
   141
vb@2829
   142
        ||
vb@2829
   143
        const "name", "@name";
vb@2829
   144
        for "func:distinctName(*//action[not(starts-with(@name, 'send'))])"
vb@2829
   145
            | PEP_STATUS «@name»(PEP_SESSION session);
vb@2829
   146
        ||
vb@2829
   147
vb@2835
   148
        // notify state machine from event
vb@2835
   149
        // use state to generate «@name» message if necessary
vb@2829
   150
vb@2835
   151
        PEP_STATUS «@name»_notify(
vb@2829
   152
                PEP_SESSION session, 
vb@2829
   153
                «@name»_PR fsm,
vb@2829
   154
                int message_type
vb@2829
   155
            );
vb@2829
   156
vb@2836
   157
        // send message about an event to partners using state
vb@2829
   158
vb@2829
   159
        PEP_STATUS send_«@name»_message(
vb@2829
   160
                PEP_SESSION session, 
vb@2829
   161
                «@name»_PR fsm,
vb@2829
   162
                int event
vb@2829
   163
            );
vb@2829
   164
vb@2838
   165
        // receive message and store it in state
vb@2829
   166
vb@2838
   167
        PEP_STATUS recv_«@name»_message(
vb@2836
   168
                PEP_SESSION session,
vb@2838
   169
                «@name»_t *msg
vb@2829
   170
            );
vb@2829
   171
    
vb@2829
   172
        // state machine driver
vb@2829
   173
        // if fsm or event set to 0 use fields in src if present
vb@2829
   174
vb@2829
   175
        PEP_STATUS «@name»_driver(
vb@2829
   176
                PEP_SESSION session,
vb@2829
   177
                «@name»_PR fsm,
vb@2829
   178
                int event
vb@2829
   179
            );
vb@2829
   180
vb@2829
   181
        PEP_STATUS inject_«@name»_event(
vb@2829
   182
                PEP_SESSION session, 
vb@2829
   183
                «@name»_PR fsm,
vb@2829
   184
                int event
vb@2829
   185
            );
vb@2829
   186
vb@2829
   187
vb@2829
   188
        #ifdef __cplusplus
vb@2829
   189
        }
vb@2829
   190
        #endif
vb@2829
   191
vb@2829
   192
        ||
vb@2829
   193
        }
vb@2829
   194
vb@2829
   195
        document "generated/{@name}_impl.c", "text"
vb@2829
   196
        ||
vb@2829
   197
        // This file is under GNU General Public License 3.0
vb@2829
   198
        // see LICENSE.txt
vb@2829
   199
    
vb@2829
   200
        #include "«@name»_impl.h"
vb@2829
   201
        #include "pEp_internal.h"
vb@2829
   202
        `` for "fsm" | #include "«@name»_fsm.h"
vb@2829
   203
vb@2829
   204
        PEP_STATUS «@name»_driver(
vb@2829
   205
                PEP_SESSION session,
vb@2829
   206
                «@name»_PR fsm,
vb@2829
   207
                int event
vb@2829
   208
            )
vb@2829
   209
        {
vb@2829
   210
            assert(session && fsm);
vb@2829
   211
            if (!(session && fsm))
vb@2829
   212
                return PEP_ILLEGAL_VALUE;
vb@2829
   213
vb@2838
   214
            int next_state = None;
vb@2838
   215
            do {
vb@2838
   216
                switch (fsm) {
vb@2838
   217
                    `` apply "fsm", 3, mode=driver               
vb@2838
   218
                    default:
vb@2838
   219
                        return PEP_ILLEGAL_VALUE;
vb@2838
   220
                }
vb@2838
   221
            }  while (next_state);
vb@2829
   222
vb@2829
   223
            return PEP_STATUS_OK;
vb@2829
   224
        }
vb@2829
   225
vb@2829
   226
        PEP_STATUS inject_«@name»_event(
vb@2829
   227
                PEP_SESSION session, 
vb@2829
   228
                «@name»_PR fsm,
vb@2829
   229
                int event
vb@2829
   230
            )
vb@2829
   231
        {
vb@2829
   232
            «@name»_t *msg = NULL;
vb@2829
   233
            «@name»_event_t *ev = NULL;
vb@2829
   234
vb@2829
   235
            assert(session && fsm > 0 && event > None);
vb@2829
   236
            if (!(session && fsm > 0 && event > None))
vb@2829
   237
                return PEP_ILLEGAL_VALUE;
vb@2829
   238
vb@2829
   239
            PEP_STATUS status = PEP_STATUS_OK;
vb@2829
   240
vb@2829
   241
            if (!session->inject_«yml:lcase(@name)»_msg) {
vb@2829
   242
               status = PEP_«yml:ucase(@name)»_NO_INJECT_CALLBACK;
vb@2829
   243
               goto error;
vb@2829
   244
            }
vb@2829
   245
vb@2829
   246
            if (event < Extra) {
vb@2829
   247
                msg = new_«@name»_message(fsm, event);
vb@2829
   248
                assert(msg);
vb@2829
   249
                if (!msg) {
vb@2829
   250
                    status = PEP_OUT_OF_MEMORY;
vb@2829
   251
                    goto error;
vb@2829
   252
                }
vb@2829
   253
vb@2829
   254
                status = update_«@name»_message(session, fsm, event, msg);
vb@2829
   255
                if (status)
vb@2829
   256
                    goto error;
vb@2829
   257
            }
vb@2829
   258
vb@2829
   259
            ev = («@name»_event_t *) calloc(1, sizeof(«@name»_event_t));
vb@2829
   260
            assert(ev);
vb@2829
   261
            if (!ev) {
vb@2829
   262
                status = PEP_OUT_OF_MEMORY;
vb@2829
   263
                goto error;
vb@2829
   264
            }
vb@2829
   265
            
vb@2829
   266
            ev->fsm = fsm;
vb@2829
   267
            ev->event = event;
vb@2829
   268
            ev->msg = msg;
vb@2829
   269
vb@2829
   270
            int result = session->inject_«yml:lcase(@name)»_msg(ev,
vb@2829
   271
                    session->«yml:lcase(@name)»_management);
vb@2829
   272
            if (result) {
vb@2829
   273
                status = PEP_STATEMACHINE_ERROR;
vb@2829
   274
                goto error;
vb@2829
   275
            }
vb@2829
   276
vb@2829
   277
            goto the_end;
vb@2829
   278
vb@2829
   279
        error:
vb@2829
   280
            free(ev);
vb@2829
   281
            free_«@name»_message(msg);
vb@2829
   282
vb@2829
   283
        the_end:
vb@2829
   284
            return status;
vb@2829
   285
        }
vb@2829
   286
vb@2835
   287
        PEP_STATUS «@name»_notify(
vb@2829
   288
                PEP_SESSION session, 
vb@2829
   289
                «@name»_PR fsm,
vb@2829
   290
                int message_type
vb@2829
   291
            )
vb@2829
   292
        {
vb@2829
   293
            assert(session && fsm > 0 && message_type > 1 && message_type < Extra);
vb@2829
   294
            if (!(session && fsm > 0 && message_type > 1 && message_type < Extra))
vb@2829
   295
                return PEP_ILLEGAL_VALUE;
vb@2829
   296
vb@2829
   297
            PEP_STATUS status = PEP_STATUS_OK;
vb@2829
   298
vb@2829
   299
            «@name»_t *msg = new_«@name»_message(fsm, message_type);
vb@2829
   300
            assert(msg);
vb@2829
   301
            if (!msg) {
vb@2829
   302
                status = PEP_OUT_OF_MEMORY;
vb@2829
   303
                goto error;
vb@2829
   304
            }
vb@2829
   305
vb@2829
   306
            status = update_«@name»_message(session, fsm, message_type, msg);
vb@2829
   307
            if (status)
vb@2829
   308
                goto error;
vb@2829
   309
vb@2829
   310
            goto the_end;
vb@2829
   311
vb@2829
   312
        error:
vb@2829
   313
            free_«@name»_message(msg);
vb@2829
   314
vb@2829
   315
        the_end:
vb@2829
   316
            return status;
vb@2829
   317
        }
vb@2829
   318
vb@2829
   319
        PEP_STATUS recv_«@name»_event(
vb@2836
   320
                PEP_SESSION session,
vb@2836
   321
                «@name»_t *ev
vb@2829
   322
            )
vb@2829
   323
        {
vb@2829
   324
            assert(session && ev);
vb@2829
   325
            if (!(session && ev))
vb@2829
   326
                return PEP_ILLEGAL_VALUE;
vb@2829
   327
vb@2829
   328
            PEP_STATUS status = PEP_STATUS_OK;
vb@2829
   329
vb@2829
   330
            if (ev->event < Extra) {
vb@2829
   331
                «@name»_PR fsm = (int) None;
vb@2829
   332
                int event = None;
vb@2829
   333
vb@2829
   334
                status = update_«@name»_state(session, ev->msg, &fsm, &event);
vb@2829
   335
                if (status)
vb@2829
   336
                    goto error;
vb@2829
   337
vb@2829
   338
                if (ev->fsm) {
vb@2829
   339
                    if (ev->fsm != fsm |`> |` ev->event != event) {
vb@2829
   340
                        status = PEP_SYNC_ILLEGAL_MESSAGE;
vb@2829
   341
                        goto error;
vb@2829
   342
                    }
vb@2829
   343
                }
vb@2829
   344
                else {
vb@2829
   345
                    if (ev->event) {
vb@2829
   346
                        status = PEP_SYNC_ILLEGAL_MESSAGE;
vb@2829
   347
                        goto error;
vb@2829
   348
                    }
vb@2829
   349
                    ev->fsm = fsm;
vb@2829
   350
                    ev->event = event;
vb@2829
   351
                }
vb@2829
   352
            }
vb@2829
   353
vb@2829
   354
            free_«@name»_message(ev->msg);
vb@2829
   355
            free(ev);
vb@2829
   356
            status = «@name»_driver(session, ev->fsm, ev->event);
vb@2829
   357
            return status;
vb@2829
   358
vb@2829
   359
        error:
vb@2829
   360
            free_«@name»_message(ev->msg);
vb@2829
   361
            free(ev);
vb@2829
   362
            return status;
vb@2829
   363
        }
vb@2829
   364
vb@2829
   365
        ||
vb@2829
   366
vb@2829
   367
        apply "fsm", 0, mode=gen;
vb@2829
   368
    }
vb@2829
   369
vb@2838
   370
    template "fsm", mode=event
vb@2838
   371
    {
vb@2838
   372
    ||
vb@2838
   373
    case Sync_PR_«yml:lcase(@name)»: {
vb@2838
   374
        switch (msg->choice.keysync.choice.present) {
vb@2838
   375
    ||
vb@2838
   376
    for "message"
vb@2838
   377
    ||
vb@2838
   378
            case «../@name»__payload_PR_«yml:mixedCase(@name)»:
vb@2838
   379
                ev->event = «@name»;
vb@2838
   380
                break;
vb@2838
   381
    ||
vb@2838
   382
    ||
vb@2838
   383
            default:
vb@2838
   384
                // unknown message type
vb@2838
   385
                free(ev);
vb@2838
   386
                return NULL;
vb@2838
   387
        }
vb@2838
   388
        break;
vb@2838
   389
    }
vb@2838
   390
vb@2838
   391
    ||
vb@2838
   392
    }
vb@2838
   393
vb@2829
   394
    template "fsm", mode=driver
vb@2829
   395
    ||
vb@2829
   396
    case Sync_PR_«yml:lcase(@name)»: {
vb@2838
   397
        next_state = fsm_«@name»(session, session->«yml:lcase(../@name)»_state.«yml:lcase(@name)».state, event);
vb@2838
   398
        if (next_state > None) {
vb@2838
   399
            session->«yml:lcase(../@name)»_state.«yml:lcase(@name)».state = next_state;
vb@2838
   400
            event = Init;
vb@2838
   401
        }
vb@2838
   402
        else if (next_state < None) {
vb@2829
   403
            return PEP_STATEMACHINE_ERROR - state;
vb@2838
   404
        }
vb@2829
   405
        break;
vb@2829
   406
    }
vb@2829
   407
vb@2829
   408
    ||
vb@2829
   409
vb@2829
   410
    template "fsm", mode=gen {
vb@2829
   411
        document "generated/{@name}_fsm.h", "text" {
vb@2829
   412
        ||
vb@2829
   413
        // This file is under GNU General Public License 3.0
vb@2829
   414
        // see LICENSE.txt
vb@2829
   415
vb@2829
   416
        #pragma once
vb@2829
   417
vb@2829
   418
        #include "«../@name»_impl.h"
vb@2829
   419
vb@2829
   420
        #ifdef __cplusplus
vb@2829
   421
        extern "C" {
vb@2829
   422
        #endif
vb@2829
   423
vb@2829
   424
        // state machine for «@name»
krista@2271
   425
krista@2271
   426
        // states
krista@2271
   427
krista@2271
   428
        typedef enum _«@name»_state {
vb@2829
   429
            «@name»_state_None = None,
vb@2829
   430
            «@name»_state_Init = Init,
vb@2829
   431
        ||
vb@2829
   432
        for "func:distinctName(state[not(@name='InitState')])"
vb@2829
   433
            |> «@name»`if "position()!=last()" > , `
vb@2829
   434
        ||
krista@2271
   435
        } «@name»_state;
krista@2271
   436
krista@2271
   437
        // events
krista@2271
   438
krista@2271
   439
        typedef enum _«@name»_event {
vb@2829
   440
            «@name»_event_None = None,
vb@2829
   441
            «@name»_event_Init = Init,
krista@2271
   442
        ||
vb@2829
   443
        for "func:distinctName(state/event[not(not(../../message/@name=@name))])" {
krista@2271
   444
            const "name", "@name";
vb@2829
   445
            |> «$name» = «/protocol/fsm/message[@name=$name]/@id»,
krista@2271
   446
        }
vb@2830
   447
        for "func:distinctName(state/event[not(not(../../external/@name=@name))])" {
vb@2830
   448
            const "name", "@name";
vb@2830
   449
            |> «$name» = «/protocol/fsm/external[@name=$name]/@id»,
vb@2830
   450
        }
vb@2829
   451
        |> «@name»_event_Extra = Extra,
vb@2830
   452
        for "func:distinctName(state/event[not(../../message/@name=@name or ../../external/@name=@name)])" {
vb@2829
   453
            if "@name!='Init'"
vb@2829
   454
                |> «@name»`if "position()!=last()" > , `
vb@2829
   455
        }
krista@2271
   456
        ||
krista@2271
   457
        } «@name»_event;
krista@2271
   458
vb@2829
   459
        // state machine
krista@2271
   460
vb@2829
   461
        const char *«@name»_state_name(int state);
krista@2271
   462
vb@2838
   463
        // the state machine function is returning the next state in case of a
vb@2838
   464
        // transition or None for staying
vb@2838
   465
krista@2271
   466
        «@name»_state fsm_«@name»(
krista@2271
   467
                PEP_SESSION session,
krista@2271
   468
                «@name»_state state,
vb@2829
   469
                «@name»_event event
krista@2271
   470
            );
krista@2271
   471
krista@2271
   472
        #ifdef __cplusplus
krista@2271
   473
        }
krista@2271
   474
        #endif
krista@2271
   475
krista@2271
   476
        ||
krista@2271
   477
        }
vb@2829
   478
vb@2829
   479
        document "generated/{@name}_fsm.c", "text" {
krista@2271
   480
        ||
vb@2829
   481
        // This file is under GNU General Public License 3.0
vb@2829
   482
        // see LICENSE.txt
krista@2271
   483
vb@2829
   484
        #include "«@name»_fsm.h"
krista@2271
   485
vb@2829
   486
        const char *«@name»_state_name(int state)
vb@2829
   487
        {
vb@2829
   488
            switch (state) {
vb@2829
   489
                case End:
vb@2829
   490
                    return "End";
vb@2829
   491
                case None:
vb@2829
   492
                    return "None";
vb@2829
   493
                case Init:
vb@2829
   494
                    return "InitState";
vb@2829
   495
        ||
vb@2829
   496
        for "func:distinctName(state[not(@name='InitState')])" {
vb@2829
   497
            |>> case «@name»:
vb@2829
   498
            |>>> return "«@name»";
vb@2829
   499
        }
vb@2829
   500
        ||
vb@2829
   501
                default:
vb@2829
   502
                    return "unknown state";
vb@2829
   503
            }
vb@2829
   504
        }
krista@2271
   505
vb@2829
   506
        static char *_str(int n, bool hex)
vb@2829
   507
        {
vb@2829
   508
            char *buf = calloc(1, 24);
vb@2829
   509
            assert(buf);
vb@2829
   510
            if (!buf)
vb@2829
   511
                return NULL;
vb@2829
   512
vb@2829
   513
            if (hex)
vb@2829
   514
                snprintf(buf, 24, "%.4x", n);
vb@2829
   515
            else
vb@2829
   516
                snprintf(buf, 24, "%d", n);
vb@2829
   517
            return buf;
vb@2829
   518
        }
vb@2829
   519
vb@2829
   520
        #define «@name»_ERR_LOG(t, d) log_event(session, (t), "«@name»", (d), "error")
vb@2829
   521
vb@2829
   522
        static PEP_STATUS _«@name»_ERR_LOG_int(PEP_SESSION session, char *t, int n, bool hex)
vb@2829
   523
        {
vb@2829
   524
            char *_buf = _str(n, hex);
vb@2829
   525
            if (!_buf)
vb@2829
   526
                return PEP_OUT_OF_MEMORY;
vb@2829
   527
            PEP_STATUS status = «@name»_ERR_LOG(t, _buf);
vb@2829
   528
            free(_buf);
vb@2829
   529
            return status;
vb@2829
   530
        }
vb@2829
   531
vb@2829
   532
        #define «@name»_ERR_LOG_INT(t, n) _«@name»_ERR_LOG_int(session, (t), (n), false)
vb@2829
   533
        #define «@name»_ERR_LOG_HEX(t, n) _«@name»_ERR_LOG_int(session, (t), (n), true)
vb@2829
   534
vb@2829
   535
        #ifndef SERVICE_LOG
vb@2829
   536
        // SERVICE LOG is meant to check session->service_log in runtime config;
vb@2829
   537
        // for older engines log more than needed
vb@2829
   538
        #define SERVICE_LOG(session, t, n, d) log_event((session), (t), (n), (d), "service")
vb@2829
   539
        #endif 
vb@2829
   540
vb@2829
   541
        #define «@name»_SERVICE_LOG(t, d) SERVICE_LOG(session, (t), "«@name»", (d))
vb@2829
   542
vb@2829
   543
        «@name»_state fsm_«@name»(
krista@2271
   544
                PEP_SESSION session,
vb@2829
   545
                «@name»_state state,
vb@2829
   546
                «@name»_event event
krista@2271
   547
            )
krista@2271
   548
        {
krista@2271
   549
            assert(session);
krista@2271
   550
            if (!session)
vb@2829
   551
                return invalid_state;
krista@2271
   552
krista@2271
   553
            switch (state) {
vb@2829
   554
                case None:
vb@2838
   555
                    return «@name»_state_Init;
vb@2829
   556
                
vb@2829
   557
                `` apply "state", 2, mode=fsm
krista@2271
   558
                default:
vb@2838
   559
                    «@name»_ERR_LOG_INT("invalid state", state);
vb@2829
   560
                    return invalid_state;
krista@2271
   561
            }
vb@2829
   562
            
vb@2838
   563
            return None;
krista@2271
   564
        }
krista@2271
   565
krista@2271
   566
        ||
vb@2829
   567
        }
vb@2829
   568
    }
vb@2829
   569
    
vb@2829
   570
    template "state", mode=fsm {
vb@2829
   571
        choose {
vb@2829
   572
            when "@name='InitState'" | case «../@name»_state_Init:
vb@2829
   573
            otherwise | case «@name»:
vb@2829
   574
        }
vb@2829
   575
        ||
vb@2829
   576
            «../@name»_SERVICE_LOG("in state", "«@name»");
vb@2829
   577
vb@2829
   578
            switch (event) {
vb@2829
   579
                case None:
vb@2829
   580
                    «../@name»_SERVICE_LOG("received None event", "ignoring");
vb@2838
   581
                    break;
vb@2829
   582
     
vb@2838
   583
        ||
vb@2838
   584
        if "not(event[@name='Init'])"
vb@2838
   585
        ||
vb@2838
   586
                case Init:
vb@2838
   587
                    // nothing to do
vb@2838
   588
                    break;
vb@2838
   589
vb@2838
   590
        ||
vb@2838
   591
        ||
vb@2829
   592
                `` apply "event", 2, mode=fsm
vb@2829
   593
                default:
vb@2838
   594
                    «../@name»_ERR_LOG_INT("invalid event", event);
vb@2829
   595
                    return invalid_event;
vb@2829
   596
            }
vb@2829
   597
            break;
vb@2829
   598
vb@2829
   599
        ||
krista@2271
   600
    }
krista@2271
   601
vb@2829
   602
    template "event", mode=fsm {
vb@2829
   603
        | case «@name»: {
vb@2829
   604
        if "condition|action" |> PEP_STATUS status;
vb@2829
   605
        if "condition" |> bool result = false;
vb@2829
   606
        if "condition|action" |
krista@2271
   607
        ||
vb@2829
   608
            «../../@name»_SERVICE_LOG("received event", "«@name»");
vb@2829
   609
            `` apply "transition|action|condition" with "protocol", "../../..", with "fsm", "../.."
vb@2829
   610
        ||
vb@2829
   611
        if "name(*[last()])!='transition'" {
vb@2829
   612
            |
vb@2829
   613
            |> KeySync_SERVICE_LOG("remaining in state", "«../@name»");
vb@2829
   614
            |> break;
vb@2829
   615
        }
vb@2829
   616
        ||
vb@2829
   617
        }
vb@2829
   618
        
vb@2829
   619
        ||
vb@2829
   620
    }
vb@2829
   621
vb@2829
   622
    template "transition" {
vb@2829
   623
        param "fsm";
krista@2271
   624
        ||
krista@2271
   625
vb@2829
   626
        «$fsm/@name»_SERVICE_LOG("transition to state", "«@target»");
vb@2838
   627
        return «@target»;
krista@2271
   628
        ||
vb@2829
   629
    }
krista@2271
   630
vb@2829
   631
    template "action" {
vb@2829
   632
        param "protocol";
vb@2829
   633
        param "fsm";
vb@2829
   634
        choose {
vb@2829
   635
            when "starts-with(@name, 'send')" {
vb@2829
   636
                const "name", "substring(@name, 5)";
vb@2829
   637
                ||
vb@2829
   638
vb@2829
   639
                «$fsm/@name»_SERVICE_LOG("send message", "«$name»");
vb@2835
   640
                status = «$protocol/@name»_notify(session, «$fsm/@id», «$name»);
vb@2829
   641
                ||
vb@2829
   642
            }
vb@2829
   643
            otherwise
vb@2829
   644
                ||
vb@2829
   645
vb@2829
   646
                «$fsm/@name»_SERVICE_LOG("do action", "«@name»");
vb@2829
   647
                status = «@name»(session);
vb@2829
   648
                ||
vb@2829
   649
        }
krista@2271
   650
        ||
vb@2829
   651
        if (status) {
vb@2829
   652
            «$fsm/@name»_ERR_LOG_HEX("executing action «@name»() failed", status);
vb@2829
   653
            return invalid_action;
krista@2271
   654
        }
krista@2271
   655
        ||
krista@2271
   656
    }
krista@2271
   657
vb@2829
   658
    template "condition" {
vb@2829
   659
        param "protocol";
vb@2829
   660
        param "fsm";
krista@2271
   661
        ||
krista@2271
   662
vb@2829
   663
        status = «@name»(session, &result);
vb@2829
   664
        if (status) {
vb@2829
   665
            «$fsm/@name»_ERR_LOG_HEX("computing condition «@name» failed", status);
vb@2829
   666
            return invalid_condition;
krista@2271
   667
        }
vb@2829
   668
        if (result) {
vb@2829
   669
            KeySync_SERVICE_LOG("condition applies", "«@name»");
krista@2271
   670
        ||
vb@2829
   671
            apply "transition|action|condition"
vb@2829
   672
                with "protocol", "$protocol", with "fsm", "$fsm";
krista@2271
   673
        | }
krista@2271
   674
    }
krista@2271
   675
}
krista@2271
   676