sync/gen_statemachine.ysl2
author Volker Birk <vb@pep-project.org>
Sat, 13 Apr 2019 22:18:57 +0200
branchsync
changeset 3509 a9c0c6f31c56
parent 3393 ecdb1635904a
child 3512 a5a45f8fa684
permissions -rw-r--r--
make it simple
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@3389
     6
// Copyleft (c) 2016 - 2019, 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@3020
    30
        typedef struct «@name» «yml:ucase(@name)»;
vb@3020
    31
        typedef int «yml:ucase(@name)»_PR;
vb@2838
    32
vb@2847
    33
        typedef struct «@name»_event {
vb@3020
    34
            «yml:ucase(@name)»_PR fsm;
vb@2838
    35
            int event;
vb@3020
    36
            «yml:ucase(@name)» *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@3020
    54
        «@name»_event_t *new_«@name»_event(«yml:ucase(@name)»_PR fsm, int event, «yml:ucase(@name)» *msg);
vb@2838
    55
vb@2910
    56
        #define «yml:ucase(@name)»_TIMEOUT_EVENT new_«@name»_event(«@name»_PR_NOTHING, 0, NULL);
vb@2910
    57
vb@3338
    58
    
vb@2838
    59
        // free_«@name»_event() - free memory occupied by event
vb@2838
    60
        //
vb@2838
    61
        //  parameters:
vb@2838
    62
        //      ev (in)         event to free
vb@2838
    63
vb@2899
    64
        void free_«@name»_event(«@name»_event_t *ev);
vb@2838
    65
vb@2838
    66
vb@2838
    67
        #ifdef __cplusplus
vb@2838
    68
        }
vb@2838
    69
        #endif
vb@2838
    70
vb@2838
    71
        ||
vb@2838
    72
vb@2838
    73
        document "generated/{@name}_event.c", "text"
vb@2838
    74
        ||
vb@2838
    75
        // This file is under GNU General Public License 3.0
vb@2838
    76
        // see LICENSE.txt
vb@2838
    77
vb@3062
    78
        #include "platform.h"
vb@3062
    79
vb@2838
    80
        #include "pEp_internal.h"
vb@2838
    81
        #include "«@name»_event.h"
vb@2838
    82
        #include "«@name»_func.h"
vb@2839
    83
        `` for "fsm" | #include "«@name»_fsm.h"
vb@2838
    84
vb@3020
    85
        «@name»_event_t *new_«@name»_event(«yml:ucase(@name)»_PR fsm, int event, «@name»_t *msg)
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@2899
   109
        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@2870
   120
            ||
vb@2870
   121
            // This file is under GNU General Public License 3.0
vb@2870
   122
            // see LICENSE.txt
krista@2271
   123
vb@2870
   124
            #pragma once
krista@2271
   125
vb@2870
   126
            #include "fsm_common.h"
vb@2889
   127
            #include "«@name»_event.h"
vb@2870
   128
            #include "message_api.h"
vb@3020
   129
            #include "../asn.1/«@name».h"
vb@2870
   130
            
vb@2909
   131
            #define «yml:ucase(@name)»_THRESHOLD «@threshold»
vb@2909
   132
            `` for "fsm" | #define «yml:ucase(@name)»_THRESHOLD «@threshold»
vb@2909
   133
vb@2870
   134
            #ifdef __cplusplus
vb@2870
   135
            extern "C" {
vb@2870
   136
            #endif
vb@2870
   137
vb@2870
   138
            // conditions
vb@2870
   139
vb@2870
   140
            ||
vb@2870
   141
            for "func:distinctName(*//condition)"
vb@2870
   142
                | PEP_STATUS «@name»(PEP_SESSION session, bool *result);
vb@2870
   143
            ||
vb@2870
   144
vb@2870
   145
            // actions
vb@2870
   146
vb@2870
   147
            ||
vb@2870
   148
            for "func:distinctName(*//action)"
vb@2870
   149
                | PEP_STATUS «@name»(PEP_SESSION session);
vb@2870
   150
            ||
vb@2870
   151
vb@2914
   152
            // timeout handler
vb@2914
   153
            
vb@2914
   154
            ||
vb@2914
   155
            for "fsm[@threshold > 0]"
vb@2914
   156
                | PEP_STATUS «@name»TimeoutHandler(PEP_SESSION session);
vb@2914
   157
            ||
vb@2914
   158
vb@2870
   159
            // send message about an event to communication partners using state
vb@2870
   160
vb@2870
   161
            PEP_STATUS send_«@name»_message(
vb@2870
   162
                    PEP_SESSION session, 
vb@2870
   163
                    «@name»_PR fsm,
vb@2870
   164
                    int message_type
vb@2870
   165
                );
vb@2870
   166
vb@2870
   167
            // receive message and store it in state
vb@2870
   168
vb@2870
   169
            PEP_STATUS recv_«@name»_event(
vb@2870
   170
                    PEP_SESSION session,
vb@2870
   171
                    «@name»_event_t *ev
vb@2870
   172
                );
krista@2271
   173
        
vb@2870
   174
            // state machine driver
vb@2870
   175
            // if fsm or event set to 0 use fields in src if present
krista@2271
   176
vb@2870
   177
            PEP_STATUS «@name»_driver(
vb@2870
   178
                    PEP_SESSION session,
vb@2870
   179
                    «@name»_PR fsm,
vb@2870
   180
                    int event
vb@2870
   181
                );
krista@2271
   182
vb@2888
   183
            // API being used by the engine internally
vb@2888
   184
vb@2888
   185
            // call this if you need to signal an external event
vb@2888
   186
vb@2880
   187
            PEP_STATUS signal_«@name»_event(
vb@2870
   188
                    PEP_SESSION session, 
vb@2870
   189
                    «@name»_PR fsm,
vb@2870
   190
                    int event
vb@2870
   191
                );
vb@2888
   192
            
vb@2889
   193
            // call this if you are a transport and are receiving
vb@2889
   194
            // a «@name» message
vb@2834
   195
vb@2888
   196
            PEP_STATUS signal_«@name»_message(
vb@2888
   197
                    PEP_SESSION session, 
vb@2888
   198
                    PEP_rating rating,
vb@2888
   199
                    const char *data,
vb@3143
   200
                    size_t size,
vb@3363
   201
                    const pEp_identity *from,
vb@3363
   202
                    const char *signature_fpr
vb@2888
   203
                );
vb@2829
   204
vb@2870
   205
            #ifdef __cplusplus
vb@2870
   206
            }
vb@2870
   207
            #endif
vb@2829
   208
vb@2870
   209
            ||
vb@2829
   210
        }
vb@2829
   211
vb@2870
   212
        document "generated/{@name}_impl.c", "text" {
vb@2870
   213
            ||
vb@2870
   214
            // This file is under GNU General Public License 3.0
vb@2870
   215
            // see LICENSE.txt
vb@2870
   216
        
vb@2870
   217
            #include "«@name»_impl.h"
vb@2870
   218
            #include "pEp_internal.h"
vb@2870
   219
            #include "«@name»_event.h"
vb@2899
   220
            #include "«yml:lcase(@name)»_codec.h"
vb@2870
   221
            #include "baseprotocol.h"
vb@2870
   222
            `` for "fsm" | #include "«@name»_fsm.h"
vb@2829
   223
vb@2909
   224
            `` apply "fsm", 0, mode=timeout
vb@2870
   225
            PEP_STATUS «@name»_driver(
vb@2870
   226
                    PEP_SESSION session,
vb@2870
   227
                    «@name»_PR fsm,
vb@2870
   228
                    int event
vb@2870
   229
                )
vb@2870
   230
            {
vb@2910
   231
                assert(session);
vb@2910
   232
                if (!session)
vb@2870
   233
                    return PEP_ILLEGAL_VALUE;
vb@2829
   234
vb@2909
   235
                switch (fsm) {
vb@2910
   236
                    case None:
vb@2910
   237
                        if (!event) {
vb@2910
   238
                            // timeout occured
vb@2910
   239
                        `` for "fsm" |>>>> «../@name»_driver(session, «../@name»_PR_«yml:lcase(@name)», None);
vb@2910
   240
                            return PEP_STATUS_OK;
vb@2910
   241
                        }
vb@2910
   242
                        return PEP_ILLEGAL_VALUE;
vb@2910
   243
vb@2909
   244
                    `` apply "fsm", mode=reset_state_machine;
vb@2909
   245
                    default:
vb@2909
   246
                        return PEP_ILLEGAL_VALUE;
vb@2909
   247
                }
vb@2909
   248
vb@2870
   249
                int next_state = None;
vb@2870
   250
                do {
vb@2870
   251
                    switch (fsm) {
vb@2870
   252
                        `` apply "fsm", 3, mode=driver               
vb@2870
   253
                        default:
vb@2870
   254
                            return PEP_ILLEGAL_VALUE;
vb@2870
   255
                    }
vb@2870
   256
                }  while (next_state);
vb@2829
   257
vb@2870
   258
                return PEP_STATUS_OK;
vb@2829
   259
            }
vb@2829
   260
vb@2880
   261
            PEP_STATUS signal_«@name»_event(
vb@2870
   262
                    PEP_SESSION session, 
vb@2870
   263
                    «@name»_PR fsm,
vb@2870
   264
                    int event
vb@2870
   265
                )
vb@2870
   266
            {
vb@2870
   267
                «@name»_t *msg = NULL;
vb@2870
   268
                «@name»_event_t *ev = NULL;
vb@2870
   269
vb@2870
   270
                assert(session && fsm > 0 && event > None);
vb@2870
   271
                if (!(session && fsm > 0 && event > None))
vb@2870
   272
                    return PEP_ILLEGAL_VALUE;
vb@2870
   273
vb@2870
   274
                PEP_STATUS status = PEP_STATUS_OK;
vb@2870
   275
vb@2888
   276
                if (!session->inject_«yml:lcase(@name)»_event)
vb@2888
   277
                   return PEP_«yml:ucase(@name)»_NO_INJECT_CALLBACK;
vb@2870
   278
vb@2870
   279
                if (event < Extra) {
vb@2870
   280
                    msg = new_«@name»_message(fsm, event);
vb@2870
   281
                    if (!msg) {
vb@2870
   282
                        status = PEP_OUT_OF_MEMORY;
vb@2888
   283
                        goto the_end;
vb@2870
   284
                    }
vb@2870
   285
vb@2870
   286
                    status = update_«@name»_message(session, msg);
vb@2870
   287
                    if (status)
vb@2888
   288
                        goto the_end;
vb@2870
   289
                }
vb@2870
   290
vb@2888
   291
                ev = new_«@name»_event(fsm, event, msg);
vb@2870
   292
                if (!ev) {
vb@2870
   293
                    status = PEP_OUT_OF_MEMORY;
vb@2888
   294
                    goto the_end;
vb@2870
   295
                }
vb@2870
   296
vb@2870
   297
                int result = session->inject_«yml:lcase(@name)»_event(ev,
vb@2870
   298
                        session->«yml:lcase(@name)»_management);
vb@2870
   299
                if (result) {
vb@2870
   300
                    status = PEP_STATEMACHINE_ERROR;
vb@2888
   301
                    goto the_end;
vb@2870
   302
                }
vb@2888
   303
                return PEP_STATUS_OK;
vb@2870
   304
vb@2870
   305
            the_end:
krista@3331
   306
                free_«@name»_event(ev); // msg gets freed here
vb@2870
   307
                return status;
vb@2870
   308
            }
vb@2870
   309
vb@2888
   310
            PEP_STATUS signal_«@name»_message(
vb@2870
   311
                    PEP_SESSION session, 
vb@2888
   312
                    PEP_rating rating,
vb@2888
   313
                    const char *data,
vb@3143
   314
                    size_t size,
vb@3363
   315
                    const pEp_identity *from,
vb@3363
   316
                    const char *signature_fpr
vb@2870
   317
                )
vb@2870
   318
            {
vb@2888
   319
                assert(session && data && size);
vb@2888
   320
                if (!(session && data && size))
vb@2870
   321
                    return PEP_ILLEGAL_VALUE;
vb@2870
   322
vb@2888
   323
                if (!session->inject_«yml:lcase(@name)»_event)
vb@2888
   324
                   return PEP_«yml:ucase(@name)»_NO_INJECT_CALLBACK;
vb@2870
   325
vb@3341
   326
                PEP_STATUS status = PEP_STATUS_OK;
vb@2890
   327
                «@name»_event_t *ev = NULL;
vb@2890
   328
vb@3363
   329
                if (from) {
vb@3363
   330
                    free_identity(session->«yml:lcase(@name)»_state.common.from);
vb@3363
   331
                    session->«yml:lcase(@name)»_state.common.from = identity_dup(from);
vb@3363
   332
                    if (!session->«yml:lcase(@name)»_state.common.from) {
vb@3363
   333
                        status = PEP_OUT_OF_MEMORY;
vb@3363
   334
                        goto the_end;
vb@3363
   335
                    }
vb@3363
   336
                }
vb@3363
   337
vb@3363
   338
                if (signature_fpr) {
vb@3363
   339
                    free(session->«yml:lcase(@name)»_state.common.signature_fpr);
vb@3363
   340
                    session->«yml:lcase(@name)»_state.common.signature_fpr = strdup(signature_fpr);
vb@3363
   341
                    if (!session->«yml:lcase(@name)»_state.common.signature_fpr) {
vb@3144
   342
                        status = PEP_OUT_OF_MEMORY;
vb@3144
   343
                        goto the_end;
vb@3144
   344
                    }
vb@3143
   345
                }
vb@3143
   346
vb@3341
   347
                «@name»_t *msg = NULL;
vb@3341
   348
                status = decode_«@name»_message(data, size, &msg);
vb@3341
   349
                if (status)
vb@3341
   350
                    return status;
vb@3341
   351
vb@3341
   352
                «@name»_PR fsm = msg->present;
vb@3341
   353
                int event = 0;
vb@3341
   354
vb@3341
   355
                switch (fsm) {
vb@3341
   356
                    `` apply "fsm", 2, mode=signal_message
vb@3341
   357
                    default:
vb@3341
   358
                        status = PEP_«yml:ucase(@name)»_ILLEGAL_MESSAGE;
vb@3341
   359
                        goto the_end;
vb@3341
   360
                }
vb@3341
   361
vb@3117
   362
                ev = new_«@name»_event(fsm, event, msg);
vb@2888
   363
                if (!ev) {
vb@2829
   364
                    status = PEP_OUT_OF_MEMORY;
vb@2888
   365
                    goto the_end;
vb@2829
   366
                }
vb@2829
   367
vb@2888
   368
                int result = session->inject_«yml:lcase(@name)»_event(ev,
vb@2888
   369
                        session->«yml:lcase(@name)»_management);
vb@2888
   370
                if (result) {
vb@2888
   371
                    status = PEP_STATEMACHINE_ERROR;
vb@2888
   372
                    goto the_end;
vb@2888
   373
                }
vb@3143
   374
vb@2888
   375
                return PEP_STATUS_OK;
vb@2870
   376
vb@2870
   377
            the_end:
krista@3331
   378
                free_«@name»_event(ev); // msg gets freed here
vb@2870
   379
                return status;
vb@2829
   380
            }
vb@2829
   381
vb@2870
   382
            PEP_STATUS send_«@name»_message(
vb@2870
   383
                    PEP_SESSION session, 
vb@2870
   384
                    «@name»_PR fsm,
vb@2870
   385
                    int message_type
vb@2870
   386
                )
vb@2870
   387
            {
vb@2870
   388
                PEP_STATUS status = PEP_STATUS_OK;
vb@2829
   389
vb@2870
   390
                assert(session && fsm > None && message_type > None);
vb@2870
   391
                if (!(session && fsm > None && message_type > None))
vb@2870
   392
                    return PEP_ILLEGAL_VALUE;
vb@2870
   393
                
vb@2870
   394
                «@name»_t *msg = new_«@name»_message(fsm, message_type);
vb@2870
   395
                if (!msg)
vb@2870
   396
                    return PEP_OUT_OF_MEMORY;
vb@2870
   397
vb@2870
   398
                char *data = NULL;
vb@2870
   399
                message *m = NULL;
vb@2870
   400
                identity_list *channels = NULL;
vb@2870
   401
vb@2870
   402
                status = update_«@name»_message(session, msg);
vb@2870
   403
                if (status)
vb@2870
   404
                    goto the_end;
vb@2870
   405
vb@2870
   406
                size_t size = 0;
vb@2870
   407
                status = encode_«@name»_message(msg, &data, &size);
vb@2870
   408
                if (status)
vb@2870
   409
                    goto the_end;
vb@2870
   410
vb@2870
   411
                switch (message_type) {
vb@2871
   412
                    // these messages are being broadcasted
vb@3509
   413
                    `` for "fsm/message[@type='broadcast']" |>> case «../@name»_PR_«yml:mixedCase(@name)»:
vb@2871
   414
                        status = _own_identities_retrieve(session, &channels, PEP_idf_not_for_«yml:lcase(@name)»);
vb@2875
   415
                        if (status)
vb@2870
   416
                            goto the_end;
vb@2871
   417
vb@2871
   418
                        if (!(channels && channels->ident)) {
vb@3240
   419
                            // status = PEP_«yml:ucase(@name)»_NO_CHANNEL;
vb@3240
   420
                            // we don't check for having a channel, because if
vb@3240
   421
                            // this is initial setup before having an own
vb@3240
   422
                            // identity we're fine
vb@2871
   423
                            goto the_end;
vb@2871
   424
                        }
vb@2870
   425
                        break;
vb@2870
   426
vb@2877
   427
                    // these go anycast; previously used address is sticky (unicast)
vb@3509
   428
                    `` for "fsm/message[@type='anycast']" |>> case «../@name»_PR_«yml:mixedCase(@name)»:
vb@2870
   429
                        if (!session->«yml:lcase(@name)»_state.common.from `> |`|
vb@2870
   430
                            (session->«yml:lcase(@name)»_state.common.from->flags &
vb@2871
   431
                            PEP_idf_not_for_«yml:lcase(@name)»)) {
vb@2870
   432
vb@2870
   433
                            // no address available yet, try to find one
vb@2871
   434
                            status = _own_identities_retrieve(session, &channels, PEP_idf_not_for_«yml:lcase(@name)»);
vb@2870
   435
                            if (!status)
vb@2870
   436
                                goto the_end;
vb@2870
   437
                            break;
vb@2870
   438
vb@2870
   439
                            if (channels && channels->ident) {
vb@2870
   440
                                // only need the first one
vb@2870
   441
                                free_identity_list(channels->next);
vb@2870
   442
                                channels->next = NULL;
vb@2870
   443
                            }
vb@2870
   444
                            else {
vb@2871
   445
                                status = PEP_«yml:ucase(@name)»_NO_CHANNEL;
vb@2870
   446
                                goto the_end;
vb@2870
   447
                            }
vb@2870
   448
                        }
vb@2870
   449
                        else {
vb@2870
   450
                            pEp_identity *channel = identity_dup(session->«yml:lcase(@name)»_state.common.from);
vb@2870
   451
                            if (!channel) {
vb@2870
   452
                                status = PEP_OUT_OF_MEMORY;
vb@2870
   453
                                goto the_end;
vb@2870
   454
                            }
vb@2870
   455
vb@2870
   456
                            channels = new_identity_list(channel);
vb@2870
   457
                            if (!channels) {
vb@2870
   458
                                status = PEP_OUT_OF_MEMORY;
vb@2870
   459
                                goto the_end;
vb@2870
   460
                            }
vb@2870
   461
                        }
vb@3340
   462
                        break;
vb@2877
   463
vb@2877
   464
                    default:
vb@2877
   465
                        status = PEP_«yml:ucase(@name)»_ILLEGAL_MESSAGE;
vb@2877
   466
                        goto the_end;
vb@2870
   467
                }
vb@2870
   468
vb@2870
   469
                for (identity_list *li = channels; li && li->ident ; li = li->next) {
vb@2878
   470
                    message *_m = NULL;
vb@2944
   471
                    char *_data = NULL;
vb@2944
   472
                    
vb@2944
   473
                    _data = malloc(size);
vb@2944
   474
                    assert(_data);
vb@2944
   475
                    if (!_data) {
vb@2944
   476
                        status = PEP_OUT_OF_MEMORY;
vb@2944
   477
                        goto the_end;
vb@2944
   478
                    }
vb@2944
   479
                    memcpy(_data, data, size);
vb@2875
   480
vb@3509
   481
                    stringlist_t *extra = NULL;
vb@3509
   482
vb@2878
   483
                    switch (message_type) {
vb@3509
   484
                    `` for "fsm/message[@security='unencrypted']" |>>> case «../@name»_PR_«yml:mixedCase(@name)»:
vb@3129
   485
                            status = base_prepare_message(
vb@3143
   486
                                    session,
vb@3129
   487
                                    li->ident,
vb@3129
   488
                                    li->ident,
vb@3129
   489
                                    _data,
vb@3129
   490
                                    size,
vb@3129
   491
                                    li->ident->fpr,
vb@3393
   492
                                    NULL,
vb@3129
   493
                                    &_m
vb@3129
   494
                                );
vb@3129
   495
                            if (status) {
vb@3129
   496
                                free(_data);
vb@3129
   497
                                goto the_end;
vb@3129
   498
                            }
Thomas@3127
   499
                            attach_own_key(session, _m);
vb@2878
   500
                            m = _m;
vb@2878
   501
                            break;
vb@2878
   502
vb@3509
   503
                    `` for "fsm/message[@security='attach_own_keys']" |>>> case «../@name»_PR_«yml:mixedCase(@name)»:
vb@3393
   504
                            status = base_prepare_message(
vb@3393
   505
                                    session,
vb@3393
   506
                                    li->ident,
vb@3393
   507
                                    li->ident,
vb@3393
   508
                                    _data,
vb@3393
   509
                                    size,
vb@3393
   510
                                    NULL,
vb@3393
   511
                                    &session->«yml:lcase(@name)»_state.common.own_keys,
vb@3393
   512
                                    &_m
vb@3393
   513
                                );
vb@3393
   514
                            if (status) {
vb@3393
   515
                                free(_data);
vb@3393
   516
                                goto the_end;
vb@3393
   517
                            }
vb@3509
   518
vb@3509
   519
                            assert(session->«yml:lcase(@name)»_state.common.signature_fpr);
vb@3509
   520
                            if (!session->«yml:lcase(@name)»_state.common.signature_fpr) {
vb@3509
   521
                                status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
vb@3509
   522
                                goto the_end;
vb@3509
   523
                            }
vb@3509
   524
vb@3509
   525
                            extra = new_stringlist(session->«yml:lcase(@name)»_state.common.signature_fpr);
vb@3509
   526
                            if (extra) {
vb@3509
   527
                                status = encrypt_message(session, _m, extra, &m, PEP_enc_PEP, 0);
vb@3509
   528
                                free_stringlist(extra);
vb@3509
   529
                            }
vb@3509
   530
                            else {
vb@3509
   531
                                status = PEP_OUT_OF_MEMORY;
vb@3509
   532
                            }
vb@3393
   533
                            if (status) {
vb@3393
   534
                                status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
vb@3393
   535
                                goto the_end;
vb@3393
   536
                            }
vb@3393
   537
                            free_message(_m);
vb@3393
   538
                            break;
vb@3393
   539
vb@2878
   540
                        default:
vb@3129
   541
                            status = base_prepare_message(
vb@3143
   542
                                    session,
vb@3129
   543
                                    li->ident,
vb@3129
   544
                                    li->ident,
vb@3129
   545
                                    _data,
vb@3129
   546
                                    size,
vb@3129
   547
                                    NULL,
vb@3393
   548
                                    NULL,
vb@3129
   549
                                    &_m
vb@3129
   550
                                );
vb@3129
   551
                            if (status) {
vb@3129
   552
                                free(_data);
vb@3129
   553
                                goto the_end;
vb@3129
   554
                            }
vb@3509
   555
vb@3509
   556
                            assert(session->«yml:lcase(@name)»_state.common.signature_fpr);
vb@3509
   557
                            if (!session->«yml:lcase(@name)»_state.common.signature_fpr) {
vb@3509
   558
                                status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
vb@3509
   559
                                goto the_end;
vb@3509
   560
                            }
vb@3509
   561
vb@3509
   562
                            stringlist_t *extra = new_stringlist(session->«yml:lcase(@name)»_state.common.signature_fpr);
vb@3509
   563
                            if (extra) {
vb@3509
   564
                                status = encrypt_message(session, _m, extra, &m, PEP_enc_PEP, 0);
vb@3509
   565
                                free_stringlist(extra);
vb@3509
   566
                            }
vb@3509
   567
                            else {
vb@3509
   568
                                status = PEP_OUT_OF_MEMORY;
vb@3509
   569
                            }
vb@2879
   570
                            if (status) {
vb@2899
   571
                                status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
vb@2878
   572
                                goto the_end;
vb@2879
   573
                            }
vb@2878
   574
                            free_message(_m);
vb@2878
   575
                    }
vb@2878
   576
vb@2899
   577
                    status = session->messageToSend(m);
vb@2870
   578
                    m = NULL;
vb@2870
   579
                }
vb@2870
   580
vb@2870
   581
            the_end:
vb@2870
   582
                free_identity_list(channels);
vb@2870
   583
                free_message(m);
vb@2870
   584
                free(data);
vb@2870
   585
                free_«@name»_message(msg);
vb@2870
   586
                return status;
vb@2829
   587
            }
vb@2829
   588
vb@2870
   589
            PEP_STATUS recv_«@name»_event(
vb@2870
   590
                    PEP_SESSION session,
vb@2870
   591
                    «@name»_event_t *ev
vb@2870
   592
                )
vb@2870
   593
            {
vb@2870
   594
                assert(session && ev);
vb@2870
   595
                if (!(session && ev))
vb@2870
   596
                    return PEP_ILLEGAL_VALUE;
vb@2829
   597
vb@2870
   598
                PEP_STATUS status = PEP_STATUS_OK;
vb@2888
   599
                «@name»_PR fsm = (int) None;
vb@2888
   600
                int event = None;
vb@2829
   601
vb@2910
   602
                if (ev->event > None && ev->event < Extra) {
vb@2870
   603
                    status = update_«@name»_state(session, ev->msg, &fsm, &event);
vb@2870
   604
                    if (status)
vb@2888
   605
                        goto the_end;
vb@2829
   606
vb@2870
   607
                    if (ev->fsm) {
vb@2870
   608
                        if (ev->fsm != fsm |`> |` ev->event != event) {
vb@2870
   609
                            status = PEP_«yml:ucase(@name)»_ILLEGAL_MESSAGE;
vb@2888
   610
                            goto the_end;
vb@2870
   611
                        }
vb@2870
   612
                    }
vb@2888
   613
                    else if (ev->event) {
vb@2888
   614
                        status = PEP_«yml:ucase(@name)»_ILLEGAL_MESSAGE;
vb@2888
   615
                        goto the_end;
vb@2870
   616
                    }
vb@2870
   617
                }
vb@2888
   618
                else {
vb@2888
   619
                    fsm = ev->fsm;
vb@2888
   620
                    event = ev->event;
vb@2888
   621
                }
vb@2829
   622
vb@2888
   623
                status = «@name»_driver(session, fsm, event);
vb@2870
   624
vb@2888
   625
            the_end:
krista@3331
   626
                //free_«@name»_event(ev); // FIXME: We don't own this pointer. Are we sure it gets freed externally?
vb@2870
   627
                return status;
vb@2829
   628
            }
vb@2829
   629
vb@2870
   630
            ||
vb@2829
   631
        }
vb@2829
   632
vb@2829
   633
        apply "fsm", 0, mode=gen;
vb@2829
   634
    }
vb@2829
   635
vb@2909
   636
    template "fsm", mode=timeout
vb@2909
   637
    ||
vb@2909
   638
    static bool _«@name»_timeout(int state)
vb@2909
   639
    {
vb@2909
   640
        static int last_state = None;
vb@2909
   641
        static time_t switch_time = 0;
vb@2909
   642
vb@2909
   643
        if (state > Init) {
vb@2909
   644
            if (state == last_state) {
vb@2909
   645
                if (time(NULL) - switch_time > «yml:ucase(@name)»_THRESHOLD) {
vb@2909
   646
                    last_state = None;
vb@2909
   647
                    switch_time = 0;
vb@2909
   648
                    return true;
vb@2909
   649
                }
vb@2909
   650
            }
vb@2909
   651
            else {
vb@2909
   652
                last_state = state;
vb@2909
   653
                switch_time = time(NULL);
vb@2909
   654
            }
vb@2909
   655
        }
vb@2909
   656
        else {
vb@2909
   657
            last_state = None;
vb@2909
   658
            switch_time = 0;
vb@2909
   659
        }
vb@2909
   660
vb@2909
   661
        return false;
vb@2909
   662
    }
vb@2909
   663
vb@2909
   664
    ||
vb@2909
   665
vb@2909
   666
    template "fsm", mode=reset_state_machine
vb@2909
   667
    ||
vb@2909
   668
        case «../@name»_PR_«yml:lcase(@name)»: {
vb@2909
   669
            int state = session->«yml:lcase(../@name)»_state.«yml:lcase(@name)».state;
vb@2909
   670
            switch (state) {
vb@2909
   671
                `` for "state[@name!='InitState' and @timeout != 'off']" |>>> case «@name»:
vb@2909
   672
                    if (_«@name»_timeout(state)) {
vb@2909
   673
                        session->«yml:lcase(../@name)»_state.«yml:lcase(@name)».state = Init;
vb@2909
   674
                        event = Init;
vb@2914
   675
                        `` if "@threshold > 0" |>>>>> «@name»TimeoutHandler(session);
vb@2909
   676
                    }
vb@2909
   677
                    break;
vb@2909
   678
                
vb@2909
   679
                default:
vb@2909
   680
                    _«@name»_timeout(None);
vb@2909
   681
            }
vb@2909
   682
            break;
vb@2909
   683
        }
vb@2909
   684
vb@2909
   685
    ||
vb@2909
   686
vb@2890
   687
    template "fsm", mode=signal_message
vb@2890
   688
    {
vb@2890
   689
        ||
vb@2890
   690
        case «../@name»_PR_«yml:lcase(@name)»:
vb@3509
   691
            switch (msg->choice.«yml:lcase(@name)».present) {
vb@2891
   692
        ||
vb@2891
   693
        if "message[@security='unencrypted']" {
vb@3338
   694
            |>> // these messages require a detached signature
vb@3338
   695
            for "message[@security='unencrypted']" {
vb@2891
   696
            ||
vb@3509
   697
                    case «../@name»_PR_«yml:mixedCase(@name)»:
vb@3363
   698
                        if (!signature_fpr) {
vb@3146
   699
                            status = PEP_«yml:ucase(ancestor::protocol/@name)»_ILLEGAL_MESSAGE;
vb@3146
   700
                            goto the_end;
vb@3146
   701
                        }
vb@3338
   702
                        event = «@name»;
vb@3117
   703
                        break;
vb@2890
   704
vb@2891
   705
            ||
vb@3338
   706
            }
vb@2891
   707
        }
vb@3338
   708
        if "message[@security='untrusted']" {
vb@3338
   709
            |>> // these messages must arrive encrypted
vb@3338
   710
            for "message[@security='untrusted']" {
vb@3338
   711
            ||
vb@3509
   712
                    case «../@name»_PR_«yml:mixedCase(@name)»:
vb@3339
   713
                        if (rating < PEP_rating_reliable) {
vb@3338
   714
                            status = PEP_«yml:ucase(ancestor::protocol/@name)»_ILLEGAL_MESSAGE;
vb@3338
   715
                            goto the_end;
vb@3338
   716
                        }
vb@3338
   717
                        event = «@name»;
vb@3338
   718
                        break;
vb@3338
   719
vb@3338
   720
            ||
vb@3338
   721
            }
vb@3338
   722
        }
vb@3338
   723
        if "message[@security='trusted']" {
vb@3338
   724
            |>> // these messages must come through a trusted channel
vb@3338
   725
            for "message[@security='trusted']" {
vb@3338
   726
            ||
vb@3509
   727
                    case «../@name»_PR_«yml:mixedCase(@name)»:
vb@3339
   728
                        if (rating < PEP_rating_trusted) {
vb@3338
   729
                            status = PEP_«yml:ucase(ancestor::protocol/@name)»_ILLEGAL_MESSAGE;
vb@3338
   730
                            goto the_end;
vb@3338
   731
                        }
vb@3338
   732
                        event = «@name»;
vb@3338
   733
                        break;
vb@3338
   734
vb@3338
   735
            ||
vb@3338
   736
            }
vb@3338
   737
        }
vb@2891
   738
        ||
vb@2890
   739
                default:
vb@2890
   740
                    status = PEP_«yml:ucase(ancestor::protocol/@name)»_ILLEGAL_MESSAGE;
vb@2890
   741
                    goto the_end;
vb@2890
   742
            }
vb@2890
   743
            break;
vb@2890
   744
vb@2890
   745
        ||
vb@2890
   746
    }
vb@2890
   747
vb@2838
   748
    template "fsm", mode=event
vb@2838
   749
    {
vb@2838
   750
    ||
vb@2843
   751
    case «../@name»_PR_«yml:lcase(@name)»: {
vb@3509
   752
        switch (msg->choice.«yml:lcase(@name)».present) {
vb@2838
   753
    ||
vb@2838
   754
    for "message"
vb@2838
   755
    ||
vb@3509
   756
            case «../@name»_PR_«yml:mixedCase(@name)»:
vb@2838
   757
                ev->event = «@name»;
vb@2838
   758
                break;
vb@2838
   759
    ||
vb@2838
   760
    ||
vb@2838
   761
            default:
vb@2838
   762
                // unknown message type
vb@2838
   763
                free(ev);
vb@2838
   764
                return NULL;
vb@2838
   765
        }
vb@2838
   766
        break;
vb@2838
   767
    }
vb@2838
   768
vb@2838
   769
    ||
vb@2838
   770
    }
vb@2838
   771
vb@2829
   772
    template "fsm", mode=driver
vb@2829
   773
    ||
vb@2843
   774
    case «../@name»_PR_«yml:lcase(@name)»: {
vb@2839
   775
        int state = session->«yml:lcase(../@name)»_state.«yml:lcase(@name)».state;
vb@2839
   776
        next_state = fsm_«@name»(session, state, event);
vb@2838
   777
        if (next_state > None) {
vb@2838
   778
            session->«yml:lcase(../@name)»_state.«yml:lcase(@name)».state = next_state;
vb@2838
   779
            event = Init;
vb@2838
   780
        }
vb@2838
   781
        else if (next_state < None) {
Hussein@3167
   782
            return PEP_STATEMACHINE_ERROR - next_state;
vb@2838
   783
        }
vb@2829
   784
        break;
vb@2829
   785
    }
vb@2829
   786
vb@2829
   787
    ||
vb@2829
   788
vb@2829
   789
    template "fsm", mode=gen {
vb@2829
   790
        document "generated/{@name}_fsm.h", "text" {
vb@2829
   791
        ||
vb@2829
   792
        // This file is under GNU General Public License 3.0
vb@2829
   793
        // see LICENSE.txt
vb@2829
   794
vb@2829
   795
        #pragma once
vb@2829
   796
vb@2829
   797
        #include "«../@name»_impl.h"
vb@2829
   798
vb@2829
   799
        #ifdef __cplusplus
vb@2829
   800
        extern "C" {
vb@2829
   801
        #endif
vb@2829
   802
vb@2829
   803
        // state machine for «@name»
krista@2271
   804
krista@2271
   805
        // states
krista@2271
   806
krista@2271
   807
        typedef enum _«@name»_state {
vb@2829
   808
            «@name»_state_None = None,
vb@2829
   809
            «@name»_state_Init = Init,
vb@2829
   810
        ||
vb@2829
   811
        for "func:distinctName(state[not(@name='InitState')])"
vb@2829
   812
            |> «@name»`if "position()!=last()" > , `
vb@2829
   813
        ||
krista@2271
   814
        } «@name»_state;
krista@2271
   815
krista@2271
   816
        // events
krista@2271
   817
krista@2271
   818
        typedef enum _«@name»_event {
vb@2829
   819
            «@name»_event_None = None,
vb@2829
   820
            «@name»_event_Init = Init,
krista@2271
   821
        ||
vb@3388
   822
        for "message" {
krista@2271
   823
            const "name", "@name";
vb@2829
   824
            |> «$name» = «/protocol/fsm/message[@name=$name]/@id»,
krista@2271
   825
        }
vb@2829
   826
        |> «@name»_event_Extra = Extra,
vb@3387
   827
        for "external" {
vb@3385
   828
            if "@id < 128"
vb@3385
   829
                error > external «@name» must have ID >= 128 but it's «@id»
vb@3384
   830
            |> «@name» = «@id»,
vb@3385
   831
        }
vb@2830
   832
        for "func:distinctName(state/event[not(../../message/@name=@name or ../../external/@name=@name)])" {
vb@2829
   833
            if "@name!='Init'"
vb@2829
   834
                |> «@name»`if "position()!=last()" > , `
vb@2829
   835
        }
krista@2271
   836
        ||
krista@2271
   837
        } «@name»_event;
krista@2271
   838
vb@2829
   839
        // state machine
krista@2271
   840
vb@2829
   841
        const char *«@name»_state_name(int state);
vb@2881
   842
        const char *«@name»_event_name(int event);
krista@2271
   843
vb@2838
   844
        // the state machine function is returning the next state in case of a
vb@2838
   845
        // transition or None for staying
vb@2838
   846
krista@2271
   847
        «@name»_state fsm_«@name»(
krista@2271
   848
                PEP_SESSION session,
krista@2271
   849
                «@name»_state state,
vb@2829
   850
                «@name»_event event
krista@2271
   851
            );
krista@2271
   852
krista@2271
   853
        #ifdef __cplusplus
krista@2271
   854
        }
krista@2271
   855
        #endif
krista@2271
   856
krista@2271
   857
        ||
krista@2271
   858
        }
vb@2829
   859
vb@2829
   860
        document "generated/{@name}_fsm.c", "text" {
krista@2271
   861
        ||
vb@2829
   862
        // This file is under GNU General Public License 3.0
vb@2829
   863
        // see LICENSE.txt
krista@2271
   864
vb@2829
   865
        #include "«@name»_fsm.h"
vb@2847
   866
        #include <stdlib.h>
krista@2271
   867
vb@2829
   868
        const char *«@name»_state_name(int state)
vb@2829
   869
        {
vb@2829
   870
            switch (state) {
vb@2829
   871
                case End:
vb@2829
   872
                    return "End";
vb@2829
   873
                case None:
vb@2829
   874
                    return "None";
vb@2829
   875
                case Init:
vb@2829
   876
                    return "InitState";
vb@2829
   877
        ||
vb@2829
   878
        for "func:distinctName(state[not(@name='InitState')])" {
vb@2829
   879
            |>> case «@name»:
vb@2829
   880
            |>>> return "«@name»";
vb@2829
   881
        }
vb@2829
   882
        ||
vb@2829
   883
                default:
vb@2829
   884
                    return "unknown state";
vb@2829
   885
            }
vb@2829
   886
        }
krista@2271
   887
vb@2881
   888
        const char *«@name»_event_name(int event)
vb@2881
   889
        {
vb@2881
   890
            switch (event) {
vb@2881
   891
                case None:
vb@2881
   892
                    return "None";
vb@2881
   893
                case Init:
vb@2881
   894
                    return "Init";
vb@2881
   895
        ||
vb@2881
   896
        for "func:distinctName(state/event[not(@name='Init')])" {
vb@2881
   897
            |>> case «@name»:
vb@2881
   898
            |>>> return "«@name»";
vb@2881
   899
        }
vb@2881
   900
        ||
vb@2881
   901
                default:
vb@2881
   902
                    return "unknown event";
vb@2881
   903
            }
vb@2881
   904
        }
vb@2881
   905
vb@2881
   906
vb@2829
   907
        static char *_str(int n, bool hex)
vb@2829
   908
        {
vb@2829
   909
            char *buf = calloc(1, 24);
vb@2829
   910
            assert(buf);
vb@2829
   911
            if (!buf)
vb@2829
   912
                return NULL;
vb@2829
   913
vb@2829
   914
            if (hex)
vb@2829
   915
                snprintf(buf, 24, "%.4x", n);
vb@2829
   916
            else
vb@2829
   917
                snprintf(buf, 24, "%d", n);
vb@2829
   918
            return buf;
vb@2829
   919
        }
vb@2829
   920
vb@2829
   921
        #define «@name»_ERR_LOG(t, d) log_event(session, (t), "«@name»", (d), "error")
vb@2829
   922
vb@2829
   923
        static PEP_STATUS _«@name»_ERR_LOG_int(PEP_SESSION session, char *t, int n, bool hex)
vb@2829
   924
        {
vb@2829
   925
            char *_buf = _str(n, hex);
vb@2829
   926
            if (!_buf)
vb@2829
   927
                return PEP_OUT_OF_MEMORY;
vb@2829
   928
            PEP_STATUS status = «@name»_ERR_LOG(t, _buf);
vb@2829
   929
            free(_buf);
vb@2829
   930
            return status;
vb@2829
   931
        }
vb@2829
   932
vb@2829
   933
        #define «@name»_ERR_LOG_INT(t, n) _«@name»_ERR_LOG_int(session, (t), (n), false)
vb@2829
   934
        #define «@name»_ERR_LOG_HEX(t, n) _«@name»_ERR_LOG_int(session, (t), (n), true)
vb@2829
   935
        #define «@name»_SERVICE_LOG(t, d) SERVICE_LOG(session, (t), "«@name»", (d))
vb@2829
   936
vb@2829
   937
        «@name»_state fsm_«@name»(
krista@2271
   938
                PEP_SESSION session,
vb@2829
   939
                «@name»_state state,
vb@2829
   940
                «@name»_event event
krista@2271
   941
            )
krista@2271
   942
        {
krista@2271
   943
            assert(session);
krista@2271
   944
            if (!session)
vb@2829
   945
                return invalid_state;
krista@2271
   946
vb@3365
   947
            if (state == None)
vb@3365
   948
                state = «@name»_state_Init;
vb@3365
   949
krista@2271
   950
            switch (state) {
vb@2829
   951
                `` apply "state", 2, mode=fsm
krista@2271
   952
                default:
vb@2838
   953
                    «@name»_ERR_LOG_INT("invalid state", state);
vb@2829
   954
                    return invalid_state;
krista@2271
   955
            }
vb@2829
   956
            
vb@2838
   957
            return None;
krista@2271
   958
        }
krista@2271
   959
krista@2271
   960
        ||
vb@2829
   961
        }
vb@2829
   962
    }
vb@2829
   963
    
vb@2829
   964
    template "state", mode=fsm {
vb@2829
   965
        choose {
vb@2829
   966
            when "@name='InitState'" | case «../@name»_state_Init:
vb@2829
   967
            otherwise | case «@name»:
vb@2829
   968
        }
vb@2829
   969
        ||
vb@2829
   970
            «../@name»_SERVICE_LOG("in state", "«@name»");
vb@2829
   971
vb@2829
   972
            switch (event) {
vb@3366
   973
                case None:
vb@3366
   974
                    «../@name»_SERVICE_LOG("received None event", "ignoring");
vb@3366
   975
                    break;
vb@3366
   976
     
vb@2838
   977
        ||
vb@2838
   978
        if "not(event[@name='Init'])"
vb@2838
   979
        ||
vb@2838
   980
                case Init:
vb@3379
   981
                    «../@name»_SERVICE_LOG("received Init but nothing to do", "Init");
vb@2838
   982
                    break;
vb@2838
   983
vb@2838
   984
        ||
vb@2838
   985
        ||
vb@2829
   986
                `` apply "event", 2, mode=fsm
vb@2829
   987
                default:
vb@2885
   988
                    // ignore events not handled here
vb@2885
   989
                    «../@name»_SERVICE_LOG("ignoring event", KeySync_event_name(event));
vb@3362
   990
                    return invalid_event;
vb@2829
   991
            }
vb@2829
   992
            break;
vb@2829
   993
vb@2829
   994
        ||
krista@2271
   995
    }
krista@2271
   996
vb@2829
   997
    template "event", mode=fsm {
vb@2829
   998
        | case «@name»: {
vb@2865
   999
        if "condition|action|send" |> PEP_STATUS status;
vb@2829
  1000
        if "condition" |> bool result = false;
vb@2865
  1001
        if "condition|action|send" |
krista@2271
  1002
        ||
vb@2829
  1003
            «../../@name»_SERVICE_LOG("received event", "«@name»");
vb@2907
  1004
            `` apply "transition|action|condition|else|send";
vb@2829
  1005
        ||
vb@2829
  1006
        if "name(*[last()])!='transition'" {
vb@2829
  1007
            |
vb@2843
  1008
            |> «../../@name»_SERVICE_LOG("remaining in state", "«../@name»");
vb@2829
  1009
            |> break;
vb@2829
  1010
        }
vb@2829
  1011
        ||
vb@2829
  1012
        }
vb@2829
  1013
        
vb@2829
  1014
        ||
vb@2829
  1015
    }
vb@2829
  1016
vb@2829
  1017
    template "transition" {
vb@2865
  1018
        const "fsm", "ancestor::fsm";
krista@2271
  1019
        ||
krista@2271
  1020
vb@2829
  1021
        «$fsm/@name»_SERVICE_LOG("transition to state", "«@target»");
vb@2838
  1022
        return «@target»;
krista@2271
  1023
        ||
vb@2829
  1024
    }
krista@2271
  1025
vb@2865
  1026
    template "send" {
vb@2865
  1027
        const "fsm", "ancestor::fsm";
vb@2865
  1028
        const "protocol", "ancestor::protocol";
vb@2865
  1029
        ||
vb@2865
  1030
vb@2865
  1031
        «$fsm/@name»_SERVICE_LOG("send message", "«@name»");
vb@3509
  1032
        status = send_«$protocol/@name»_message(session, «$fsm/@id», «$fsm/@name»_PR_«yml:mixedCase(@name)»);
vb@3089
  1033
        if (status == PEP_OUT_OF_MEMORY)
vb@3089
  1034
            return out_of_memory;
vb@3089
  1035
        if (status) {
vb@3089
  1036
            «$fsm/@name»_ERR_LOG_HEX("sending «@name» failed", status);
vb@3089
  1037
            return cannot_send;
vb@3089
  1038
        }
vb@2865
  1039
        ||
vb@2865
  1040
    }
vb@2865
  1041
vb@2829
  1042
    template "action" {
vb@2865
  1043
        const "fsm", "ancestor::fsm";
vb@2865
  1044
        ||
vb@2829
  1045
vb@2865
  1046
        «$fsm/@name»_SERVICE_LOG("do action", "«@name»");
vb@2865
  1047
        status = «@name»(session);
vb@3089
  1048
        if (status == PEP_OUT_OF_MEMORY)
vb@3089
  1049
            return out_of_memory;
vb@2829
  1050
        if (status) {
vb@2829
  1051
            «$fsm/@name»_ERR_LOG_HEX("executing action «@name»() failed", status);
vb@2829
  1052
            return invalid_action;
krista@2271
  1053
        }
krista@2271
  1054
        ||
krista@2271
  1055
    }
krista@2271
  1056
vb@2829
  1057
    template "condition" {
vb@2865
  1058
        const "fsm", "ancestor::fsm";
krista@2271
  1059
        ||
krista@2271
  1060
vb@2829
  1061
        status = «@name»(session, &result);
vb@3089
  1062
        if (status == PEP_OUT_OF_MEMORY)
vb@3089
  1063
            return out_of_memory;
vb@2829
  1064
        if (status) {
vb@2829
  1065
            «$fsm/@name»_ERR_LOG_HEX("computing condition «@name» failed", status);
vb@2829
  1066
            return invalid_condition;
krista@2271
  1067
        }
vb@2829
  1068
        if (result) {
vb@2843
  1069
            «$fsm/@name»_SERVICE_LOG("condition applies", "«@name»");
krista@2271
  1070
        ||
vb@2907
  1071
        apply "transition|action|condition|else|send";
vb@2907
  1072
        | }
vb@2907
  1073
    }
vb@2907
  1074
vb@2907
  1075
    template "else" {
vb@2907
  1076
        if "not(name(preceding-sibling::*[last()]) = 'condition')"
vb@2907
  1077
            error "else without if";
vb@2907
  1078
vb@2907
  1079
        | else {
vb@2907
  1080
        |> «ancestor::fsm/@name»_SERVICE_LOG("condition does not apply", "«preceding-sibling::*[last()]/@name»");
vb@2907
  1081
        apply "transition|action|condition|else|send";
krista@2271
  1082
        | }
krista@2271
  1083
    }
krista@2271
  1084
}