Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

gdp / gdp / gdp_proto.c @ master

History | View | Annotate | Download (24.5 KB)

1
/* vim: set ai sw=4 sts=4 ts=4 :*/
2

    
3
/*
4
**        This implements the GDP Protocol.
5
**
6
**        In the future this may need to be extended to have knowledge of
7
**        TSN/AVB, but for now we don't worry about that.
8
**
9
**        ----- BEGIN LICENSE BLOCK -----
10
**        GDP: Global Data Plane Support Library
11
**        From the Ubiquitous Swarm Lab, 490 Cory Hall, U.C. Berkeley.
12
**
13
**        Copyright (c) 2015-2019, Regents of the University of California.
14
**        All rights reserved.
15
**
16
**        Permission is hereby granted, without written agreement and without
17
**        license or royalty fees, to use, copy, modify, and distribute this
18
**        software and its documentation for any purpose, provided that the above
19
**        copyright notice and the following two paragraphs appear in all copies
20
**        of this software.
21
**
22
**        IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
23
**        SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
24
**        PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
25
**        EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
**
27
**        REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
28
**        LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
29
**        FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION,
30
**        IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO
31
**        OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
32
**        OR MODIFICATIONS.
33
**        ----- END LICENSE BLOCK -----
34
*/
35

    
36
#include "gdp.h"
37
#include "gdp_chan.h"
38
#include "gdp_event.h"
39
#include "gdp_priv.h"
40

    
41
#include <ep/ep_dbg.h>
42
#include <ep/ep_log.h>
43

    
44
#include <string.h>
45
#include <sys/errno.h>
46

    
47

    
48
static EP_DBG        Dbg = EP_DBG_INIT("gdp.proto", "GDP protocol processing");
49
static EP_DBG        DbgCmdTrace = EP_DBG_INIT("gdp.proto.command.trace",
50
                                                        "GDP command execution tracing");
51

    
52

    
53

    
54
/*
55
**        GDP_INVOKE --- do a remote invocation to the GDP daemon
56
**
57
**                This acts as an remote procedure call.  In particular it
58
**                waits to get a result, which makes it inappropriate for
59
**                instances where multiple commands are in flight, or
60
**                where a command can return multiple values (e.g., subscribe).
61
**
62
**                The req must be locked before this is called.
63
*/
64

    
65
EP_STAT
66
_gdp_invoke(gdp_req_t *req)
67
{
68
        EP_STAT estat = EP_STAT_OK;
69
        EP_TIME_SPEC abs_to;
70
        long delta_to;                                // how long to wait for a response
71
        bool retry;                                        // retry the command
72
        int retries;                                // how many times to retry
73
        long retry_delay;                        // how long to delay between retries
74
        EP_TIME_SPEC delta_ts;
75
        const char *cmdname;
76
        EP_TIME_SPEC starttime;
77

    
78
        ep_time_now(&starttime);
79
        EP_ASSERT_POINTER_VALID(req);
80
        GDP_MSG_CHECK(req->cpdu, return EP_STAT_ASSERT_ABORT);
81
        if (req->gob != NULL)
82
                GDP_GOB_ASSERT_ISLOCKED(req->gob);
83
        cmdname = _gdp_proto_cmd_name(req->cpdu->msg->cmd);
84
        if (ep_dbg_test(Dbg, 11))
85
        {
86
                ep_dbg_printf("\n>>> _gdp_invoke(req=%p rid=%" PRIgdp_rid "): %s (%d), gob@%p\n",
87
                                req,
88
                                req->cpdu->msg->rid,
89
                                cmdname,
90
                                req->cpdu->msg->cmd,
91
                                req->gob);
92
                if (ep_dbg_test(Dbg, 11))
93
                {
94
                        ep_dbg_printf("%s", _gdp_pr_indent(1));
95
                        _gdp_pdu_dump(req->cpdu, ep_dbg_getfile(), 1);
96
                }
97
        }
98
        EP_ASSERT_ELSE(req->state == GDP_REQ_ACTIVE, return EP_STAT_ASSERT_ABORT);
99
        EP_THR_MUTEX_ASSERT_ISLOCKED(&req->mutex);
100

    
101
        // scale timeout to milliseconds
102
        delta_to = ep_adm_getlongparam("swarm.gdp.invoke.timeout", 10000L);
103
        ep_time_from_nsec(delta_to * INT64_C(1000000), &delta_ts);
104
        retry_delay = ep_adm_getlongparam("swarm.gdp.invoke.retrydelay", 5000L);
105

    
106
        // loop to allow for retransmissions
107
        retries = ep_adm_getintparam("swarm.gdp.invoke.retries", 3);
108
        if (retries < 1)
109
                retries = 1;
110
        do
111
        {
112
                /*
113
                **  Top Half: sending the command
114
                */
115

    
116
                ep_dbg_cprintf(Dbg, 36,
117
                                "_gdp_invoke: sending %d, retries=%d\n",
118
                                req->cpdu->msg->cmd, retries);
119

    
120
                retry = false;
121
                estat = _gdp_req_send(req);
122
                EP_STAT_CHECK(estat, continue);
123

    
124
                /*
125
                **  Bottom Half: read the response
126
                */
127

    
128
                // wait until we receive a result
129
                ep_time_deltanow(&delta_ts, &abs_to);
130
                estat = EP_STAT_OK;
131
                req->state = GDP_REQ_WAITING;
132
                req->flags &= ~GDP_REQ_ASYNCIO;
133
                while (!EP_UT_BITSET(GDP_REQ_DONE, req->flags))
134
                {
135
                        // release the GOB while we're waiting
136
                        if (req->gob != NULL)
137
                                _gdp_gob_unlock(req->gob);
138

    
139
                        // cond_wait will unlock the mutex
140
                        ep_dbg_cprintf(Dbg, 37, "_gdp_invoke: waiting on %p\n", req);
141
                        int e = ep_thr_cond_wait(&req->cond, &req->mutex, &abs_to);
142
                        ep_dbg_cprintf(Dbg, 37, "_gdp_invoke: continuing %p\n", req);
143

    
144
                        // re-acquire GOB lock
145
                        if (req->gob != NULL)
146
                        {
147
                                // have to unlock the req so lock ordering is right
148
                                //XXX possible race condition?
149
                                _gdp_req_unlock(req);
150
                                _gdp_gob_lock(req->gob);
151
                                _gdp_req_lock(req);
152
                        }
153

    
154
                        char ebuf[100];
155
                        ep_dbg_cprintf(Dbg, 52,
156
                                        "_gdp_invoke wait: got %d, done=%d, state=%d,\n"
157
                                        "    stat=%s\n",
158
                                        e, EP_UT_BITSET(GDP_REQ_DONE, req->flags), req->state,
159
                                        ep_stat_tostr(req->stat, ebuf, sizeof ebuf));
160
                        if (e != 0)
161
                        {
162
                                estat = ep_stat_from_errno(e);
163
                                if (e == ETIMEDOUT)                        // retry on timeouts
164
                                        retry = true;
165
                                break;
166
                        }
167
                }
168

    
169
                if (ep_dbg_test(Dbg, 46))
170
                {
171
                        char e1buf[100], e2buf[100];
172
                        ep_dbg_printf(
173
                                        "_gdp_invoke: after cond_wait, estat %s, req->stat %s\n",
174
                                        ep_stat_tostr(estat, e1buf, sizeof e1buf),
175
                                        ep_stat_tostr(req->stat, e2buf, sizeof e2buf));
176
                }
177
                req->state = GDP_REQ_ACTIVE;
178
                if (EP_STAT_ISOK(estat))
179
                {
180
                        estat = req->stat;
181

    
182
                        // determine if this is something we can recover from
183
                        if (EP_STAT_IS_SAME(estat, GDP_STAT_NAK_NOROUTE) &&
184
                                        !EP_UT_BITSET(GDP_REQ_ROUTEFAIL, req->flags))
185
                                retry = true;
186
                }
187

    
188
                // (maybe) do a retry, after re-locking the GOB
189
                if (retry)
190
                {
191
                        estat = _gdp_req_unsend(req);
192
                        EP_STAT_CHECK(estat, break);
193
                        estat = GDP_STAT_INVOKE_TIMEOUT;
194
                        if (retries > 1)
195
                        {
196
                                // if ETIMEDOUT, maybe the router had a glitch:
197
                                //   wait and try again
198
                                ep_time_nanosleep(retry_delay MILLISECONDS);
199
                        }
200
                }
201
        } while (retry && --retries > 0);
202

    
203
        // if we had any pending asynchronous events, deliver them
204
        _gdp_event_trigger_pending(req, false);
205

    
206
        if (ep_dbg_test(Dbg, 11))
207
        {
208
                char ebuf[200];
209

    
210
                flockfile(ep_dbg_getfile());
211
                ep_dbg_printf("<<< _gdp_invoke(%p rid=%" PRIgdp_rid ") %s: %s\n",
212
                                req, req->cpdu->msg->rid, cmdname,
213
                                ep_stat_tostr(estat, ebuf, sizeof ebuf));
214
                _gdp_show_elapsed("_gdp_invoke", req->cpdu->msg->cmd, &starttime);
215
                if (ep_dbg_test(Dbg, 22))
216
                {
217
                        _gdp_req_dump(req, ep_dbg_getfile(), GDP_PR_DETAILED, 0);
218
                        ep_dbg_printf("\n");
219
                }
220
                funlockfile(ep_dbg_getfile());
221
        }
222
        return estat;
223
}
224

    
225

    
226

    
227
/***********************************************************************
228
**
229
**        Protocol processing (CMD/ACK/NAK)
230
**
231
**                All of these take as parameters:
232
**                        req --- the request information (including PDU header)
233
**
234
**                They can return GDP_STAT_KEEP_READING to tell the upper
235
**                layer that the whole PDU hasn't been read yet.
236
**
237
***********************************************************************/
238

    
239
typedef struct
240
{
241
        cmdfunc_t        *func;                // function to call
242
        const char        *name;                // name of command (for debugging)
243
        EP_STAT                estat;                // corresponding status
244
} dispatch_ent_t;
245

    
246
static EP_STAT        get_default_estat(gdp_cmd_t);
247

    
248

    
249
/*
250
**  Common code for ACKs and NAKs
251
**
252
**                When called, the ack/nak PDU should be in req->rpdu.
253
*/
254

    
255
static EP_STAT
256
acknak(gdp_req_t *req, const char *where, bool reuse_pdu)
257
{
258
        EP_STAT estat = EP_STAT_WARN;
259
        const char *emsg = NULL;
260

    
261
        // we require a request
262
        if (req == NULL)
263
        {
264
                estat = GDP_STAT_PROTOCOL_FAIL;
265
                emsg = "null request";
266
                goto fail0;
267
        }
268

    
269
        GDP_MSG_CHECK(req->rpdu, return EP_STAT_ASSERT_ABORT);
270

    
271
        ep_dbg_cprintf(Dbg, 20, "%s: received %s for %s\n", where,
272
                        req->rpdu == NULL ? "???" : _gdp_proto_cmd_name(req->rpdu->msg->cmd),
273
                        req->cpdu == NULL ? "???" : _gdp_proto_cmd_name(req->cpdu->msg->cmd));
274

    
275
        // we want to re-use caller's datum for (e.g.) read commands
276
        if (req->rpdu == req->cpdu)
277
        {
278
                emsg = "acknak: req->rpdu == req->cpdu";
279
        }
280
        else
281
        {
282
                estat = get_default_estat(req->rpdu->msg->cmd);
283
        }
284

    
285
fail0:
286
        if (!EP_STAT_ISOK(estat))
287
        {
288
                if (EP_STAT_ISSEVERE(estat))
289
                {
290
                        ep_log(estat, "%s: %s",
291
                                        where,
292
                                        emsg != NULL ? emsg : "unknown severe failure");
293
                }
294
                else if (ep_dbg_test(Dbg, EP_STAT_ISWARN(estat) ? 10 : 1))
295
                {
296
                        char ebuf[100];
297
                        if (emsg != NULL)
298
                                ep_dbg_printf("%s: %s: %s\n",
299
                                                where, emsg,
300
                                                ep_stat_tostr(estat, ebuf, sizeof ebuf));
301
                        else
302
                                ep_dbg_printf("%s: %s\n",
303
                                                where, ep_stat_tostr(estat, ebuf, sizeof ebuf));
304
                }
305
                if (emsg != NULL && ep_dbg_test(Dbg, 1))
306
                        _gdp_req_dump(req, NULL, GDP_PR_DETAILED, 0);
307
        }
308
        return estat;
309
}
310

    
311

    
312
/*
313
**  ACKs (success)
314
*/
315

    
316
// 2xx --- all successful acks
317
static EP_STAT
318
ack(gdp_req_t *req, const char *where)
319
{
320
        EP_STAT estat;
321

    
322
        estat = acknak(req, where, true);
323
        if (EP_STAT_ISFAIL(estat))
324
                return estat;
325

    
326
        // mark this request as active (for subscriptions)
327
        ep_time_now(&req->act_ts);
328

    
329
        estat = GDP_STAT_FROM_ACK(req->rpdu->msg->cmd);
330
        return estat;
331
}
332

    
333

    
334
// 200 --- generic success
335
static EP_STAT
336
ack_success(gdp_req_t *req)
337
{
338
        EP_STAT estat;
339
        gdp_gob_t *gob;
340

    
341
        estat = ack(req, "ack_success");
342
        if (EP_STAT_ISFAIL(estat))
343
                goto fail0;
344

    
345
        //        If we started with no gob id, adopt from incoming PDU.
346
        //        This can happen when creating a GOB.
347
        gob = req->gob;
348
        if (gob != NULL && !gdp_name_is_valid(gob->name))
349
        {
350
                memcpy(gob->name, req->rpdu->src, sizeof gob->name);
351
                gdp_printable_name(gob->name, gob->pname);
352
        }
353

    
354
        // keep track of next sequence number in case async data following
355
        req->seqnext = (req->rpdu->seqno + 1) % GDP_SEQNO_BASE;
356

    
357
        // if this is an open response, the GOB is now fully open
358
        if (gob != NULL)
359
                gob->flags &= ~GOBF_PENDING;
360

    
361
fail0:
362
        return estat;
363
}
364

    
365
// 204 --- response to append command
366
static EP_STAT
367
ack_data_changed(gdp_req_t *req)
368
{
369
        EP_STAT estat;
370

    
371
        estat = ack(req, "ack_data_changed");
372
        EP_STAT_CHECK(estat, return estat);
373

    
374
        EP_ASSERT_ELSE(req->rpdu->msg->body_case ==
375
                                                GDP_MESSAGE__BODY_ACK_CHANGED,
376
                                return EP_STAT_ASSERT_ABORT);
377

    
378
        // keep track of number of records (in case we lose sync)
379
        if (req->gob != NULL)
380
                req->gob->nrecs = req->rpdu->msg->ack_changed->recno;
381

    
382
        return estat;
383
}
384

    
385
// 205 --- response to read or subscribe command
386
static EP_STAT
387
ack_data_content(gdp_req_t *req)
388
{
389
        EP_STAT estat;
390

    
391
        EP_ASSERT_ELSE(req->gob != NULL, return EP_STAT_ASSERT_ABORT);
392
        GDP_MSG_CHECK(req->rpdu, return EP_STAT_ASSERT_ABORT);
393

    
394
        estat = ack(req, "ack_data_content");
395
        EP_STAT_CHECK(estat, return estat);
396

    
397
        EP_ASSERT_ELSE(req->rpdu->msg->body_case ==
398
                                                GDP_MESSAGE__BODY_ACK_CONTENT,
399
                                return EP_STAT_ASSERT_ABORT);
400
        GdpMessage__AckContent *payload = req->rpdu->msg->ack_content;
401

    
402
        if (ep_dbg_test(Dbg, 25))
403
        {
404
                ep_dbg_printf("ack_data_content(%zd): ", payload->dl->n_d);
405
                if (payload->dl->n_d == 1)
406
                        ep_dbg_printf(" recno %"PRIgdp_recno "\n",
407
                                        payload->dl->d[0]->recno);
408
                else if (payload->dl->n_d > 1)
409
                        ep_dbg_printf(" recno %"PRIgdp_recno " - %"PRIgdp_recno "\n",
410
                                        payload->dl->d[0]->recno,
411
                                        payload->dl->d[payload->dl->n_d - 1]->recno);
412
        }
413

    
414
        // if we returned zero content, handle specially
415
        //TODO: should put all datums into event queue here rather than
416
        //TODO: up the call stack.
417
        if (payload->dl->n_d != 1)
418
        {
419
                if (ep_dbg_test(Dbg, 1))
420
                {
421
                        ep_dbg_printf("ack_data_content: %zd datums in ",
422
                                        payload->dl->n_d);
423
                        _gdp_req_dump(req, NULL, GDP_PR_BASIC, 0);
424
                }
425
                if (payload->dl->n_d < 1)
426
                        return GDP_STAT_RECORD_MISSING;                //XXX better choice?
427
                //XXX should we return an error here?  Not fully implemented yet
428
        }
429

    
430
        // check the signature on the last datum in the PDU
431
        GdpDatum *pbdatum = payload->dl->d[payload->dl->n_d - 1];
432
        gdp_datum_t *datum = gdp_datum_new();                // inefficient
433
        _gdp_datum_from_pb(datum, pbdatum, pbdatum->sig);
434

    
435
        if (EP_UT_BITSET(GDP_REQ_VRFY_CONTENT, req->flags))
436
        {
437
                char ebuf[100];
438

    
439
                estat = _gdp_datum_vrfy_gob(datum, req->gob);
440
                ep_dbg_cprintf(Dbg, EP_STAT_ISOK(estat) ? 44 : 24,
441
                                "ack_data_content: vrfy %s\n",
442
                                ep_stat_tostr(estat, ebuf, sizeof ebuf));
443
        }
444

    
445
        // hack to try to "self heal" in case we get out of sync
446
        if (datum->recno > 0 &&
447
                        ((gdp_recno_t) req->gob->nrecs) < datum->recno)
448
                req->gob->nrecs = datum->recno;
449

    
450
        // keep track of how many more records we expect
451
        if (req->numrecs > 0)
452
                req->numrecs -= payload->dl->n_d;
453

    
454
        // ... and how many we actually got
455
        req->r_results += payload->dl->n_d;
456
        if (req->s_results >= 0 && req->r_results >= req->s_results)
457
                req->flags &= ~GDP_REQ_PERSIST;
458

    
459
#if 0 //TODO: IMPLEMENT ME
460
        // do read filtering if requested
461
        if (req->gin != NULL && req->gin->readfilter != NULL)
462
                estat = req->gin->readfilter(req->rpdu->datum, req->gin->readfpriv);
463
#endif //TODO
464

    
465
        gdp_datum_free(datum);
466
        return estat;
467
}
468

    
469

    
470
// 263 --- no more results to come
471
static EP_STAT
472
ack_end_results(gdp_req_t *req)
473
{
474
        EP_STAT estat;
475

    
476
        EP_ASSERT_ELSE(req->gob != NULL, return EP_STAT_ASSERT_ABORT);
477
        GDP_MSG_CHECK(req->rpdu, return EP_STAT_ASSERT_ABORT);
478

    
479
        estat = ack(req, "ack_end_results");
480
        if (EP_STAT_ISFAIL(estat))
481
                return estat;
482

    
483
        EP_ASSERT_ELSE(req->rpdu->msg->body_case ==
484
                                                GDP_MESSAGE__BODY_ACK_END_OF_RESULTS,
485
                                return EP_STAT_ASSERT_ABORT);
486
        GdpMessage__AckEndOfResults *payload = req->rpdu->msg->ack_end_of_results;
487

    
488
        // don't need to check has_nresults, since the default is what we want
489
        req->s_results = payload->nresults;
490
        ep_dbg_cprintf(Dbg, req->r_results == req->s_results ? 15 : 10,
491
                        "ack_end_results: read %"PRId64 " sent %"PRId64 "\n",
492
                        req->r_results, req->s_results);
493
        if (req->r_results >= req->s_results)
494
        {
495
                _gdp_event_trigger_pending(req, true);
496
                req->flags &= ~GDP_REQ_PERSIST;
497
        }
498

    
499
        return EP_STAT_OK;
500
}
501

    
502

    
503
/*
504
**  NAKs (failures)
505
*/
506

    
507
static EP_STAT
508
nak(gdp_req_t *req, const char *where)
509
{
510
        EP_STAT estat;
511

    
512
        estat = acknak(req, where, true);
513
        return estat;
514
}
515

    
516

    
517
static EP_STAT
518
nak_client(gdp_req_t *req)
519
{
520
        return nak(req, "nak_client");
521
}
522

    
523

    
524
static EP_STAT
525
nak_server(gdp_req_t *req)
526
{
527
        return nak(req, "nak_server");
528
}
529

    
530

    
531
static EP_STAT
532
nak_router(gdp_req_t *req)
533
{
534
        return acknak(req, "nak_router", false);
535
}
536

    
537

    
538
// called when a record number has been repeated
539
static EP_STAT
540
nak_conflict(gdp_req_t *req)
541
{
542
        EP_STAT estat = nak_client(req);
543

    
544
        EP_STAT_CHECK(estat, return estat);
545
        GDP_MSG_CHECK(req->rpdu, return EP_STAT_ASSERT_ABORT);
546
        EP_ASSERT_ELSE(req->rpdu->msg->body_case ==
547
                                                GDP_MESSAGE__BODY_NAK_CONFLICT,
548
                                return EP_STAT_ASSERT_ABORT);
549

    
550
        // adjust nrecs to match the server's view
551
        if (req->gob != NULL)
552
                req->gob->nrecs = req->rpdu->msg->nak_conflict->recno;
553

    
554
        return estat;
555
}
556

    
557

    
558

    
559
/*
560
**        Command/Ack/Nak Dispatch Table
561
*/
562

    
563
#define NOENT                { NULL, NULL, GDP_STAT_NOT_IMPLEMENTED }
564

    
565
static dispatch_ent_t        DispatchTable[256] =
566
{
567
        { NULL,                                "CMD_KEEPALIVE",        EP_STAT_OK                                        },        // 0
568
        { NULL,                                "CMD_ADVERTISE",        EP_STAT_OK                                        },        // 1
569
        { NULL,                                "CMD_WITHDRAW",                EP_STAT_OK                                        },        // 2
570
        NOENT,                                // 3
571
        NOENT,                                // 4
572
        NOENT,                                // 5
573
        NOENT,                                // 6
574
        NOENT,                                // 7
575
        NOENT,                                // 8
576
        NOENT,                                // 9
577
        NOENT,                                // 10
578
        NOENT,                                // 11
579
        NOENT,                                // 12
580
        NOENT,                                // 13
581
        NOENT,                                // 14
582
        NOENT,                                // 15
583
        NOENT,                                // 16
584
        NOENT,                                // 17
585
        NOENT,                                // 18
586
        NOENT,                                // 19
587
        NOENT,                                // 20
588
        NOENT,                                // 21
589
        NOENT,                                // 22
590
        NOENT,                                // 23
591
        NOENT,                                // 24
592
        NOENT,                                // 25
593
        NOENT,                                // 26
594
        NOENT,                                // 27
595
        NOENT,                                // 28
596
        NOENT,                                // 29
597
        NOENT,                                // 30
598
        NOENT,                                // 31
599
        NOENT,                                // 32
600
        NOENT,                                // 33
601
        NOENT,                                // 34
602
        NOENT,                                // 35
603
        NOENT,                                // 36
604
        NOENT,                                // 37
605
        NOENT,                                // 38
606
        NOENT,                                // 39
607
        NOENT,                                // 40
608
        NOENT,                                // 41
609
        NOENT,                                // 42
610
        NOENT,                                // 43
611
        NOENT,                                // 44
612
        NOENT,                                // 45
613
        NOENT,                                // 46
614
        NOENT,                                // 47
615
        NOENT,                                // 48
616
        NOENT,                                // 49
617
        NOENT,                                // 50
618
        NOENT,                                // 51
619
        NOENT,                                // 52
620
        NOENT,                                // 53
621
        NOENT,                                // 54
622
        NOENT,                                // 55
623
        NOENT,                                // 56
624
        NOENT,                                // 57
625
        NOENT,                                // 58
626
        NOENT,                                // 59
627
        NOENT,                                // 60
628
        NOENT,                                // 61
629
        NOENT,                                // 62
630
        NOENT,                                // 63
631
        { NULL,                                "CMD_PING",                                GDP_STAT_ACK_SUCCESS                },        // 64
632
        { NULL,                                "CMD_HELLO",                        GDP_STAT_ACK_SUCCESS                },        // 65
633
        { NULL,                                "CMD_CREATE",                        GDP_STAT_ACK_SUCCESS                },        // 66
634
        { NULL,                                "CMD_OPEN_AO",                        GDP_STAT_ACK_SUCCESS                },        // 67
635
        { NULL,                                "CMD_OPEN_RO",                        GDP_STAT_ACK_SUCCESS                },        // 68
636
        { NULL,                                "CMD_OPEN_RA",                        GDP_STAT_ACK_SUCCESS                },        // 69
637
        { NULL,                                "CMD_CLOSE",                        GDP_STAT_ACK_SUCCESS                },        // 70
638
        { NULL,                                "CMD_APPEND",                        GDP_STAT_ACK_SUCCESS                },        // 71
639
        { NULL,                                "CMD_READ_BY_RECNO",        GDP_STAT_ACK_SUCCESS                },        // 72
640
        { NULL,                                "CMD_READ_BY_TS",                GDP_STAT_ACK_SUCCESS                },        // 73
641
        { NULL,                                "CMD_READ_BY_HASH",                GDP_STAT_ACK_SUCCESS                },        // 74
642
        { NULL,                                "CMD_SUBSCRIBE_BY_RECNO", GDP_STAT_ACK_SUCCESS                },        // 75
643
        { NULL,                                "CMD_SUBSCRIBE_BY_TS",        GDP_STAT_ACK_SUCCESS                },        // 76
644
        { NULL,                                "CMD_SUBSCRIBE_BY_HASH", GDP_STAT_ACK_SUCCESS                },        // 77
645
        { NULL,                                "CMD_UNSUBSCRIBE",                GDP_STAT_ACK_SUCCESS                },        // 78
646
        { NULL,                                "CMD_GETMETADATA",                GDP_STAT_ACK_SUCCESS                },        // 79
647
        { NULL,                                "CMD_NEWSEGMENT",                GDP_STAT_ACK_SUCCESS                },        // 80
648
        { NULL,                                "CMD_DELETE",                        GDP_STAT_ACK_SUCCESS                },        // 81
649
        NOENT,                                // 82
650
        NOENT,                                // 83
651
        NOENT,                                // 84
652
        NOENT,                                // 85
653
        NOENT,                                // 86
654
        NOENT,                                // 87
655
        NOENT,                                // 88
656
        NOENT,                                // 89
657
        NOENT,                                // 90
658
        NOENT,                                // 91
659
        NOENT,                                // 92
660
        NOENT,                                // 93
661
        NOENT,                                // 94
662
        NOENT,                                // 95
663
        NOENT,                                // 96
664
        NOENT,                                // 97
665
        NOENT,                                // 98
666
        NOENT,                                // 99
667
        NOENT,                                // 100
668
        NOENT,                                // 101
669
        NOENT,                                // 102
670
        NOENT,                                // 103
671
        NOENT,                                // 104
672
        NOENT,                                // 105
673
        NOENT,                                // 106
674
        NOENT,                                // 107
675
        NOENT,                                // 108
676
        NOENT,                                // 109
677
        NOENT,                                // 110
678
        NOENT,                                // 111
679
        NOENT,                                // 112
680
        NOENT,                                // 113
681
        NOENT,                                // 114
682
        NOENT,                                // 115
683
        NOENT,                                // 116
684
        NOENT,                                // 117
685
        NOENT,                                // 118
686
        NOENT,                                // 119
687
        NOENT,                                // 120
688
        NOENT,                                // 121
689
        NOENT,                                // 122
690
        NOENT,                                // 123
691
        NOENT,                                // 124
692
        NOENT,                                // 125
693
        NOENT,                                // 126
694
        { NULL,                                "CMD_FWD_APPEND",                GDP_STAT_ACK_SUCCESS                },        // 127
695
        { ack_success,                "ACK_SUCCESS",                        GDP_STAT_ACK_SUCCESS                },        // 128
696
        { ack_success,                "ACK_DATA_CREATED",                GDP_STAT_ACK_CREATED                },        // 129
697
        { ack_success,                "ACK_DATA_DEL",                        GDP_STAT_ACK_DELETED                },        // 130
698
        { ack_success,                "ACK_DATA_VALID",                GDP_STAT_ACK_VALID                        },        // 131
699
        { ack_data_changed,        "ACK_DATA_CHANGED",                GDP_STAT_ACK_CHANGED                },        // 132
700
        { ack_data_content,        "ACK_DATA_CONTENT",                GDP_STAT_ACK_CONTENT                },        // 133
701
        NOENT,                                // 134
702
        NOENT,                                // 135
703
        NOENT,                                // 136
704
        NOENT,                                // 137
705
        NOENT,                                // 138
706
        NOENT,                                // 139
707
        NOENT,                                // 140
708
        NOENT,                                // 141
709
        NOENT,                                // 142
710
        NOENT,                                // 143
711
        NOENT,                                // 144
712
        NOENT,                                // 145
713
        NOENT,                                // 146
714
        NOENT,                                // 147
715
        NOENT,                                // 148
716
        NOENT,                                // 149
717
        NOENT,                                // 150
718
        NOENT,                                // 151
719
        NOENT,                                // 152
720
        NOENT,                                // 153
721
        NOENT,                                // 154
722
        NOENT,                                // 155
723
        NOENT,                                // 156
724
        NOENT,                                // 157
725
        NOENT,                                // 158
726
        NOENT,                                // 159
727
        NOENT,                                // 160
728
        NOENT,                                // 161
729
        NOENT,                                // 162
730
        NOENT,                                // 163
731
        NOENT,                                // 164
732
        NOENT,                                // 165
733
        NOENT,                                // 166
734
        NOENT,                                // 167
735
        NOENT,                                // 168
736
        NOENT,                                // 169
737
        NOENT,                                // 170
738
        NOENT,                                // 171
739
        NOENT,                                // 172
740
        NOENT,                                // 173
741
        NOENT,                                // 174
742
        NOENT,                                // 175
743
        NOENT,                                // 176
744
        NOENT,                                // 177
745
        NOENT,                                // 178
746
        NOENT,                                // 179
747
        NOENT,                                // 180
748
        NOENT,                                // 181
749
        NOENT,                                // 182
750
        NOENT,                                // 183
751
        NOENT,                                // 184
752
        NOENT,                                // 185
753
        NOENT,                                // 186
754
        NOENT,                                // 187
755
        NOENT,                                // 188
756
        NOENT,                                // 189
757
        NOENT,                                // 190
758
        { ack_end_results,        "ACK_END_OF_RESULTS",        GDP_STAT_ACK_END_OF_RESULTS        },        // 191
759

    
760
        { nak_client,                "NAK_C_BADREQ",                        GDP_STAT_NAK_BADREQ                        },        // 192
761
        { nak_client,                "NAK_C_UNAUTH",                        GDP_STAT_NAK_UNAUTH                        },        // 193
762
        { nak_client,                "NAK_C_BADOPT",                        GDP_STAT_NAK_BADOPT                        },        // 194
763
        { nak_client,                "NAK_C_FORBIDDEN",                GDP_STAT_NAK_FORBIDDEN                },        // 195
764
        { nak_client,                "NAK_C_NOTFOUND",                GDP_STAT_NAK_NOTFOUND                },        // 196
765
        { nak_client,                "NAK_C_METHNOTALLOWED",        GDP_STAT_NAK_METHNOTALLOWED        },        // 197
766
        { nak_client,                "NAK_C_NOTACCEPTABLE",        GDP_STAT_NAK_NOTACCEPTABLE        },        // 198
767
        NOENT,                                // 199
768
        NOENT,                                // 200
769
        { nak_conflict,                "NAK_C_CONFLICT",                GDP_STAT_NAK_CONFLICT                },        // 201
770
        { nak_client,                "NAK_C_GONE",                        GDP_STAT_NAK_GONE                        },        // 202
771
        NOENT,                                // 203
772
        { nak_client,                "NAK_C_PRECONFAILED",        GDP_STAT_NAK_PRECONFAILED        },        // 204
773
        { nak_client,                "NAK_C_TOOLARGE",                GDP_STAT_NAK_TOOLARGE                },        // 205
774
        NOENT,                                // 206
775
        { nak_client,                "NAK_C_UNSUPMEDIA",                GDP_STAT_NAK_UNSUPMEDIA                },        // 207
776
        NOENT,                                // 208
777
        NOENT,                                // 209
778
        NOENT,                                // 210
779
        NOENT,                                // 211
780
        NOENT,                                // 212
781
        NOENT,                                // 213
782
        NOENT,                                // 214
783
        NOENT,                                // 215
784
        NOENT,                                // 216
785
        NOENT,                                // 217
786
        NOENT,                                // 218
787
        NOENT,                                // 219
788
        NOENT,                                // 220
789
        NOENT,                                // 221
790
        { nak_client,                "NAK_C_MISSING_RECORD",        GDP_STAT_NAK_REC_MISSING        },        // 222
791
        { nak_client,                "NAK_C_REC_DUP",                GDP_STAT_NAK_REC_DUP                },        // 223
792

    
793
        { nak_server,                "NAK_S_INTERNAL",                GDP_STAT_NAK_INTERNAL                },        // 224
794
        { nak_server,                "NAK_S_NOTIMPL"        ,                GDP_STAT_NAK_NOTIMPL                },        // 225
795
        { nak_server,                "NAK_S_BADGATEWAY",                GDP_STAT_NAK_BADGATEWAY                },        // 226
796
        { nak_server,                "NAK_S_SVCUNAVAIL",                GDP_STAT_NAK_SVCUNAVAIL                },        // 227
797
        { nak_server,                "NAK_S_GWTIMEOUT",                GDP_STAT_NAK_GWTIMEOUT                },        // 228
798
        { nak_server,                "NAK_S_PROXYNOTSUP",        GDP_STAT_NAK_PROXYNOTSUP        },        // 229
799
        NOENT,                                // 230
800
        NOENT,                                // 231
801
        NOENT,                                // 232
802
        NOENT,                                // 233
803
        NOENT,                                // 234
804
        NOENT,                                // 235
805
        NOENT,                                // 236
806
        NOENT,                                // 237
807
        { nak_server,                "NAK_S_REC_MISSING",        GDP_STAT_NAK_REC_MISSING        },        // 238
808
        { nak_server,                "NAK_S_LOSTSUB",                GDP_STAT_NAK_LOST_SUBSCR        },        // 239
809

    
810
        { nak_router,                "NAK_R_NOROUTE",                GDP_STAT_NAK_NOROUTE                },        // 240
811
        NOENT,                                // 241
812
        NOENT,                                // 242
813
        NOENT,                                // 243
814
        NOENT,                                // 244
815
        NOENT,                                // 245
816
        NOENT,                                // 246
817
        NOENT,                                // 247
818
        NOENT,                                // 248
819
        NOENT,                                // 249
820
        NOENT,                                // 250
821
        NOENT,                                // 251
822
        NOENT,                                // 252
823
        NOENT,                                // 253
824
        NOENT,                                // 254
825
        NOENT,                                // 255
826
};
827

    
828

    
829
/*
830
**        _GDP_CMD_NAME --- return name of command
831
*/
832

    
833
const char *
834
_gdp_proto_cmd_name(uint8_t cmd)
835
{
836
        dispatch_ent_t *d;
837

    
838
        if (cmd >= 0 && cmd <= 255 && (d = &DispatchTable[cmd])->name != NULL)
839
        {
840
                return d->name;
841
        }
842
        else
843
        {
844
                // not thread safe, but shouldn't happen
845
                static char buf[10];
846

    
847
                snprintf(buf, sizeof buf, "%d", cmd);
848
                return buf;
849
        }
850
}
851

    
852
static EP_STAT
853
get_default_estat(gdp_cmd_t cmd)
854
{
855
        return DispatchTable[cmd].estat;
856
}
857

    
858

    
859
/*
860
**  Add any additional command functions.
861
**                Applications that add additional functionality (e.g.,
862
**                gdplogd) can add implementations by calling this function.
863
*/
864

    
865
void
866
_gdp_register_cmdfuncs(struct cmdfuncs *cf)
867
{
868
        for (; cf->func != NULL; cf++)
869
        {
870
                DispatchTable[cf->cmd].func = cf->func;
871
        }
872
}
873

    
874

    
875
/*
876
**  Called for unimplemented commands
877
*/
878

    
879
static EP_STAT
880
cmd_not_implemented(gdp_req_t *req)
881
{
882
        // just ignore unknown commands
883
        if (ep_dbg_test(Dbg, 1))
884
        {
885
                flockfile(ep_dbg_getfile());
886
                ep_dbg_printf("_gdp_req_dispatch: Unknown cmd, req:\n");
887
                _gdp_req_dump(req, ep_dbg_getfile(), GDP_PR_BASIC, 0);
888
                funlockfile(ep_dbg_getfile());
889
        }
890

    
891
        return _gdp_req_nak_resp(req, GDP_NAK_C_BADREQ,
892
                                        "Command not implemented", GDP_STAT_NOT_IMPLEMENTED);
893
}
894

    
895

    
896
/*
897
**  Dispatch command to implementation function.
898
**
899
**                The req should be locked when this is called.
900
*/
901

    
902
EP_STAT
903
_gdp_req_dispatch(gdp_req_t *req, int cmd)
904
{
905
        EP_STAT estat;
906
        dispatch_ent_t *d;
907
        gdp_pname_t pname;
908
        EP_TIME_SPEC starttime;
909

    
910
        ep_time_now(&starttime);
911
        if (req->gob != NULL)
912
        {
913
                memcpy(pname, req->gob->pname, sizeof pname);
914
                GDP_GOB_ASSERT_ISLOCKED(req->gob);
915
        }
916
        else
917
        {
918
                pname[0] = '\0';
919
        }
920
        if (ep_dbg_test(Dbg, 28) || ep_dbg_test(DbgCmdTrace, 28))
921
        {
922
                flockfile(ep_dbg_getfile());
923
                ep_dbg_printf("_gdp_req_dispatch(%p -> %p) >>> %s",
924
                                req, req->gob, _gdp_proto_cmd_name(cmd));
925
                if (pname[0] != '\0')
926
                        ep_dbg_printf("(%s)", req->gob->pname);
927
                if (req->gob != NULL && ep_dbg_test(Dbg, 70))
928
                                ep_dbg_printf(" [gob->refcnt %d]", req->gob->refcnt);
929
                ep_dbg_printf("\n");
930
                if (ep_dbg_test(Dbg, 51))
931
                        _gdp_req_dump(req, NULL, GDP_PR_DETAILED, 0);
932
                funlockfile(ep_dbg_getfile());
933
        }
934

    
935
        d = &DispatchTable[cmd];
936
        if (d->func == NULL)
937
                estat = cmd_not_implemented(req);
938
        else
939
                estat = (*d->func)(req);
940

    
941
        // command function should not change lock state of GOB
942
        if (req->gob != NULL && !GDP_GOB_ASSERT_ISLOCKED(req->gob))
943
                _gdp_gob_dump(req->gob, NULL, GDP_PR_DETAILED, 0);
944

    
945
        if (ep_dbg_test(Dbg, 18) || ep_dbg_test(DbgCmdTrace, 18))
946
        {
947
                char ebuf[200];
948

    
949
                flockfile(ep_dbg_getfile());
950
                ep_dbg_printf("_gdp_req_dispatch <<< %s",
951
                                _gdp_proto_cmd_name(cmd));
952
                if (pname[0] != '\0')
953
                        ep_dbg_printf("(%s)", pname);
954
                else if (req->gob != NULL && req->gob->pname[0] != '\0')
955
                        ep_dbg_printf("(%s)", req->gob->pname);
956
                if (req->gob != NULL && ep_dbg_test(Dbg, 70))
957
                        ep_dbg_printf(" [gob->refcnt %d]", req->gob->refcnt);
958
                ep_dbg_printf(": %s\n", ep_stat_tostr(estat, ebuf, sizeof ebuf));
959
                if (ep_dbg_test(Dbg, 70))
960
                        _gdp_req_dump(req, NULL, GDP_PR_BASIC, 0);
961
                funlockfile(ep_dbg_getfile());
962
        }
963
        _gdp_show_elapsed("_gdp_req_dispatch", cmd, &starttime);
964

    
965
        return estat;
966
}
967

    
968

    
969
/*
970
**  Advertise me only
971
*/
972

    
973
EP_STAT
974
_gdp_advertise_me(gdp_chan_t *chan, int cmd, void *adata)
975
{
976
        EP_STAT estat;
977
        gdp_chan_advert_cr_t *cr_cb = NULL;                        //XXX XXX
978
        gdp_adcert_t *adcert = NULL;                                //XXX XXX
979
        estat = _gdp_chan_advertise(chan, _GdpMyRoutingName, adcert, cr_cb, adata);
980
        if (EP_STAT_ISOK(estat))
981
                estat = _gdp_chan_advert_commit(chan);
982
        return estat;
983
}