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