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