~ubuntu-branches/debian/experimental/ion/experimental

« back to all changes in this revision

Viewing changes to cfdp/library/libcfdpP.c

  • Committer: Package Import Robot
  • Author(s): Leo Iannacone
  • Date: 2012-02-01 09:46:31 UTC
  • Revision ID: package-import@ubuntu.com-20120201094631-qpfwehc1b7ftkjgx
Tags: upstream-2.5.3~dfsg1
ImportĀ upstreamĀ versionĀ 2.5.3~dfsg1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *      libcfdpP.c:     functions enabling the implementation of
 
3
 *                      CFDP entities.
 
4
 *
 
5
 *      Copyright (c) 2009, California Institute of Technology.
 
6
 *      ALL RIGHTS RESERVED.  U.S. Government Sponsorship acknowledged.
 
7
 *
 
8
 *      Author: Scott Burleigh, JPL
 
9
 *
 
10
 */
 
11
 
 
12
#include "cfdpP.h"
 
13
#include "lyst.h"
 
14
 
 
15
#define CFDPDEBUG       0
 
16
 
 
17
/*      *       *       Helpful utility functions       *       *       */
 
18
 
 
19
static Object   _cfdpdbObject(Object *newDbObj)
 
20
{
 
21
        static Object   obj = 0;
 
22
 
 
23
        if (newDbObj)
 
24
        {
 
25
                obj = *newDbObj;
 
26
        }
 
27
 
 
28
        return obj;
 
29
}
 
30
 
 
31
static CfdpDB   *_cfdpConstants()
 
32
{
 
33
        static CfdpDB   buf;
 
34
        static CfdpDB   *db = NULL;
 
35
 
 
36
        if (db == NULL)
 
37
        {
 
38
                /*      Load constants into a conveniently accessed
 
39
                 *      structure.  Note that this CANNOT be treated
 
40
                 *      as a current database image in later
 
41
                 *      processing.                                     */
 
42
 
 
43
                sdr_read(getIonsdr(), (char *) &buf, _cfdpdbObject(NULL),
 
44
                                sizeof(CfdpDB));
 
45
                db = &buf;
 
46
        }
 
47
 
 
48
        return db;
 
49
}
 
50
 
 
51
#ifdef TargetFFS
 
52
typedef struct
 
53
{
 
54
        char            *fileName;
 
55
        int             fileExists;
 
56
        pthread_cond_t  *cv;
 
57
} StatParms;
 
58
 
 
59
static void     *checkFileExists(void *parm)
 
60
{
 
61
        StatParms       *parms = (StatParms *) parm;
 
62
        int             result;
 
63
        struct stat     statbuf;
 
64
 
 
65
        result = stat(parms->fileName, &statbuf);
 
66
 
 
67
        /*      If hang on trying to find and open the file, wait
 
68
         *      until parent thread times out and cancels this one.
 
69
         *      Otherwise, depending on stat() result, indicate
 
70
         *      whether or not the file exists and return.              */
 
71
 
 
72
        if (result < 0)
 
73
        {
 
74
                parms->fileExists = 0;
 
75
        }
 
76
        else
 
77
        {
 
78
                parms->fileExists = 1;
 
79
        }
 
80
 
 
81
        /*      If no delay on opening the file, then the parent
 
82
         *      thread is still waiting on the condition variable,
 
83
         *      in which case we need to signal it right away.  In
 
84
         *      any case, no harm in signaling it.                      */
 
85
 
 
86
        pthread_cond_signal(parms->cv);
 
87
        return NULL;
 
88
}
 
89
#endif
 
90
 
 
91
int     checkFile(char *fileName)
 
92
{
 
93
#ifdef TargetFFS
 
94
        StatParms       parms;
 
95
        pthread_mutex_t mutex;
 
96
        pthread_cond_t  cv;
 
97
        pthread_attr_t  attr;
 
98
        pthread_t       statThread;
 
99
        struct timeval  workTime;
 
100
        struct timespec deadline;
 
101
        int             result;
 
102
 
 
103
        parms.fileName = fileName;
 
104
        parms.fileExists = -1;  /*      Unknown.                        */
 
105
        memset((char *) &mutex, 0, sizeof mutex);
 
106
        if (pthread_mutex_init(&mutex, NULL))
 
107
        {
 
108
                putSysErrmsg("Can't initialize mutex", NULL);
 
109
                return -1;
 
110
        }
 
111
 
 
112
        memset((char *) &cv, 0, sizeof cv);
 
113
        if (pthread_cond_init(&cv, NULL))
 
114
        {
 
115
                oK(pthread_mutex_destroy(&mutex));
 
116
                putSysErrmsg("Can't initialize condition variable", NULL);
 
117
                return -1;
 
118
        }
 
119
 
 
120
        parms.cv = &cv;
 
121
        pthread_attr_init(&attr);
 
122
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 
123
        getCurrentTime(&workTime);
 
124
        deadline.tv_sec = workTime.tv_sec + 2;  /*      2 sec timeout.  */
 
125
        deadline.tv_nsec = 0;
 
126
 
 
127
        /*      Spawn a separate thread that hangs on opening the file
 
128
         *      if there's an error in the file system.                 */
 
129
 
 
130
        if (pthread_create(&statThread, &attr, checkFileExists, &parms))
 
131
        {
 
132
                oK(pthread_mutex_destroy(&mutex));
 
133
                oK(pthread_cond_destroy(&cv));
 
134
                putSysErrmsg("Can't create stat thread", NULL);
 
135
                return -1;
 
136
        }
 
137
 
 
138
        /*      At this point the child might already have finished
 
139
         *      looking for the file and terminated, in which case
 
140
         *      we want NOT to wait for a signal from it.               */
 
141
 
 
142
        if (parms.fileExists == -1)     /*      Child not ended yet.    */
 
143
        {
 
144
                /*      Wait for all-OK signal from child; if none,
 
145
                 *      cancel the child thread and note that the file
 
146
                 *      does not exist.                                 */
 
147
 
 
148
                oK(pthread_mutex_lock(&mutex));
 
149
                result = pthread_cond_timedwait(&cv, &mutex, &deadline);
 
150
                oK(pthread_mutex_unlock(&mutex));
 
151
                if (result)     /*      NOT signaled by child thread.   */
 
152
                {
 
153
                        if (result != ETIMEDOUT)
 
154
                        {
 
155
                                errno = result;
 
156
                                oK(pthread_mutex_destroy(&mutex));
 
157
                                oK(pthread_cond_destroy(&cv));
 
158
                                putSysErrmsg("pthread_cond_timedwait failed",
 
159
                                                NULL);
 
160
                                return -1;
 
161
                        }
 
162
 
 
163
                        /*      Timeout: child stuck, file undefined.   */
 
164
 
 
165
                        pthread_cancel(statThread);
 
166
                        parms.fileExists = 0;
 
167
                }
 
168
        }
 
169
 
 
170
        oK(pthread_mutex_destroy(&mutex));
 
171
        oK(pthread_cond_destroy(&cv));
 
172
        return parms.fileExists;
 
173
#else
 
174
        struct stat     statbuf;
 
175
 
 
176
        if (stat(fileName, &statbuf) < 0)
 
177
        {
 
178
                return 0;
 
179
        }
 
180
 
 
181
        return 1;
 
182
#endif
 
183
}
 
184
 
 
185
void    addToChecksum(unsigned char octet, unsigned int *offset,
 
186
                unsigned int *checksum)
 
187
{
 
188
        unsigned int    octetVal;
 
189
        unsigned int    N;
 
190
 
 
191
        /*      To get the value to add to the checksum:
 
192
         *
 
193
         *      -       The octet needs to be inserted into the
 
194
         *              correct position in a 4-byte word based
 
195
         *              on its offset from the start of the file.
 
196
         *              Needs to be shifted left by 8N bits for
 
197
         *              this purpose.
 
198
         *
 
199
         *      -       We calculate N as 3 minus the octet's
 
200
         *              offset from the start of the file
 
201
         *              modulo 4, then multiply it by 8 to
 
202
         *              convert from bytes to bits.                     */
 
203
 
 
204
        N = 3 - (*offset & 0x03);
 
205
        octetVal = octet << (N << 3);   /*      Multiply N by 8.        */
 
206
        *checksum += octetVal;
 
207
        (*offset)++;
 
208
}
 
209
 
 
210
int     getReqNbr()
 
211
{
 
212
        Sdr     sdr = getIonsdr();
 
213
        Object  dbObj = getCfdpDbObject();
 
214
        CfdpDB  db;
 
215
 
 
216
        CHKERR(ionLocked());
 
217
        sdr_stage(sdr, (char *) &db, dbObj, sizeof(CfdpDB));
 
218
        db.requestCounter++;
 
219
        sdr_write(sdr, dbObj, (char *) &db, sizeof(CfdpDB));
 
220
        return db.requestCounter;
 
221
}
 
222
 
 
223
static unsigned char    *_crcComputationBuf()
 
224
{
 
225
        static unsigned char    buffer[CFDP_MAX_PDU_SIZE];
 
226
 
 
227
        return buffer;
 
228
}
 
229
 
 
230
static unsigned short   computeCRC(unsigned char *buffer, int length)
 
231
{
 
232
        static int              crcCalcValuesInitialized = 0;
 
233
        int                     i;
 
234
        unsigned int            tmp;
 
235
        static unsigned int     crcCalcValues[256];
 
236
        unsigned char           *cursor = buffer;
 
237
        unsigned int            crc = 0xffff;
 
238
 
 
239
        if (!crcCalcValuesInitialized)
 
240
        {
 
241
                for (i = 0; i < 256; i++)
 
242
                {
 
243
                        tmp = 0;
 
244
                        if ((i & 1) != 0) tmp = tmp ^ 0x1021;
 
245
                        if ((i & 2) != 0) tmp = tmp ^ 0x2042;
 
246
                        if ((i & 4) != 0) tmp = tmp ^ 0x4084;
 
247
                        if ((i & 8) != 0) tmp = tmp ^ 0x8108;
 
248
                        if ((i & 16) != 0) tmp = tmp ^ 0x1231;
 
249
                        if ((i & 32) != 0) tmp = tmp ^ 0x2462;
 
250
                        if ((i & 64) != 0) tmp = tmp ^ 0x48c4;
 
251
                        if ((i & 128) != 0) tmp = tmp ^ 0x9188;
 
252
                        crcCalcValues[i] = tmp;
 
253
                }
 
254
 
 
255
                crcCalcValuesInitialized = 1;
 
256
        }
 
257
 
 
258
        while (length > 0)
 
259
        {
 
260
            crc = (((crc << 8) & 0xff00)
 
261
                        ^ crcCalcValues[(((crc >> 8) ^ (*cursor)) & 0x00ff)]);
 
262
            cursor++;
 
263
            length--;
 
264
        }
 
265
 
 
266
        return crc;
 
267
}
 
268
 
 
269
/*      *       *       CFDP service control functions  *       *       */
 
270
 
 
271
static char     *_cfdpvdbName()
 
272
{
 
273
        return "cfdpvdb";
 
274
}
 
275
 
 
276
static CfdpVdb  *_cfdpvdb(char **name)
 
277
{
 
278
        static CfdpVdb  *vdb = NULL;
 
279
        PsmPartition    wm;
 
280
        PsmAddress      vdbAddress;
 
281
        PsmAddress      elt;
 
282
        Sdr             sdr;
 
283
        char            *corruptionModulusString;
 
284
 
 
285
        if (name)
 
286
        {
 
287
                if (*name == NULL)      /*      Terminating.            */
 
288
                {
 
289
                        vdb = NULL;
 
290
                        return vdb;
 
291
                }
 
292
 
 
293
                /*      Attaching to volatile database.                 */
 
294
 
 
295
                wm = getIonwm();
 
296
                if (psm_locate(wm, *name, &vdbAddress, &elt) < 0)
 
297
                {
 
298
                        putErrmsg("Failed searching for vdb.", NULL);
 
299
                        return vdb;
 
300
                }
 
301
 
 
302
                if (elt)
 
303
                {
 
304
                        vdb = (CfdpVdb *) psp(wm, vdbAddress);
 
305
                        return vdb;
 
306
                }
 
307
 
 
308
                /*      CFDP volatile database doesn't exist yet.       */
 
309
 
 
310
                sdr = getIonsdr();
 
311
                sdr_begin_xn(sdr);      /*      Just to lock memory.    */
 
312
                vdbAddress = psm_zalloc(wm, sizeof(CfdpVdb));
 
313
                if (vdbAddress == 0)
 
314
                {
 
315
                        sdr_exit_xn(sdr);
 
316
                        putErrmsg("No space for volatile database.", NULL);
 
317
                        return NULL;
 
318
                }
 
319
 
 
320
                vdb = (CfdpVdb *) psp(wm, vdbAddress);
 
321
                memset((char *) vdb, 0, sizeof(CfdpVdb));
 
322
                vdb->utaPid = ERROR;            /*      None yet.       */
 
323
                vdb->clockPid = ERROR;          /*      None yet.       */
 
324
                vdb->eventSemaphore = sm_SemCreate(SM_NO_KEY, SM_SEM_FIFO);
 
325
                vdb->fduSemaphore = sm_SemCreate(SM_NO_KEY, SM_SEM_FIFO);
 
326
                if (vdb->eventSemaphore == SM_SEM_NONE
 
327
                || vdb->fduSemaphore == SM_SEM_NONE
 
328
                || psm_catlg(wm, *name, vdbAddress) < 0)
 
329
                {
 
330
                        sdr_exit_xn(sdr);
 
331
                        putErrmsg("Can't initialize volatile database.", NULL);
 
332
                        return NULL;
 
333
                }
 
334
 
 
335
                sm_SemTake(vdb->eventSemaphore);/*      Lock.           */
 
336
                sm_SemTake(vdb->fduSemaphore);  /*      Lock.           */
 
337
                vdb->currentFile = -1;          /*      Nothing open.   */
 
338
                corruptionModulusString = getenv("CFDP_CORRUPTION_MODULUS");
 
339
                if (corruptionModulusString)
 
340
                {
 
341
                        vdb->corruptionModulus = strtol(corruptionModulusString,
 
342
                                        NULL, 0);
 
343
                        writeMemoNote("[?] Non-zero CFDP corruption modulus!",
 
344
                                        utoa(vdb->corruptionModulus));
 
345
                }
 
346
 
 
347
                sdr_exit_xn(sdr);       /*      Unlock wm.              */
 
348
        }
 
349
 
 
350
        return vdb;
 
351
}
 
352
 
 
353
static char     *_cfdpdbName()
 
354
{
 
355
        return "cfdpdb";
 
356
}
 
357
 
 
358
int     cfdpInit()
 
359
{
 
360
        Sdr             sdr;
 
361
        Object          cfdpdbObject;
 
362
        IonDB           iondb;
 
363
        CfdpDB          cfdpdbBuf;
 
364
        int             i;
 
365
        char            *cfdpvdbName = _cfdpvdbName();
 
366
 
 
367
        if (ionAttach() < 0)
 
368
        {
 
369
                putErrmsg("CFDP can't attach to ION.", NULL);
 
370
                return -1;
 
371
        }
 
372
 
 
373
        sdr = getIonsdr();
 
374
 
 
375
        /*      Recover the CFDP database, creating it if necessary.    */
 
376
 
 
377
        sdr_begin_xn(sdr);
 
378
        cfdpdbObject = sdr_find(sdr, _cfdpdbName(), NULL);
 
379
        switch (cfdpdbObject)
 
380
        {
 
381
        case -1:                /*      SDR error.                      */
 
382
                sdr_cancel_xn(sdr);
 
383
                putErrmsg("Can't search for CFDP database in SDR.", NULL);
 
384
                return -1;
 
385
 
 
386
        case 0:                 /*      Not found; must create new DB.  */
 
387
                cfdpdbObject = sdr_malloc(sdr, sizeof(CfdpDB));
 
388
                if (cfdpdbObject == 0)
 
389
                {
 
390
                        sdr_cancel_xn(sdr);
 
391
                        putErrmsg("No space for database.", NULL);
 
392
                        return -1;
 
393
                }
 
394
 
 
395
                /*      Initialize the non-volatile database.           */
 
396
 
 
397
                memset((char *) &cfdpdbBuf, 0, sizeof(CfdpDB));
 
398
                sdr_read(sdr, (char *) &iondb, getIonDbObject(),
 
399
                                sizeof(IonDB));
 
400
                cfdpdbBuf.ownEntityId = iondb.ownNodeNbr;
 
401
                cfdp_compress_number(&cfdpdbBuf.ownEntityNbr,
 
402
                                cfdpdbBuf.ownEntityId);
 
403
 
 
404
                /*      Default values.                                 */
 
405
 
 
406
                cfdpdbBuf.maxTransactionNbr = 999999999;
 
407
                cfdpdbBuf.fillCharacter = 0xaa;
 
408
                cfdpdbBuf.discardIncompleteFile = 1;
 
409
                cfdpdbBuf.crcRequired = 0;
 
410
                cfdpdbBuf.maxFileDataLength = 65000;
 
411
                cfdpdbBuf.transactionInactivityLimit = 86400;
 
412
                cfdpdbBuf.checkTimerPeriod = 86400;     /*      1 day.  */
 
413
                cfdpdbBuf.checkTimeoutLimit = 7;
 
414
 
 
415
                /*      Management information.                         */
 
416
 
 
417
                for (i = 0; i < 16; i++)
 
418
                {
 
419
                        cfdpdbBuf.faultHandlers[i] = CfdpIgnore;
 
420
                }
 
421
 
 
422
                cfdpdbBuf.faultHandlers[CfdpFilestoreRejection] = CfdpCancel;
 
423
                cfdpdbBuf.faultHandlers[CfdpCheckLimitReached] = CfdpCancel;
 
424
                cfdpdbBuf.usrmsgLists = sdr_list_create(sdr);
 
425
                cfdpdbBuf.fsreqLists = sdr_list_create(sdr);
 
426
                cfdpdbBuf.fsrespLists = sdr_list_create(sdr);
 
427
                cfdpdbBuf.outboundFdus = sdr_list_create(sdr);
 
428
                cfdpdbBuf.events = sdr_list_create(sdr);
 
429
                cfdpdbBuf.entities = sdr_list_create(sdr);
 
430
                sdr_write(sdr, cfdpdbObject, (char *) &cfdpdbBuf,
 
431
                                sizeof(CfdpDB));
 
432
                sdr_catlg(sdr, _cfdpdbName(), 0, cfdpdbObject);
 
433
                if (sdr_end_xn(sdr))
 
434
                {
 
435
                        putErrmsg("Can't create CFDP database.", NULL);
 
436
                        return -1;
 
437
                }
 
438
 
 
439
                break;
 
440
 
 
441
        default:                        /*      Found DB in the SDR.    */
 
442
                sdr_exit_xn(sdr);
 
443
        }
 
444
 
 
445
        oK(_cfdpdbObject(&cfdpdbObject));/*     Save database location. */
 
446
        oK(_cfdpConstants());
 
447
 
 
448
        /*      Locate volatile database, initializing as necessary.    */
 
449
 
 
450
        if (_cfdpvdb(&cfdpvdbName) == NULL)
 
451
        {
 
452
                putErrmsg("CFDP can't initialize vdb.", NULL);
 
453
                return -1;
 
454
        }
 
455
 
 
456
        return 0;               /*      CFDP service is available.      */
 
457
}
 
458
 
 
459
Object  getCfdpDbObject()
 
460
{
 
461
        return _cfdpdbObject(NULL);
 
462
}
 
463
 
 
464
CfdpDB  *getCfdpConstants()
 
465
{
 
466
        return _cfdpConstants();
 
467
}
 
468
 
 
469
CfdpVdb *getCfdpVdb()
 
470
{
 
471
        return _cfdpvdb(NULL);
 
472
}
 
473
 
 
474
int     _cfdpStart(char *utaCmd)
 
475
{
 
476
        Sdr     sdr = getIonsdr();
 
477
        CfdpVdb *cfdpvdb = _cfdpvdb(NULL);
 
478
 
 
479
        if (utaCmd == NULL)
 
480
        {
 
481
                putErrmsg("CFDP can't start: no UTA command.", NULL);
 
482
                return -1;
 
483
        }
 
484
 
 
485
        sdr_begin_xn(sdr);      /*      Just to lock memory.            */
 
486
 
 
487
        /*      Start the CFDP events clock if necessary.               */
 
488
 
 
489
        if (cfdpvdb->clockPid == ERROR || sm_TaskExists(cfdpvdb->clockPid) == 0)
 
490
        {
 
491
                cfdpvdb->clockPid = pseudoshell("cfdpclock");
 
492
        }
 
493
 
 
494
        /*      Start UT adapter service if necessary.                  */
 
495
 
 
496
        if (cfdpvdb->utaPid == ERROR || sm_TaskExists(cfdpvdb->utaPid) == 0)
 
497
        {
 
498
                cfdpvdb->utaPid = pseudoshell(utaCmd);
 
499
        }
 
500
 
 
501
        sdr_exit_xn(sdr);       /*      Unlock memory.                  */
 
502
        return 0;
 
503
}
 
504
 
 
505
void    _cfdpStop()             /*      Reverses cfdpStart.             */
 
506
{
 
507
        Sdr     sdr = getIonsdr();
 
508
        CfdpVdb *cfdpvdb = _cfdpvdb(NULL);
 
509
 
 
510
        /*      Tell all CFDP processes to stop.                        */
 
511
 
 
512
        sdr_begin_xn(sdr);      /*      Just to lock memory.            */
 
513
 
 
514
        /*      Stop user application input thread.                     */
 
515
 
 
516
        if (cfdpvdb->eventSemaphore != SM_SEM_NONE)
 
517
        {
 
518
                sm_SemEnd(cfdpvdb->eventSemaphore);
 
519
        }
 
520
 
 
521
        /*      Stop UTA task.                                          */
 
522
 
 
523
        if (cfdpvdb->fduSemaphore != SM_SEM_NONE)
 
524
        {
 
525
                sm_SemEnd(cfdpvdb->fduSemaphore);
 
526
        }
 
527
 
 
528
        /*      Stop clock task.                                        */
 
529
 
 
530
        if (cfdpvdb->clockPid != ERROR)
 
531
        {
 
532
                sm_TaskKill(cfdpvdb->clockPid, SIGTERM);
 
533
        }
 
534
 
 
535
        sdr_exit_xn(sdr);       /*      Unlock memory.                  */
 
536
 
 
537
        /*      Wait until all CFDP processes have stopped.             */
 
538
 
 
539
        if (cfdpvdb->utaPid != ERROR)
 
540
        {
 
541
                while (sm_TaskExists(cfdpvdb->utaPid))
 
542
                {
 
543
                        microsnooze(100000);
 
544
                }
 
545
        }
 
546
 
 
547
        if (cfdpvdb->clockPid != ERROR)
 
548
        {
 
549
                while (sm_TaskExists(cfdpvdb->clockPid))
 
550
                {
 
551
                        microsnooze(100000);
 
552
                }
 
553
        }
 
554
 
 
555
        /*      Now erase all the tasks and reset the semaphores.       */
 
556
 
 
557
        sdr_begin_xn(sdr);      /*      Just to lock memory.            */
 
558
        cfdpvdb->utaPid = ERROR;
 
559
        cfdpvdb->clockPid = ERROR;
 
560
        if (cfdpvdb->eventSemaphore == SM_SEM_NONE)
 
561
        {
 
562
                cfdpvdb->eventSemaphore = sm_SemCreate(SM_NO_KEY, SM_SEM_FIFO);
 
563
        }
 
564
        else
 
565
        {
 
566
                sm_SemUnend(cfdpvdb->eventSemaphore);
 
567
        }
 
568
 
 
569
        sm_SemTake(cfdpvdb->eventSemaphore);            /*      Lock.   */
 
570
        if (cfdpvdb->fduSemaphore == SM_SEM_NONE)
 
571
        {
 
572
                cfdpvdb->fduSemaphore = sm_SemCreate(SM_NO_KEY, SM_SEM_FIFO);
 
573
        }
 
574
        else
 
575
        {
 
576
                sm_SemUnend(cfdpvdb->fduSemaphore);
 
577
        }
 
578
 
 
579
        sm_SemTake(cfdpvdb->fduSemaphore);              /*      Lock.   */
 
580
        sdr_exit_xn(sdr);       /*      Unlock memory.                  */
 
581
}
 
582
 
 
583
int     cfdpAttach()
 
584
{
 
585
        Object          cfdpdbObject = _cfdpdbObject(NULL);
 
586
        CfdpVdb         *cfdpvdb = _cfdpvdb(NULL);
 
587
        Sdr             sdr;
 
588
        char            *cfdpvdbName = _cfdpvdbName();
 
589
 
 
590
        if (cfdpdbObject && cfdpvdb)
 
591
        {
 
592
                return 0;               /*      Already attached.       */
 
593
        }
 
594
 
 
595
        if (ionAttach() < 0)
 
596
        {
 
597
                putErrmsg("CFDP can't attach to ION.", NULL);
 
598
                return -1;
 
599
        }
 
600
 
 
601
        sdr = getIonsdr();
 
602
 
 
603
        /*      Locate the CFDP database.                               */
 
604
 
 
605
        if (cfdpdbObject == 0)
 
606
        {
 
607
                sdr_begin_xn(sdr);      /*      Lock database.          */
 
608
                cfdpdbObject = sdr_find(sdr, _cfdpdbName(), NULL);
 
609
                sdr_exit_xn(sdr);       /*      Unlock database.        */
 
610
                if (cfdpdbObject == 0)
 
611
                {
 
612
                        putErrmsg("Can't find CFDP database.", NULL);
 
613
                        return -1;
 
614
                }
 
615
 
 
616
                oK(_cfdpdbObject(&cfdpdbObject));
 
617
        }
 
618
 
 
619
        oK(_cfdpConstants());
 
620
 
 
621
        /*      Locate the CFDP volatile database.                      */
 
622
 
 
623
        if (cfdpvdb == NULL)
 
624
        {
 
625
                if (_cfdpvdb(&cfdpvdbName) == NULL)
 
626
                {
 
627
                        putErrmsg("CFDP volatile database not found.", NULL);
 
628
                        return -1;
 
629
                }
 
630
        }
 
631
 
 
632
        return 0;               /*      CFDP service is available.      */
 
633
}
 
634
 
 
635
MetadataList    createMetadataList(Object log)
 
636
{
 
637
        Sdr     sdr = getIonsdr();
 
638
        Object  list;
 
639
 
 
640
        /*      Create new list, add it to database's list of
 
641
         *      filestore response lists, and store that reference
 
642
         *      in the new list's user data.                            */
 
643
 
 
644
        CHKZERO(log);
 
645
        sdr_begin_xn(sdr);
 
646
        list = sdr_list_create(sdr);
 
647
        if (list)
 
648
        {
 
649
                sdr_list_user_data_set(sdr, list,
 
650
                                sdr_list_insert_last(sdr, log, list));
 
651
        }
 
652
 
 
653
        if (sdr_end_xn(sdr) < 0)
 
654
        {
 
655
                putErrmsg("Can't create metadata list.", NULL);
 
656
                return 0;
 
657
        }
 
658
 
 
659
        return list;
 
660
}
 
661
 
 
662
void    destroyUsrmsgList(MetadataList *list)
 
663
{
 
664
        Sdr             sdr = getIonsdr();
 
665
        Object          elt;
 
666
        Object          obj;
 
667
        MsgToUser       usrmsg;
 
668
 
 
669
        CHKVOID(list);
 
670
        elt = sdr_list_first(sdr, *list);
 
671
        while (elt)
 
672
        {
 
673
                obj = sdr_list_data(sdr, elt);
 
674
                sdr_list_delete(sdr, elt, NULL, NULL);
 
675
                sdr_read(sdr, (char *) &usrmsg, obj, sizeof(MsgToUser));
 
676
                if (usrmsg.text)
 
677
                {
 
678
                        sdr_free(sdr, usrmsg.text);
 
679
                }
 
680
 
 
681
                sdr_free(sdr, obj);
 
682
                elt = sdr_list_first(sdr, *list);
 
683
        }
 
684
 
 
685
        elt = sdr_list_user_data(sdr, *list);
 
686
        if (elt)
 
687
        {
 
688
                sdr_list_delete(sdr, elt, NULL, NULL);
 
689
        }
 
690
 
 
691
        sdr_list_destroy(sdr, *list, NULL, NULL);
 
692
        *list = 0;
 
693
}
 
694
 
 
695
void    destroyFsreqList(MetadataList *list)
 
696
{
 
697
        Sdr                     sdr = getIonsdr();
 
698
        Object                  elt;
 
699
        Object                  obj;
 
700
        FilestoreRequest        fsreq;
 
701
 
 
702
        CHKVOID(list);
 
703
        elt = sdr_list_first(sdr, *list);
 
704
        while (elt)
 
705
        {
 
706
                obj = sdr_list_data(sdr, elt);
 
707
                sdr_list_delete(sdr, elt, NULL, NULL);
 
708
                sdr_read(sdr, (char *) &fsreq, obj,
 
709
                                sizeof(FilestoreRequest));
 
710
                if (fsreq.firstFileName)
 
711
                {
 
712
                        sdr_free(sdr, fsreq.firstFileName);
 
713
                }
 
714
 
 
715
                if (fsreq.secondFileName)
 
716
                {
 
717
                        sdr_free(sdr, fsreq.secondFileName);
 
718
                }
 
719
 
 
720
                sdr_free(sdr, obj);
 
721
                elt = sdr_list_first(sdr, *list);
 
722
        }
 
723
 
 
724
        elt = sdr_list_user_data(sdr, *list);
 
725
        if (elt)
 
726
        {
 
727
                sdr_list_delete(sdr, elt, NULL, NULL);
 
728
        }
 
729
 
 
730
        sdr_list_destroy(sdr, *list, NULL, NULL);
 
731
        *list = 0;
 
732
}
 
733
 
 
734
void    destroyFsrespList(Object *list)
 
735
{
 
736
        Sdr                     sdr = getIonsdr();
 
737
        Object                  elt;
 
738
        Object                  obj;
 
739
        FilestoreResponse       fsresp;
 
740
 
 
741
        CHKVOID(list);
 
742
        elt = sdr_list_first(sdr, *list);
 
743
        while (elt)
 
744
        {
 
745
                obj = sdr_list_data(sdr, elt);
 
746
                sdr_list_delete(sdr, elt, NULL, NULL);
 
747
                sdr_read(sdr, (char *) &fsresp, obj,
 
748
                                sizeof(FilestoreResponse));
 
749
                if (fsresp.firstFileName)
 
750
                {
 
751
                        sdr_free(sdr, fsresp.firstFileName);
 
752
                }
 
753
 
 
754
                if (fsresp.secondFileName)
 
755
                {
 
756
                        sdr_free(sdr, fsresp.secondFileName);
 
757
                }
 
758
 
 
759
                if (fsresp.message)
 
760
                {
 
761
                        sdr_free(sdr, fsresp.message);
 
762
                }
 
763
 
 
764
                sdr_free(sdr, obj);
 
765
                elt = sdr_list_first(sdr, *list);
 
766
        }
 
767
 
 
768
        elt = sdr_list_user_data(sdr, *list);
 
769
        if (elt)
 
770
        {
 
771
                sdr_list_delete(sdr, elt, NULL, NULL);
 
772
        }
 
773
 
 
774
        sdr_list_destroy(sdr, *list, NULL, NULL);
 
775
        *list = 0;
 
776
}
 
777
 
 
778
void    cfdpScrub()
 
779
{
 
780
        Sdr             sdr = getIonsdr();
 
781
        CfdpDB          *cfdpConstants = _cfdpConstants();
 
782
        Object          elt;
 
783
        MetadataList    list;
 
784
 
 
785
        CHKVOID(ionLocked());
 
786
        elt = sdr_list_first(sdr, cfdpConstants->usrmsgLists);
 
787
        while (elt)
 
788
        {
 
789
                list = sdr_list_data(sdr, elt);
 
790
                destroyUsrmsgList(&list);
 
791
                elt = sdr_list_first(sdr, cfdpConstants->usrmsgLists);
 
792
        }
 
793
 
 
794
        elt = sdr_list_first(sdr, cfdpConstants->fsreqLists);
 
795
        while (elt)
 
796
        {
 
797
                list = sdr_list_data(sdr, elt);
 
798
                destroyFsreqList(&list);
 
799
                elt = sdr_list_first(sdr, cfdpConstants->fsreqLists);
 
800
        }
 
801
 
 
802
        elt = sdr_list_first(sdr, cfdpConstants->fsrespLists);
 
803
        while (elt)
 
804
        {
 
805
                list = sdr_list_data(sdr, elt);
 
806
                destroyFsrespList(&list);
 
807
                elt = sdr_list_first(sdr, cfdpConstants->fsrespLists);
 
808
        }
 
809
}
 
810
 
 
811
int     addFsResp(Object list, CfdpAction action, int status,
 
812
                char *firstFileName, char *secondFileName, char *message)
 
813
{
 
814
        Sdr                     sdr = getIonsdr();
 
815
        CfdpDB                  *cfdpConstants = _cfdpConstants();
 
816
        FilestoreResponse       fsresp;
 
817
        Object                  addr;
 
818
 
 
819
        CHKERR(list);
 
820
        CHKERR(firstFileName == NULL || strlen(firstFileName) < 256);
 
821
        CHKERR(secondFileName == NULL || strlen(secondFileName) < 256);
 
822
        CHKERR(message == NULL || strlen(secondFileName) < 256);
 
823
        CHKERR(sdr_list_list(sdr, sdr_list_user_data(sdr, list))
 
824
                        == cfdpConstants->fsreqLists);
 
825
        sdr_begin_xn(sdr);
 
826
        fsresp.action = action;
 
827
        fsresp.status = status;
 
828
        if (firstFileName)
 
829
        {
 
830
                fsresp.firstFileName = sdr_string_create(sdr,
 
831
                                firstFileName);
 
832
        }
 
833
 
 
834
        if (secondFileName)
 
835
        {
 
836
                fsresp.secondFileName = sdr_string_create(sdr,
 
837
                                secondFileName);
 
838
        }
 
839
 
 
840
        if (message)
 
841
        {
 
842
                fsresp.message = sdr_string_create(sdr, message);
 
843
        }
 
844
 
 
845
        addr = sdr_malloc(sdr, sizeof(FilestoreResponse));
 
846
        if (addr)
 
847
        {
 
848
                sdr_write(sdr, addr, (char *) &fsresp,
 
849
                                sizeof(FilestoreResponse));
 
850
                oK(sdr_list_insert_last(sdr, list, addr));
 
851
        }
 
852
 
 
853
        if (sdr_end_xn(sdr) < 0)
 
854
        {
 
855
                putErrmsg("CFDP: failed adding filestore response.", NULL);
 
856
                return -1;
 
857
        }
 
858
 
 
859
        return 0;
 
860
}
 
861
 
 
862
/*      *       CFDP transaction mgt and access functions       *       */
 
863
 
 
864
Object  findOutFdu(CfdpTransactionId *transactionId, OutFdu *fduBuf,
 
865
                Object *fduElt)
 
866
{
 
867
        Sdr     sdr = getIonsdr();
 
868
        CfdpDB  *cfdpConstants = _cfdpConstants();
 
869
        Object  elt;
 
870
        Object  fduObj;
 
871
 
 
872
        CHKZERO(transactionId);
 
873
        CHKZERO(fduBuf);
 
874
        CHKZERO(fduElt);
 
875
        *fduElt = 0;                    /*      Default.                */
 
876
        for (elt = sdr_list_first(sdr, cfdpConstants->outboundFdus); elt;
 
877
                        elt = sdr_list_next(sdr, elt))
 
878
        {
 
879
                fduObj = sdr_list_data(sdr, elt);
 
880
                sdr_read(sdr, (char *) fduBuf, fduObj, sizeof(OutFdu));
 
881
                if (memcmp((char *) &fduBuf->transactionId.transactionNbr,
 
882
                                (char *) &transactionId->transactionNbr,
 
883
                                sizeof(CfdpNumber)) == 0)
 
884
                {
 
885
                        *fduElt = elt;
 
886
                        return fduObj;
 
887
                }
 
888
        }
 
889
 
 
890
        return 0;
 
891
}
 
892
 
 
893
static Object   createInFdu(CfdpTransactionId *transactionId, Entity *entity,
 
894
                        InFdu *fdubuf, Object *fduElt)
 
895
{
 
896
        Sdr     sdr = getIonsdr();
 
897
        CfdpDB  cfdpdb;
 
898
        Object  fduObj;
 
899
 
 
900
        memset((char *) fdubuf, 0, sizeof(InFdu));
 
901
        memcpy((char *) &fdubuf->transactionId, (char *) transactionId,
 
902
                        sizeof(CfdpTransactionId));
 
903
        fdubuf->messagesToUser = sdr_list_create(sdr);
 
904
        fdubuf->filestoreRequests = sdr_list_create(sdr);
 
905
        fdubuf->extents = sdr_list_create(sdr);
 
906
        fduObj = sdr_malloc(sdr, sizeof(InFdu));
 
907
        if (fduObj == 0 || fdubuf->messagesToUser == 0
 
908
        || fdubuf->filestoreRequests == 0 || fdubuf->extents == 0
 
909
        || (*fduElt = sdr_list_insert_last(sdr, entity->inboundFdus,
 
910
                        fduObj)) == 0)
 
911
        {
 
912
                return 0;               /*      System failure.         */
 
913
        }
 
914
 
 
915
        sdr_read(sdr, (char *) &cfdpdb, getCfdpDbObject(), sizeof(CfdpDB));
 
916
        fdubuf->inactivityDeadline = getUTCTime()
 
917
                        + cfdpdb.transactionInactivityLimit;
 
918
        sdr_write(sdr, fduObj, (char *) fdubuf, sizeof(InFdu));
 
919
        return fduObj;
 
920
}
 
921
 
 
922
Object  findInFdu(CfdpTransactionId *transactionId, InFdu *fduBuf,
 
923
                Object *fduElt, int createIfNotFound)
 
924
{
 
925
        unsigned long   sourceEntityId;
 
926
        Sdr             sdr = getIonsdr();
 
927
        CfdpDB          *cfdpConstants = _cfdpConstants();
 
928
        Object          elt;
 
929
        Object          entityObj;
 
930
        Entity          entity;
 
931
        int             foundIt = 0;
 
932
        Object          fduObj;
 
933
 
 
934
        CHKZERO(transactionId);
 
935
        CHKZERO(fduBuf);
 
936
        CHKZERO(fduElt);
 
937
        cfdp_decompress_number(&sourceEntityId,
 
938
                        &transactionId->sourceEntityNbr);
 
939
        for (elt = sdr_list_first(sdr, cfdpConstants->entities); elt;
 
940
                        elt = sdr_list_next(sdr, elt))
 
941
        {
 
942
                entityObj = sdr_list_data(sdr, elt);
 
943
                sdr_read(sdr, (char *) &entity, entityObj, sizeof(Entity));
 
944
                if (entity.entityId < sourceEntityId)
 
945
                {
 
946
                        continue;
 
947
                }
 
948
 
 
949
                if (entity.entityId == sourceEntityId)
 
950
                {
 
951
                        foundIt = 1;
 
952
                }
 
953
 
 
954
                break;
 
955
        }
 
956
 
 
957
        if (foundIt)            /*      Entity is already known.        */
 
958
        {
 
959
                foundIt = 0;
 
960
                for (elt = sdr_list_first(sdr, entity.inboundFdus); elt;
 
961
                                elt = sdr_list_next(sdr, elt))
 
962
                {
 
963
                        fduObj = sdr_list_data(sdr, elt);
 
964
                        sdr_read(sdr, (char *) fduBuf, fduObj,
 
965
                                        sizeof(InFdu));
 
966
                        if (memcmp((char *) &fduBuf->transactionId,
 
967
                                        (char *) transactionId,
 
968
                                        sizeof(CfdpTransactionId)) == 0)
 
969
                        {
 
970
                                foundIt = 1;
 
971
                                break;
 
972
                        }
 
973
                }
 
974
        
 
975
                if (foundIt)    /*      FDU is already started.         */
 
976
                {
 
977
                        *fduElt = elt;
 
978
                        return fduObj;
 
979
                }
 
980
 
 
981
                /*      No such FDU.  Create it?                        */
 
982
 
 
983
                if (createIfNotFound)
 
984
                {
 
985
                        return createInFdu(transactionId, &entity, fduBuf,
 
986
                                        fduElt);
 
987
                }
 
988
 
 
989
                *fduElt = 0;
 
990
                return 0;
 
991
        }
 
992
 
 
993
        /*      No such entity.                                         */
 
994
 
 
995
        if (!createIfNotFound)
 
996
        {
 
997
                *fduElt = 0;
 
998
                return 0;
 
999
        }
 
1000
 
 
1001
        /*      Must create Entity, then create FDU within new Entity.  */
 
1002
 
 
1003
        cfdp_decompress_number(&entity.entityId,
 
1004
                        &transactionId->sourceEntityNbr);
 
1005
        entity.inboundFdus = sdr_list_create(sdr);
 
1006
        entityObj = sdr_malloc(sdr, sizeof(Entity));
 
1007
        if (entity.inboundFdus == 0 || entityObj == 0
 
1008
        || (elt == 0    ?
 
1009
                sdr_list_insert_last(sdr, cfdpConstants->entities,
 
1010
                        entityObj)
 
1011
                        : 
 
1012
                sdr_list_insert_before(sdr, elt, entityObj)) == 0)
 
1013
        {
 
1014
                return 0;       /*      System failure.         */
 
1015
        }
 
1016
 
 
1017
        sdr_write(sdr, entityObj, (char *) &entity, sizeof(Entity));
 
1018
        return createInFdu(transactionId, &entity, fduBuf, fduElt);
 
1019
}
 
1020
 
 
1021
int     suspendOutFdu(CfdpTransactionId *transactionId, CfdpCondition condition,
 
1022
                        int reqNbr)
 
1023
{
 
1024
        OutFdu          fduBuf;
 
1025
        Object          fduObj;
 
1026
        Object          fduElt;
 
1027
        Sdr             sdr = getIonsdr();
 
1028
        CfdpEvent       event;
 
1029
 
 
1030
        CHKZERO(transactionId);
 
1031
        fduObj = findOutFdu(transactionId, &fduBuf, &fduElt);
 
1032
        if (fduObj == 0 || fduBuf.state != FduActive)
 
1033
        {
 
1034
                return 0;
 
1035
        }
 
1036
 
 
1037
        sdr_stage(sdr, NULL, fduObj, 0);
 
1038
        fduBuf.state = FduSuspended;
 
1039
        sdr_write(sdr, fduObj, (char *) &fduBuf, sizeof(OutFdu));
 
1040
        memset((char *) &event, 0, sizeof(CfdpEvent));
 
1041
        event.type = CfdpSuspendedInd;
 
1042
        memcpy((char *) &event.transactionId, (char *) transactionId,
 
1043
                        sizeof(CfdpTransactionId));
 
1044
        event.condition = condition;
 
1045
        event.reqNbr = reqNbr;
 
1046
        if (enqueueCfdpEvent(&event) < 0)
 
1047
        {
 
1048
                putErrmsg("CFDP can't suspend transaction.", NULL);
 
1049
                return -1;
 
1050
        }
 
1051
 
 
1052
        return event.reqNbr;
 
1053
}
 
1054
 
 
1055
int     cancelOutFdu(CfdpTransactionId *transactionId, CfdpCondition condition,
 
1056
                        int reqNbr)
 
1057
{
 
1058
        OutFdu          fduBuf;
 
1059
        Object          fduObj;
 
1060
        Object          fduElt;
 
1061
        Sdr             sdr = getIonsdr();
 
1062
        CfdpEvent       event;
 
1063
 
 
1064
        CHKZERO(transactionId);
 
1065
        fduObj = findOutFdu(transactionId, &fduBuf, &fduElt);
 
1066
        if (fduObj == 0 || fduBuf.state == FduCanceled)
 
1067
        {
 
1068
                writeMemo("[?] CFDP unable to cancel outbound FDU.");
 
1069
                return 0;
 
1070
        }
 
1071
 
 
1072
        sdr_stage(sdr, NULL, fduObj, 0);
 
1073
        fduBuf.state = FduCanceled;
 
1074
        sdr_write(sdr, fduObj, (char *) &fduBuf, sizeof(OutFdu));
 
1075
        memset((char *) &event, 0, sizeof(CfdpEvent));
 
1076
        event.type = CfdpTransactionFinishedInd;
 
1077
        memcpy((char *) &event.transactionId, (char *) transactionId,
 
1078
                        sizeof(CfdpTransactionId));
 
1079
        event.condition = condition;
 
1080
        event.fileStatus = CfdpFileStatusUnreported;
 
1081
        if (fduBuf.metadataPdu == 0 && fduBuf.eofPdu == 0
 
1082
        && fduBuf.progress == fduBuf.fileSize)
 
1083
        {
 
1084
                event.deliveryCode = CfdpDataComplete;
 
1085
        }
 
1086
        else
 
1087
        {
 
1088
                event.deliveryCode = CfdpDataIncomplete;
 
1089
        }
 
1090
 
 
1091
        event.reqNbr = reqNbr;
 
1092
        if (enqueueCfdpEvent(&event) < 0)
 
1093
        {
 
1094
                putErrmsg("CFDP can't cancel transaction.", NULL);
 
1095
                return -1;
 
1096
        }
 
1097
 
 
1098
        return event.reqNbr;
 
1099
}
 
1100
 
 
1101
void    destroyOutFdu(OutFdu *fdu, Object fduObj, Object fduElt)
 
1102
{
 
1103
        Sdr     sdr = getIonsdr();
 
1104
        Object  elt;
 
1105
        Object  obj;
 
1106
 
 
1107
        CHKVOID(fdu);
 
1108
        CHKVOID(fduObj);
 
1109
        CHKVOID(fduElt);
 
1110
        if (fdu->metadataPdu)
 
1111
        {
 
1112
                sdr_free(sdr, fdu->metadataPdu);
 
1113
        }
 
1114
 
 
1115
        while (fdu->recordLengths)
 
1116
        {
 
1117
                elt = sdr_list_first(sdr, fdu->recordLengths);
 
1118
                if (elt == 0)
 
1119
                {
 
1120
                        sdr_list_destroy(sdr, fdu->recordLengths, NULL,
 
1121
                                        NULL);
 
1122
                        break;
 
1123
                }
 
1124
 
 
1125
                sdr_list_delete(sdr, elt, NULL, NULL);
 
1126
        }
 
1127
 
 
1128
        if (fdu->eofPdu)
 
1129
        {
 
1130
                sdr_free(sdr, fdu->eofPdu);
 
1131
        }
 
1132
 
 
1133
        while (fdu->extantPdus)
 
1134
        {
 
1135
                elt = sdr_list_first(sdr, fdu->extantPdus);
 
1136
                if (elt == 0)
 
1137
                {
 
1138
                        sdr_list_destroy(sdr, fdu->extantPdus, NULL, NULL);
 
1139
                        break;
 
1140
                }
 
1141
 
 
1142
                obj = sdr_list_data(sdr, elt);
 
1143
                zco_destroy_reference(sdr, obj);
 
1144
                sdr_list_delete(sdr, elt, NULL, NULL);
 
1145
        }
 
1146
 
 
1147
        if (fdu->fileRef)
 
1148
        {
 
1149
                zco_destroy_file_ref(sdr, fdu->fileRef);
 
1150
        }
 
1151
 
 
1152
        sdr_free(sdr, fduObj);
 
1153
        sdr_list_delete(sdr, fduElt, NULL, NULL);
 
1154
}
 
1155
 
 
1156
static int      abandonOutFdu(CfdpTransactionId *transactionId,
 
1157
                        CfdpCondition condition)
 
1158
{
 
1159
        Sdr             sdr = getIonsdr();
 
1160
        OutFdu          fduBuf;
 
1161
        Object          fduObj;
 
1162
        Object          fduElt;
 
1163
        CfdpEvent       event;
 
1164
 
 
1165
        fduObj = findOutFdu(transactionId, &fduBuf, &fduElt);
 
1166
        if (fduObj == 0)
 
1167
        {
 
1168
                return 0;
 
1169
        }
 
1170
 
 
1171
        sdr_stage(sdr, NULL, fduObj, 0);
 
1172
        memset((char *) &event, 0, sizeof(CfdpEvent));
 
1173
        event.type = CfdpAbandonedInd;
 
1174
        memcpy((char *) &event.transactionId, (char *) transactionId,
 
1175
                        sizeof(CfdpTransactionId));
 
1176
        event.condition = condition;
 
1177
        event.progress = fduBuf.progress;
 
1178
        event.reqNbr = getReqNbr();
 
1179
        if (enqueueCfdpEvent(&event) < 0)
 
1180
        {
 
1181
                putErrmsg("CFDP can't cancel transaction.", NULL);
 
1182
                return -1;
 
1183
        }
 
1184
 
 
1185
        destroyOutFdu(&fduBuf, fduObj, fduElt);
 
1186
        return event.reqNbr;
 
1187
}
 
1188
 
 
1189
void    destroyInFdu(InFdu *fdu, Object fduObj, Object fduElt)
 
1190
{
 
1191
        Sdr     sdr = getIonsdr();
 
1192
        CfdpVdb *cfdpvdb = _cfdpvdb(NULL);
 
1193
        Object  elt;
 
1194
        Object  obj;
 
1195
                OBJ_POINTER(MsgToUser, msg);
 
1196
                OBJ_POINTER(FilestoreRequest, req);
 
1197
 
 
1198
        CHKVOID(fdu);
 
1199
        CHKVOID(fduObj);
 
1200
        CHKVOID(fduElt);
 
1201
        if (fdu->sourceFileName)
 
1202
        {
 
1203
                sdr_free(sdr, fdu->sourceFileName);
 
1204
        }
 
1205
 
 
1206
        if (fdu->destFileName)
 
1207
        {
 
1208
                sdr_free(sdr, fdu->destFileName);
 
1209
        }
 
1210
 
 
1211
        if (fdu->flowLabel)
 
1212
        {
 
1213
                sdr_free(sdr, fdu->flowLabel);
 
1214
        }
 
1215
 
 
1216
        while (fdu->messagesToUser)
 
1217
        {
 
1218
                elt = sdr_list_first(sdr, fdu->messagesToUser);
 
1219
                if (elt == 0)
 
1220
                {
 
1221
                        sdr_list_destroy(sdr, fdu->messagesToUser, NULL,
 
1222
                                        NULL);
 
1223
                        fdu->messagesToUser = 0;
 
1224
                        continue;
 
1225
                }
 
1226
 
 
1227
                obj = sdr_list_data(sdr, elt);
 
1228
                GET_OBJ_POINTER(sdr, MsgToUser, msg, obj);
 
1229
                if (msg->text)
 
1230
                {
 
1231
                        sdr_free(sdr, msg->text);
 
1232
                }
 
1233
 
 
1234
                sdr_free(sdr, obj);
 
1235
                sdr_list_delete(sdr, elt, NULL, NULL);
 
1236
        }
 
1237
 
 
1238
        while (fdu->filestoreRequests)
 
1239
        {
 
1240
                elt = sdr_list_first(sdr, fdu->filestoreRequests);
 
1241
                if (elt == 0)
 
1242
                {
 
1243
                        sdr_list_destroy(sdr, fdu->filestoreRequests, NULL,
 
1244
                                        NULL);
 
1245
                        fdu->filestoreRequests = 0;
 
1246
                        continue;
 
1247
                }
 
1248
 
 
1249
                obj = sdr_list_data(sdr, elt);
 
1250
                GET_OBJ_POINTER(sdr, FilestoreRequest, req, obj);
 
1251
                if (req->firstFileName)
 
1252
                {
 
1253
                        sdr_free(sdr, req->firstFileName);
 
1254
                }
 
1255
 
 
1256
                if (req->secondFileName)
 
1257
                {
 
1258
                        sdr_free(sdr, req->secondFileName);
 
1259
                }
 
1260
 
 
1261
                sdr_free(sdr, obj);
 
1262
                sdr_list_delete(sdr, elt, NULL, NULL);
 
1263
        }
 
1264
 
 
1265
        while (fdu->extents)
 
1266
        {
 
1267
                elt = sdr_list_first(sdr, fdu->extents);
 
1268
                if (elt == 0)
 
1269
                {
 
1270
                        sdr_list_destroy(sdr, fdu->extents, NULL, NULL);
 
1271
                        fdu->extents = 0;
 
1272
                        continue;
 
1273
                }
 
1274
 
 
1275
                obj = sdr_list_data(sdr, elt);
 
1276
                sdr_free(sdr, obj);     /*      A CfdpExtent structure. */
 
1277
                sdr_list_delete(sdr, elt, NULL, NULL);
 
1278
        }
 
1279
 
 
1280
        sdr_free(sdr, fduObj);
 
1281
        sdr_list_delete(sdr, fduElt, NULL, NULL);
 
1282
        if (cfdpvdb->currentFdu == fduObj)
 
1283
        {
 
1284
                cfdpvdb->currentFdu = 0;
 
1285
        }
 
1286
}
 
1287
 
 
1288
static int      abandonInFdu(CfdpTransactionId *transactionId,
 
1289
                        CfdpCondition condition)
 
1290
{
 
1291
        InFdu           fduBuf;
 
1292
        Object          fduObj;
 
1293
        Object          fduElt;
 
1294
        Sdr             sdr = getIonsdr();
 
1295
        CfdpEvent       event;
 
1296
        char            fileName[256];
 
1297
 
 
1298
        fduObj = findInFdu(transactionId, &fduBuf, &fduElt, 0);
 
1299
        if (fduObj == 0)
 
1300
        {
 
1301
                return 0;
 
1302
        }
 
1303
 
 
1304
        sdr_stage(sdr, NULL, fduObj, 0);
 
1305
        memset((char *) &event, 0, sizeof(CfdpEvent));
 
1306
        event.type = CfdpAbandonedInd;
 
1307
        memcpy((char *) &event.transactionId, (char *) transactionId,
 
1308
                        sizeof(CfdpTransactionId));
 
1309
        event.condition = condition;
 
1310
        event.progress = fduBuf.progress;
 
1311
        event.reqNbr = getReqNbr();
 
1312
        if (enqueueCfdpEvent(&event) < 0)
 
1313
        {
 
1314
                putErrmsg("CFDP can't abandon transaction.", NULL);
 
1315
                return -1;
 
1316
        }
 
1317
 
 
1318
        if (fduBuf.destFileName)
 
1319
        {
 
1320
                sdr_string_read(sdr, fileName, fduBuf.destFileName);
 
1321
                unlink(fileName);
 
1322
        }
 
1323
 
 
1324
        destroyInFdu(&fduBuf, fduObj, fduElt);
 
1325
        return event.reqNbr;
 
1326
}
 
1327
 
 
1328
static void     frCreateFile(char *firstFileName, char *secondFileName,
 
1329
                        FilestoreResponse *resp, char *msgBuf, int bufLen)
 
1330
{
 
1331
        int     fd = iopen(firstFileName, O_CREAT, 0777);
 
1332
 
 
1333
        if (fd < 0)
 
1334
        {
 
1335
                resp->status = 1;
 
1336
                isprintf(msgBuf, bufLen, "%.255s", system_error_msg());
 
1337
        }
 
1338
        else
 
1339
        {
 
1340
                close(fd);
 
1341
        }
 
1342
}
 
1343
 
 
1344
static void     frDeleteFile(char *firstFileName, char *secondFileName,
 
1345
                        FilestoreResponse *resp, char *msgBuf, int bufLen)
 
1346
{
 
1347
        if (unlink(firstFileName) < 0)
 
1348
        {
 
1349
                resp->status = 1;
 
1350
                isprintf(msgBuf, bufLen, "%.255s", system_error_msg());
 
1351
        }
 
1352
}
 
1353
 
 
1354
static void     frRenameFile(char *firstFileName, char *secondFileName,
 
1355
                        FilestoreResponse *resp, char *msgBuf, int bufLen)
 
1356
{
 
1357
        if (checkFile(firstFileName) != 1)
 
1358
        {
 
1359
                resp->status = 1;
 
1360
                isprintf(msgBuf, bufLen, "%.255s", system_error_msg());
 
1361
                return;
 
1362
        }
 
1363
 
 
1364
        if (checkFile(secondFileName) == 1)
 
1365
        {
 
1366
                resp->status = 2;
 
1367
                return;
 
1368
        }
 
1369
 
 
1370
        if (rename(firstFileName, secondFileName) < 0)
 
1371
        {
 
1372
                resp->status = 3;
 
1373
                isprintf(msgBuf, bufLen, "%.255s", system_error_msg());
 
1374
        }
 
1375
}
 
1376
 
 
1377
static void     frCopyFile(char *firstFileName, char *secondFileName,
 
1378
                        FilestoreResponse *resp, char *msgBuf, int bufLen,
 
1379
                        int flag)
 
1380
{
 
1381
        char    *buf;
 
1382
        int     destFd;
 
1383
        int     sourceFd;
 
1384
        int     length;
 
1385
        int     bytesWritten;
 
1386
        int     writing = 1;
 
1387
 
 
1388
        if ((buf = MTAKE(10000)) == NULL)
 
1389
        {
 
1390
                resp->status = 3;
 
1391
                istrcpy(msgBuf, "No space for buffer.", bufLen);
 
1392
                return;
 
1393
        }
 
1394
 
 
1395
        destFd = iopen(firstFileName, O_WRONLY | flag, 0);
 
1396
        if (destFd < 0)
 
1397
        {
 
1398
                MRELEASE(buf);
 
1399
                resp->status = 3;
 
1400
                isprintf(msgBuf, bufLen, "%.255s", system_error_msg());
 
1401
                return;
 
1402
        }
 
1403
 
 
1404
        sourceFd = iopen(secondFileName, O_RDONLY, 0);
 
1405
        if (sourceFd < 0)
 
1406
        {
 
1407
                close(destFd);
 
1408
                MRELEASE(buf);
 
1409
                resp->status = 3;
 
1410
                isprintf(msgBuf, bufLen, "%.255s", system_error_msg());
 
1411
                return;
 
1412
        }
 
1413
 
 
1414
        while (writing)
 
1415
        {
 
1416
                length = read(sourceFd, buf, 10000);
 
1417
                switch (length)
 
1418
                {
 
1419
                case -1:
 
1420
                        resp->status = 3;
 
1421
                        isprintf(msgBuf, bufLen, "%.255s", system_error_msg());
 
1422
                        writing = 0;
 
1423
                        break;                  /*      Out of switch.  */
 
1424
 
 
1425
                case 0:                         /*      End of file.    */
 
1426
                        writing = 0;
 
1427
                        break;                  /*      Out of switch.  */
 
1428
 
 
1429
                default:
 
1430
                        while (length > 0)
 
1431
                        {
 
1432
                                bytesWritten = write(destFd, buf, length);
 
1433
                                if (bytesWritten < 0)
 
1434
                                {
 
1435
                                        resp->status = 3;
 
1436
                                        isprintf(msgBuf, bufLen, "%.255s",
 
1437
                                                system_error_msg());
 
1438
                                        writing = 0;
 
1439
                                        break;  /*      Out of loop.    */
 
1440
                                }
 
1441
 
 
1442
                                length -= bytesWritten;
 
1443
                        }
 
1444
                }
 
1445
        }
 
1446
 
 
1447
        close(sourceFd);
 
1448
        close(destFd);
 
1449
        MRELEASE(buf);
 
1450
}
 
1451
 
 
1452
static void     frAppendFile(char *firstFileName, char *secondFileName,
 
1453
                        FilestoreResponse *resp, char *msgBuf, int bufLen)
 
1454
{
 
1455
        if (checkFile(firstFileName) != 1)
 
1456
        {
 
1457
                resp->status = 1;
 
1458
                isprintf(msgBuf, bufLen, "%.255s", system_error_msg());
 
1459
                return;
 
1460
        }
 
1461
 
 
1462
        if (checkFile(secondFileName) != 1)
 
1463
        {
 
1464
                resp->status = 2;
 
1465
                isprintf(msgBuf, bufLen, "%.255s", system_error_msg());
 
1466
                return;
 
1467
        }
 
1468
 
 
1469
        frCopyFile(firstFileName, secondFileName, resp, msgBuf, bufLen,
 
1470
                        O_APPEND);
 
1471
}
 
1472
 
 
1473
static void     frReplaceFile(char *firstFileName, char *secondFileName,
 
1474
                        FilestoreResponse *resp, char *msgBuf, int bufLen)
 
1475
{
 
1476
        if (checkFile(firstFileName) != 1)
 
1477
        {
 
1478
                resp->status = 1;
 
1479
                isprintf(msgBuf, bufLen, "%.255s", system_error_msg());
 
1480
                return;
 
1481
        }
 
1482
 
 
1483
        if (checkFile(secondFileName) != 1)
 
1484
        {
 
1485
                resp->status = 2;
 
1486
                isprintf(msgBuf, bufLen, "%.255s", system_error_msg());
 
1487
                return;
 
1488
        }
 
1489
 
 
1490
        frCopyFile(firstFileName, secondFileName, resp, msgBuf, bufLen,
 
1491
                        O_TRUNC);
 
1492
}
 
1493
 
 
1494
static void     frCreateDirectory(char *firstFileName, char *secondFileName,
 
1495
                        FilestoreResponse *resp, char *msgBuf, int bufLen)
 
1496
{
 
1497
#if (defined(VXWORKS) || defined(mingw))
 
1498
        if (mkdir(firstFileName) < 0)
 
1499
#else
 
1500
        if (mkdir(firstFileName, 0777) < 0)
 
1501
#endif
 
1502
        {
 
1503
                resp->status = 1;
 
1504
                isprintf(msgBuf, bufLen, "%.255s", system_error_msg());
 
1505
        }
 
1506
}
 
1507
 
 
1508
static void     frRemoveDirectory(char *firstFileName, char *secondFileName,
 
1509
                        FilestoreResponse *resp, char *msgBuf, int bufLen)
 
1510
{
 
1511
        if (rmdir(firstFileName) < 0)
 
1512
        {
 
1513
                resp->status = 1;
 
1514
                isprintf(msgBuf, bufLen, "%.255s", system_error_msg());
 
1515
        }
 
1516
}
 
1517
 
 
1518
static void     frDenyFile(char *firstFileName, char *secondFileName,
 
1519
                        FilestoreResponse *resp, char *msgBuf, int bufLen)
 
1520
{
 
1521
        if (checkFile(firstFileName) != 1)
 
1522
        {
 
1523
                return;         /*      Nothing to delete.              */
 
1524
        }
 
1525
 
 
1526
        if (unlink(firstFileName) < 0)
 
1527
        {
 
1528
                resp->status = 1;
 
1529
                isprintf(msgBuf, bufLen, "%.255s", system_error_msg());
 
1530
        }
 
1531
}
 
1532
 
 
1533
static void     frDenyDirectory(char *firstFileName, char *secondFileName,
 
1534
                        FilestoreResponse *resp, char *msgBuf, int bufLen)
 
1535
{
 
1536
        if (checkFile(firstFileName) != 1)
 
1537
        {
 
1538
                return;         /*      Nothing to delete.              */
 
1539
        }
 
1540
 
 
1541
        if (rmdir(firstFileName) < 0)
 
1542
        {
 
1543
                resp->status = 1;
 
1544
                isprintf(msgBuf, bufLen, "%.255s", system_error_msg());
 
1545
        }
 
1546
}
 
1547
 
 
1548
static int      executeFilestoreRequests(InFdu *fdu,
 
1549
                        MetadataList filestoreResponses)
 
1550
{
 
1551
        Sdr                     sdr = getIonsdr();
 
1552
        Object                  elt;
 
1553
                                OBJ_POINTER(FilestoreRequest, req);
 
1554
        char                    firstFileNameBuf[256];
 
1555
        char                    *firstFileName;
 
1556
        char                    secondFileNameBuf[256];
 
1557
        char                    *secondFileName;
 
1558
        Object                  addr;
 
1559
        FilestoreResponse       resp;
 
1560
        char                    msgBuf[256];
 
1561
        int                     reqAborted = 0;
 
1562
 
 
1563
        for (elt = sdr_list_first(sdr, fdu->filestoreRequests); elt;
 
1564
                        elt = sdr_list_next(sdr, elt))
 
1565
        {
 
1566
                GET_OBJ_POINTER(sdr, FilestoreRequest, req,
 
1567
                                sdr_list_data(sdr, elt));
 
1568
                if (req->firstFileName)
 
1569
                {
 
1570
                        sdr_string_read(sdr, firstFileNameBuf,
 
1571
                                        req->firstFileName);
 
1572
                        firstFileName = firstFileNameBuf;
 
1573
                }
 
1574
                else
 
1575
                {
 
1576
                        firstFileName = NULL;
 
1577
                }
 
1578
 
 
1579
                if (req->secondFileName)
 
1580
                {
 
1581
                        sdr_string_read(sdr, secondFileNameBuf,
 
1582
                                        req->secondFileName);
 
1583
                        secondFileName = secondFileNameBuf;
 
1584
                }
 
1585
                else
 
1586
                {
 
1587
                        secondFileName = NULL;
 
1588
                }
 
1589
 
 
1590
                addr = sdr_malloc(sdr, sizeof(FilestoreResponse));
 
1591
                if (addr == 0
 
1592
                || sdr_list_insert_last(sdr, filestoreResponses, addr) == 0)
 
1593
                {
 
1594
                        putErrmsg("Can't create filestore response.", NULL);
 
1595
                        return -1;
 
1596
                }
 
1597
 
 
1598
                memset((char *) &resp, 0, sizeof(FilestoreResponse));
 
1599
                resp.action = req->action;
 
1600
                if (firstFileName)
 
1601
                {
 
1602
                        resp.firstFileName = sdr_string_create(sdr,
 
1603
                                        firstFileName);
 
1604
                        if (resp.firstFileName == 0)
 
1605
                        {
 
1606
                                putErrmsg("Can't write 1st file name.", NULL);
 
1607
                                return -1;
 
1608
                        }
 
1609
                }
 
1610
 
 
1611
                if (secondFileName)
 
1612
                {
 
1613
                        resp.secondFileName = sdr_string_create(sdr,
 
1614
                                        secondFileName);
 
1615
                        if (resp.secondFileName == 0)
 
1616
                        {
 
1617
                                putErrmsg("Can't write 2nd file name.", NULL);
 
1618
                                return -1;
 
1619
                        }
 
1620
                }
 
1621
 
 
1622
                if (reqAborted) /*      All remaining requests fail.    */
 
1623
                {
 
1624
                        resp.status = 15;
 
1625
                        sdr_write(sdr, addr, (char *) &resp,
 
1626
                                        sizeof(FilestoreResponse));
 
1627
                        continue;
 
1628
                }
 
1629
 
 
1630
                msgBuf[0] = '\0';
 
1631
                switch (req->action)
 
1632
                {
 
1633
                case CfdpCreateFile:
 
1634
                        frCreateFile(firstFileName, secondFileName, &resp,
 
1635
                                        msgBuf, sizeof msgBuf);
 
1636
                        break;
 
1637
 
 
1638
                case CfdpDeleteFile:
 
1639
                        frDeleteFile(firstFileName, secondFileName, &resp,
 
1640
                                        msgBuf, sizeof msgBuf);
 
1641
                        break;
 
1642
 
 
1643
                case CfdpRenameFile:
 
1644
                        frRenameFile(firstFileName, secondFileName, &resp,
 
1645
                                        msgBuf, sizeof msgBuf);
 
1646
                        break;
 
1647
 
 
1648
                case CfdpAppendFile:
 
1649
                        frAppendFile(firstFileName, secondFileName, &resp,
 
1650
                                        msgBuf, sizeof msgBuf);
 
1651
                        break;
 
1652
 
 
1653
                case CfdpReplaceFile:
 
1654
                        frReplaceFile(firstFileName, secondFileName, &resp,
 
1655
                                        msgBuf, sizeof msgBuf);
 
1656
                        break;
 
1657
 
 
1658
                case CfdpCreateDirectory:
 
1659
                        frCreateDirectory(firstFileName, secondFileName, &resp,
 
1660
                                        msgBuf, sizeof msgBuf);
 
1661
                        break;
 
1662
 
 
1663
                case CfdpRemoveDirectory:
 
1664
                        frRemoveDirectory(firstFileName, secondFileName, &resp,
 
1665
                                        msgBuf, sizeof msgBuf);
 
1666
                        break;
 
1667
 
 
1668
                case CfdpDenyFile:
 
1669
                        frDenyFile(firstFileName, secondFileName, &resp,
 
1670
                                        msgBuf, sizeof msgBuf);
 
1671
                        break;
 
1672
 
 
1673
                case CfdpDenyDirectory:
 
1674
                        frDenyDirectory(firstFileName, secondFileName, &resp,
 
1675
                                        msgBuf, sizeof msgBuf);
 
1676
                        break;
 
1677
 
 
1678
                default:
 
1679
                        resp.status = 15;
 
1680
                        istrcpy(msgBuf, "Invalid action code.", sizeof msgBuf);
 
1681
                }
 
1682
 
 
1683
                if (resp.status != 0)   /*      Request failed.         */
 
1684
                {
 
1685
                        reqAborted = 1;
 
1686
                        if (strlen(msgBuf) > 0)
 
1687
                        {
 
1688
                                resp.message = sdr_string_create(sdr,
 
1689
                                                msgBuf);
 
1690
                                if (resp.message == 0)
 
1691
                                {
 
1692
                                        putErrmsg("Can't write messge.", NULL);
 
1693
                                        return -1;
 
1694
                                }
 
1695
                        }
 
1696
                }
 
1697
 
 
1698
                sdr_write(sdr, addr, (char *) &resp,
 
1699
                                sizeof(FilestoreResponse));
 
1700
        }
 
1701
 
 
1702
        return 0;
 
1703
}
 
1704
 
 
1705
static void     getQualifiedFileName(char *pathNameBuf, int bufLen,
 
1706
                        char *fileName, int newFile)
 
1707
{
 
1708
        char    *wdname;
 
1709
 
 
1710
        if (*fileName == ION_PATH_DELIMITER)    /*      Absolute path.  */
 
1711
        {
 
1712
                istrcpy(pathNameBuf, fileName, bufLen);
 
1713
        }
 
1714
        else
 
1715
        {
 
1716
                /*      ION working directory is the location for all
 
1717
                 *      received files for which destination path name
 
1718
                 *      is not absolute.                                */
 
1719
 
 
1720
                wdname = getIonWorkingDirectory();
 
1721
                if (*wdname == ION_PATH_DELIMITER)
 
1722
                {
 
1723
                        /*      The cwd path name starts with the path
 
1724
                         *      delimiter, so it's a POSIX file system,
 
1725
                         *      so stringBuf is *not* an absolute path
 
1726
                         *      name, so compute absolute path name.    */
 
1727
 
 
1728
                        isprintf(pathNameBuf, bufLen, "%.255s%c%.255s",
 
1729
                                        wdname, ION_PATH_DELIMITER, fileName);
 
1730
                }
 
1731
                else    /*      Assume file name is an absolute path.   */
 
1732
                {
 
1733
                        istrcpy(pathNameBuf, fileName, bufLen);
 
1734
                }
 
1735
        }
 
1736
 
 
1737
        if (!newFile)
 
1738
        {
 
1739
                return;
 
1740
        }
 
1741
 
 
1742
#if (!(defined(VXWORKS) || defined(mingw)))
 
1743
        /*      If nothing has yet been written to this file, create
 
1744
         *      (as necessary) the directory in which the file is to
 
1745
         *      be created.
 
1746
         *
 
1747
         *      Per Josh Schoolcraft, 23 June 2011.
 
1748
         *
 
1749
         *      Given the destination file's qualified pathname, try
 
1750
         *      to make sure the directory in which the file is to be
 
1751
         *      created exists.
 
1752
         *
 
1753
         *      Each directory on the path that doesn't already exist
 
1754
         *      is created: at each level of the directory tree a
 
1755
         *      qualified name is used to create the directory that
 
1756
         *      is needed at that level.
 
1757
         *
 
1758
         *      Note that the length of the path name is known not
 
1759
         *      to be zero: if no Metadata yet, or if the destination
 
1760
         *      file name in the Metadata PDU was of length zero,
 
1761
         *      then getFileName() made up a name based on the FDU's
 
1762
         *      transaction ID because fdu->workingFileName was zero.   */
 
1763
 
 
1764
        size_t  pathNameLen;
 
1765
        char    *cursor;
 
1766
        char    *lastPathSeparator = NULL;
 
1767
 
 
1768
        pathNameLen = istrlen(pathNameBuf, bufLen);
 
1769
        if (pathNameLen > MAXPATHLEN)           /*      Too long.       */
 
1770
        {
 
1771
                return;         /*      Can't create the directory.     */
 
1772
        }
 
1773
 
 
1774
        /*      Temporarily strip off the unqualified file name, i.e.,
 
1775
         *      everything after and including the last path separator
 
1776
         *      character.                                              */
 
1777
 
 
1778
        cursor = pathNameBuf + pathNameLen;     /*      Terminal NULL.  */
 
1779
        while (cursor > pathNameBuf)
 
1780
        {
 
1781
                if (*cursor == ION_PATH_DELIMITER)
 
1782
                {
 
1783
                        lastPathSeparator = cursor;
 
1784
                        *cursor = 0;    /*      Delimit at file name.   */
 
1785
                        break;
 
1786
                }
 
1787
 
 
1788
                cursor--;
 
1789
        }
 
1790
 
 
1791
        /*      Now create directories along the path as necessary.
 
1792
         *      Wherever a path name separator is found, we change
 
1793
         *      it to NULL, create a directory using all qualification
 
1794
         *      to that point, and then restore the separator to
 
1795
         *      enable creation of the next directory in the path.
 
1796
         *
 
1797
         *      We skip over the first byte of the path name: if
 
1798
         *      it's not a path name separator then we wouldn't act
 
1799
         *      on it anyway, and if it is then we want to ignore
 
1800
         *      it since we'd never create a top-level directory
 
1801
         *      with a name of length zero.                             */
 
1802
 
 
1803
        for (cursor = pathNameBuf + 1; *cursor; cursor++)
 
1804
        {
 
1805
                if (*cursor == ION_PATH_DELIMITER)
 
1806
                {
 
1807
                        *cursor = 0;
 
1808
                        oK(mkdir(pathNameBuf, 0777));
 
1809
 
 
1810
                        /*      NOTE: if the qualification path is
 
1811
                         *      explicitly relative, we execute
 
1812
                         *      'mkdir .', trying (and failing) to
 
1813
                         *      create the current working directory.
 
1814
                         *      If the qualification path is absolute,
 
1815
                         *      we might try (and fail) to create the
 
1816
                         *      top-level directory for the file
 
1817
                         *      system.  In short, the failure of path
 
1818
                         *      mkdir operations is not anomalous, so
 
1819
                         *      we don't check the return code.         */
 
1820
 
 
1821
                        *cursor = ION_PATH_DELIMITER;
 
1822
                }
 
1823
        }
 
1824
 
 
1825
        /*      Now create the destination directory itself.            */
 
1826
 
 
1827
        oK(mkdir(pathNameBuf, 0777));
 
1828
 
 
1829
        /*      And restore the original qualified path name.           */
 
1830
 
 
1831
        if (lastPathSeparator)
 
1832
        {
 
1833
                *lastPathSeparator = ION_PATH_DELIMITER;
 
1834
        }
 
1835
#endif
 
1836
}
 
1837
 
 
1838
static void     renameWorkingFile(InFdu *fduBuf)
 
1839
{
 
1840
        Sdr     sdr = getIonsdr();
 
1841
        char    workingFileName[256];
 
1842
        char    destFileName[256];
 
1843
        char    qualifiedFileName[MAXPATHLEN + 2];
 
1844
        char    renameErrBuffer[600];
 
1845
 
 
1846
        sdr_string_read(sdr, workingFileName, fduBuf->workingFileName);
 
1847
        sdr_string_read(sdr, destFileName, fduBuf->destFileName);
 
1848
        getQualifiedFileName(qualifiedFileName, sizeof qualifiedFileName,
 
1849
                        destFileName, 1);
 
1850
        if (rename(workingFileName, qualifiedFileName) < 0)
 
1851
        {
 
1852
                isprintf(renameErrBuffer, sizeof renameErrBuffer,
 
1853
                                "CFDP can't rename '%s' to '%s'",
 
1854
                                workingFileName, qualifiedFileName);
 
1855
                putSysErrmsg(renameErrBuffer, NULL);
 
1856
        }
 
1857
}
 
1858
 
 
1859
int     completeInFdu(InFdu *fduBuf, Object fduObj, Object fduElt,
 
1860
                CfdpCondition condition, int reqNbr)
 
1861
{
 
1862
        Sdr             sdr = getIonsdr();
 
1863
        CfdpDB          *db = getCfdpConstants();
 
1864
        CfdpEvent       event;
 
1865
        char            workingFileName[256];
 
1866
        char            reportBuffer[256];
 
1867
 
 
1868
        CHKERR(ionLocked());
 
1869
        CHKERR(fduBuf);
 
1870
        CHKERR(fduObj);
 
1871
        CHKERR(fduElt);
 
1872
        memset((char *) &event, 0, sizeof(CfdpEvent));
 
1873
        event.type = CfdpTransactionFinishedInd;
 
1874
        memcpy((char *) &event.transactionId, (char *) &fduBuf->transactionId,
 
1875
                        sizeof(CfdpTransactionId));
 
1876
        event.condition = condition;
 
1877
        event.reqNbr = reqNbr;
 
1878
        switch (condition)
 
1879
        {
 
1880
        case CfdpNoError:
 
1881
                if (fduBuf->destFileName == 0)
 
1882
                {
 
1883
                        event.fileStatus = CfdpFileStatusUnreported;
 
1884
                }
 
1885
                else
 
1886
                {
 
1887
                        event.fileStatus = CfdpFileRetained;
 
1888
                        if (fduBuf->destFileName
 
1889
                        && fduBuf->workingFileName != fduBuf->destFileName)
 
1890
                        {
 
1891
                                renameWorkingFile(fduBuf);
 
1892
                        }
 
1893
                }
 
1894
 
 
1895
                event.deliveryCode = CfdpDataComplete;
 
1896
                event.filestoreResponses = createMetadataList(db->fsrespLists);
 
1897
                if (event.filestoreResponses == 0)
 
1898
                {
 
1899
                        putErrmsg("CFDP can't record filestore responses.",
 
1900
                                        NULL);
 
1901
                        return -1;
 
1902
                }
 
1903
 
 
1904
                if (executeFilestoreRequests(fduBuf,
 
1905
                                event.filestoreResponses) < 0)
 
1906
                {
 
1907
                        putErrmsg("CFDP can't execute filestore requests.",
 
1908
                                        NULL);
 
1909
                        return -1;
 
1910
                }
 
1911
 
 
1912
                break;
 
1913
 
 
1914
        case CfdpFilestoreRejection:
 
1915
                event.fileStatus = CfdpFileRejected;
 
1916
                event.deliveryCode = CfdpDataIncomplete;
 
1917
                break;
 
1918
 
 
1919
        default:
 
1920
                if (fduBuf->destFileName == 0)
 
1921
                {
 
1922
                        event.fileStatus = CfdpFileStatusUnreported;
 
1923
                        if (fduBuf->checksumVerified)
 
1924
                        {
 
1925
                                event.deliveryCode = CfdpDataComplete;
 
1926
                        }
 
1927
                        else
 
1928
                        {
 
1929
                                event.deliveryCode = CfdpDataIncomplete;
 
1930
                        }
 
1931
                }
 
1932
                else
 
1933
                {
 
1934
                        if (db->discardIncompleteFile)
 
1935
                        {
 
1936
                                sdr_string_read(sdr, workingFileName,
 
1937
                                                fduBuf->workingFileName);
 
1938
                                unlink(workingFileName);
 
1939
                                event.fileStatus = CfdpFileDiscarded;
 
1940
                                event.deliveryCode = CfdpDataIncomplete;
 
1941
                        }
 
1942
                        else
 
1943
                        {
 
1944
                                event.fileStatus = CfdpFileRetained;
 
1945
                                if (fduBuf->destFileName
 
1946
                                && fduBuf->workingFileName !=
 
1947
                                                fduBuf->destFileName)
 
1948
                                {
 
1949
                                        renameWorkingFile(fduBuf);
 
1950
                                }
 
1951
 
 
1952
                                if (fduBuf->checksumVerified)
 
1953
                                {
 
1954
                                        event.deliveryCode = CfdpDataComplete;
 
1955
                                }
 
1956
                                else
 
1957
                                {
 
1958
                                        event.deliveryCode =
 
1959
                                                        CfdpDataIncomplete;
 
1960
                                }
 
1961
                        }
 
1962
                }
 
1963
        }
 
1964
 
 
1965
        isprintf(reportBuffer, sizeof reportBuffer, "bytesReceived %u  size \
 
1966
%u  progress %u", fduBuf->bytesReceived, fduBuf->fileSize, fduBuf->progress);
 
1967
        event.statusReport = sdr_string_create(sdr, reportBuffer);
 
1968
        event.reqNbr = getReqNbr();
 
1969
        if (enqueueCfdpEvent(&event) < 0)
 
1970
        {
 
1971
                putErrmsg("CFDP can't complete inbound transaction.", NULL);
 
1972
                return -1;
 
1973
        }
 
1974
 
 
1975
        destroyInFdu(fduBuf, fduObj, fduElt);
 
1976
        return event.reqNbr;
 
1977
}
 
1978
 
 
1979
/*      *       *       Service interface functions     *       *       */
 
1980
 
 
1981
int     enqueueCfdpEvent(CfdpEvent *event)
 
1982
{
 
1983
        Sdr     sdr = getIonsdr();
 
1984
        CfdpDB  *cfdpConstants = _cfdpConstants();
 
1985
        CfdpVdb *cfdpvdb = _cfdpvdb(NULL);
 
1986
        Object  eventObj;
 
1987
 
 
1988
        CHKERR(ionLocked());
 
1989
        CHKERR(event);
 
1990
        eventObj = sdr_malloc(sdr, sizeof(CfdpEvent));
 
1991
        if (eventObj == 0)
 
1992
        {
 
1993
                putErrmsg("Can't create CFDP event.", NULL);
 
1994
                return -1;
 
1995
        }
 
1996
 
 
1997
        if (sdr_list_insert_last(sdr, cfdpConstants->events, eventObj) == 0)
 
1998
        {
 
1999
                putErrmsg("Can't enqueue CFDP event.", NULL);
 
2000
                return -1;
 
2001
        }
 
2002
 
 
2003
        sdr_write(sdr, eventObj, (char *) event, sizeof(CfdpEvent));
 
2004
 
 
2005
        /*      Tell user application that an event is waiting.         */
 
2006
 
 
2007
        sm_SemGive(cfdpvdb->eventSemaphore);
 
2008
        return 0;
 
2009
}
 
2010
 
 
2011
int     handleFault(CfdpTransactionId *transactionId, CfdpCondition fault,
 
2012
                CfdpHandler *handler)
 
2013
{
 
2014
        Sdr             sdr = getIonsdr();
 
2015
        CfdpDB          cfdpdb;
 
2016
        Object          fduObj;
 
2017
        InFdu           inFdu;
 
2018
        OutFdu          outFdu;
 
2019
        Object          fduElt;
 
2020
        CfdpEvent       event;
 
2021
 
 
2022
        CHKERR(transactionId);
 
2023
        CHKERR(handler);
 
2024
        *handler = CfdpNoHandler;
 
2025
        sdr_read(sdr, (char *) &cfdpdb, getCfdpDbObject(), sizeof(CfdpDB));
 
2026
        if (memcmp((char *) &transactionId->sourceEntityNbr,
 
2027
                        (char *) &cfdpdb.ownEntityNbr, sizeof(CfdpNumber)) == 0)
 
2028
        {
 
2029
                memset((char *) &outFdu, 0, sizeof(OutFdu));
 
2030
                fduObj = findOutFdu(transactionId, &outFdu, &fduElt);
 
2031
                if (fduObj != 0)
 
2032
                {
 
2033
                        *handler = outFdu.faultHandlers[fault];
 
2034
                }
 
2035
        }
 
2036
        else
 
2037
        {
 
2038
                memset((char *) &inFdu, 0, sizeof(InFdu));
 
2039
                fduObj = findInFdu(transactionId, &inFdu, &fduElt, 0);
 
2040
                if (fduObj != 0)
 
2041
                {
 
2042
                        *handler = inFdu.faultHandlers[fault];
 
2043
                }
 
2044
        }
 
2045
 
 
2046
        if (*handler == CfdpNoHandler)
 
2047
        {
 
2048
                *handler = cfdpdb.faultHandlers[fault];
 
2049
        }
 
2050
 
 
2051
        switch (*handler)
 
2052
        {
 
2053
        case CfdpCancel:
 
2054
                if (fduObj == 0)
 
2055
                {
 
2056
                        return 0;
 
2057
                }
 
2058
 
 
2059
                if (memcmp((char *) &transactionId->sourceEntityNbr,
 
2060
                                (char *) &cfdpdb.ownEntityNbr,
 
2061
                                sizeof(CfdpNumber)) == 0)
 
2062
                {
 
2063
                        return cancelOutFdu(transactionId, fault, 0);
 
2064
                }
 
2065
 
 
2066
                return completeInFdu(&inFdu, fduObj, fduElt, fault, 0);
 
2067
 
 
2068
        case CfdpSuspend:
 
2069
                if (fduObj == 0)
 
2070
                {
 
2071
                        return 0;
 
2072
                }
 
2073
 
 
2074
                if (memcmp((char *) &transactionId->sourceEntityNbr,
 
2075
                                (char *) &cfdpdb.ownEntityNbr,
 
2076
                                sizeof(CfdpNumber)) == 0)
 
2077
                {
 
2078
                        return suspendOutFdu(transactionId, fault, 0);
 
2079
                }
 
2080
 
 
2081
                return 0;       /*      Per 4.1.11.3.1.2.               */
 
2082
 
 
2083
        case CfdpIgnore:
 
2084
                memset((char *) &event, 0, sizeof(CfdpEvent));
 
2085
                event.type = CfdpFaultInd;
 
2086
                memcpy((char *) &event.transactionId, (char *) transactionId,
 
2087
                                sizeof(CfdpTransactionId));
 
2088
                event.condition = fault;
 
2089
                if (memcmp((char *) &transactionId->sourceEntityNbr,
 
2090
                                (char *) &cfdpdb.ownEntityNbr,
 
2091
                                sizeof(CfdpNumber)) == 0)
 
2092
                {
 
2093
                        event.progress = outFdu.progress;
 
2094
                }
 
2095
                else
 
2096
                {
 
2097
                        event.progress = inFdu.progress;
 
2098
                }
 
2099
 
 
2100
                event.reqNbr = 0;
 
2101
                if (enqueueCfdpEvent(&event) < 0)
 
2102
                {
 
2103
                        putErrmsg("Can't post Fault indication.", NULL);
 
2104
                        return -1;
 
2105
                }
 
2106
 
 
2107
                return 0;
 
2108
 
 
2109
        case CfdpAbandon:
 
2110
                if (fduObj == 0)
 
2111
                {
 
2112
                        return 0;
 
2113
                }
 
2114
 
 
2115
                if (memcmp((char *) &transactionId->sourceEntityNbr,
 
2116
                                (char *) &cfdpdb.ownEntityNbr,
 
2117
                                sizeof(CfdpNumber)) == 0)
 
2118
                {
 
2119
                        return abandonOutFdu(transactionId, fault);
 
2120
                }
 
2121
 
 
2122
                return abandonInFdu(transactionId, fault);
 
2123
 
 
2124
        default:
 
2125
                return 0;
 
2126
        }
 
2127
}
 
2128
 
 
2129
/*      *       *       PDU issuance functions  *       *       *       */
 
2130
 
 
2131
static Object   selectOutFdu(OutFdu *buffer)
 
2132
{
 
2133
        Sdr     sdr = getIonsdr();
 
2134
        CfdpDB  *cfdpConstants = _cfdpConstants();
 
2135
        Object  elt;
 
2136
        Object  obj;
 
2137
 
 
2138
        for (elt = sdr_list_first(sdr, cfdpConstants->outboundFdus); elt;
 
2139
                        elt = sdr_list_next(sdr, elt))
 
2140
        {
 
2141
                obj = sdr_list_data(sdr, elt);
 
2142
                sdr_read(sdr, (char *) buffer, obj, sizeof(OutFdu));
 
2143
                if (buffer->state != FduActive
 
2144
                || buffer->eofPdu == 0  /*      Nothing left to send.   */)
 
2145
                {
 
2146
                        continue;
 
2147
                }
 
2148
 
 
2149
                return obj;
 
2150
        }
 
2151
 
 
2152
        return 0;
 
2153
}
 
2154
 
 
2155
static Object   selectOutPdu(OutFdu *fdu, int *pduIsFileData)
 
2156
{
 
2157
        Object          pdu;
 
2158
        Sdr             sdr = getIonsdr();
 
2159
        Object          elt;
 
2160
        unsigned int    length;
 
2161
        unsigned int    offset;
 
2162
        Object          header;
 
2163
 
 
2164
        if (fdu->metadataPdu)
 
2165
        {
 
2166
                pdu = fdu->metadataPdu;
 
2167
                fdu->metadataPdu = 0;
 
2168
                *pduIsFileData = 0;
 
2169
                return pdu;
 
2170
        }
 
2171
 
 
2172
        if (fdu->fileSize > 0)
 
2173
        {
 
2174
                elt = sdr_list_first(sdr, fdu->recordLengths);
 
2175
                if (elt)
 
2176
                {
 
2177
                        length = sdr_list_data(sdr, elt);
 
2178
                        offset = fdu->progress;
 
2179
                        offset = htonl(offset);
 
2180
                        header = sdr_malloc(sdr, 4);
 
2181
                        if (header == 0)
 
2182
                        {
 
2183
                                putErrmsg("No space for file PDU hdr.", NULL);
 
2184
                                return 0;
 
2185
                        }
 
2186
 
 
2187
                        sdr_write(sdr, header, (char *) &offset, 4);
 
2188
                        pdu = zco_create(sdr, ZcoSdrSource, header, 0, 4);
 
2189
                        if (pdu == 0)
 
2190
                        {
 
2191
                                putErrmsg("No space for file PDU.", NULL);
 
2192
                                return 0;
 
2193
                        }
 
2194
 
 
2195
                        if (zco_append_extent(sdr, pdu, ZcoFileSource,
 
2196
                                fdu->fileRef, fdu->progress, length) < 0)
 
2197
                        {
 
2198
                                putErrmsg("Can't append extent.", NULL);
 
2199
                                return 0;
 
2200
                        }
 
2201
 
 
2202
                        sdr_list_delete(sdr, elt, NULL, NULL);
 
2203
                        fdu->progress += length;
 
2204
                        *pduIsFileData = 1;
 
2205
                        return pdu;
 
2206
                }
 
2207
        }
 
2208
 
 
2209
        pdu = fdu->eofPdu;
 
2210
        fdu->eofPdu = 0;
 
2211
        *pduIsFileData = 0;
 
2212
        return pdu;
 
2213
}
 
2214
 
 
2215
int     cfdpDequeueOutboundPdu(Object *pdu, OutFdu *fduBuffer)
 
2216
{
 
2217
        Sdr             sdr = getIonsdr();
 
2218
        CfdpVdb         *cfdpvdb = _cfdpvdb(NULL);
 
2219
        CfdpDB          cfdpdb;
 
2220
        Object          fduObj;
 
2221
        int             pduIsFileData = 0;      /*      Boolean.        */
 
2222
        unsigned int    dataFieldLength;
 
2223
        unsigned int    octet;
 
2224
        int             pduSourceDataLength;
 
2225
        int             entityNbrLength;
 
2226
        unsigned char   pduHeader[28];
 
2227
        unsigned int    pduHeaderLength = 4;
 
2228
        unsigned int    proposedLength;
 
2229
        unsigned char   *buf;
 
2230
        ZcoReader       reader;
 
2231
        unsigned short  crc;
 
2232
 
 
2233
        CHKERR(pdu);
 
2234
        CHKERR(fduBuffer);
 
2235
        sdr_begin_xn(sdr);
 
2236
        fduObj = selectOutFdu(fduBuffer);
 
2237
        while (fduObj == 0)
 
2238
        {
 
2239
                sdr_exit_xn(sdr);
 
2240
 
 
2241
                /*      Wait until an FDU is resumed or a new one
 
2242
                 *      is created.                                     */
 
2243
 
 
2244
                if (sm_SemTake(cfdpvdb->fduSemaphore) < 0)
 
2245
                {
 
2246
                        putErrmsg("UTO can't take FDU semaphore.", NULL);
 
2247
                        return -1;
 
2248
                }
 
2249
 
 
2250
                if (sm_SemEnded(cfdpvdb->fduSemaphore))
 
2251
                {
 
2252
                        writeMemo("[i] UTO has been stopped.");
 
2253
                        return -1;
 
2254
                }
 
2255
 
 
2256
                sdr_begin_xn(sdr);
 
2257
                fduObj = selectOutFdu(fduBuffer);
 
2258
        }
 
2259
 
 
2260
        sdr_stage(sdr, NULL, fduObj, 0);
 
2261
        *pdu = selectOutPdu(fduBuffer, &pduIsFileData);
 
2262
        if (*pdu == 0)
 
2263
        {
 
2264
                putErrmsg("UTO can't get outbound PDU.", NULL);
 
2265
                sdr_cancel_xn(sdr);
 
2266
                return -1;
 
2267
        }
 
2268
 
 
2269
        sdr_read(sdr, (char *) &cfdpdb, getCfdpDbObject(), sizeof(CfdpDB));
 
2270
        octet = (pduIsFileData << 4)    /*      bit 3 is PDU type       */
 
2271
                        + 4             /*      1 in bit 6 == unack     */
 
2272
                        + (cfdpdb.crcRequired ? 2 : 0);
 
2273
        pduHeader[0] = octet;
 
2274
        pduSourceDataLength = zco_length(sdr, *pdu);
 
2275
        dataFieldLength = pduSourceDataLength
 
2276
                        + (cfdpdb.crcRequired ? 2 : 0);
 
2277
 
 
2278
        /*      Note that length of CRC, if present, is included in
 
2279
         *      the data field length per 4.1.1.3.2.                    */
 
2280
 
 
2281
        pduHeader[1] = (dataFieldLength >> 8) & 0xff;
 
2282
        pduHeader[2] = dataFieldLength & 0xff;
 
2283
 
 
2284
        /*      Compute the lengths byte value.                         */
 
2285
 
 
2286
        entityNbrLength = cfdpdb.ownEntityNbr.length;
 
2287
        if (fduBuffer->destinationEntityNbr.length > entityNbrLength)
 
2288
        {
 
2289
                entityNbrLength = fduBuffer->destinationEntityNbr.length;
 
2290
        }
 
2291
 
 
2292
        octet = ((entityNbrLength - 1) << 4)
 
2293
                        + (fduBuffer->transactionId.transactionNbr.length - 1);
 
2294
        pduHeader[3] = octet;
 
2295
 
 
2296
        /*      Insert entity IDs and transaction number.               */
 
2297
 
 
2298
        proposedLength = pduHeaderLength + entityNbrLength
 
2299
                        + fduBuffer->transactionId.transactionNbr.length
 
2300
                        + entityNbrLength;
 
2301
        if (proposedLength > sizeof pduHeader)
 
2302
        {
 
2303
                sdr_cancel_xn(sdr);
 
2304
                putErrmsg("pduHeaderLength too large.", utoa(proposedLength));
 
2305
                return -1;
 
2306
        }
 
2307
 
 
2308
        memcpy(pduHeader + pduHeaderLength, cfdpdb.ownEntityNbr.buffer,
 
2309
                        entityNbrLength);
 
2310
        pduHeaderLength += entityNbrLength;
 
2311
        memcpy(pduHeader + pduHeaderLength,
 
2312
                        fduBuffer->transactionId.transactionNbr.buffer,
 
2313
                        fduBuffer->transactionId.transactionNbr.length);
 
2314
        pduHeaderLength += fduBuffer->transactionId.transactionNbr.length;
 
2315
        memcpy(pduHeader + pduHeaderLength,
 
2316
                        fduBuffer->destinationEntityNbr.buffer,
 
2317
                        entityNbrLength);
 
2318
        pduHeaderLength += entityNbrLength;
 
2319
 
 
2320
        /*      Prepend header to pdu.                                  */
 
2321
 
 
2322
        oK(zco_prepend_header(sdr, *pdu, (char *) pduHeader,
 
2323
                        pduHeaderLength));
 
2324
 
 
2325
        /*      If CRC required, compute CRC and append to pdu.         */
 
2326
 
 
2327
        if (cfdpdb.crcRequired)
 
2328
        {
 
2329
                buf = _crcComputationBuf();
 
2330
                memcpy((char *) buf, pduHeader, pduHeaderLength);
 
2331
                zco_start_receiving(sdr, *pdu, &reader);
 
2332
                if (zco_receive_source(sdr, &reader, pduSourceDataLength,
 
2333
                                ((char *) buf) + pduHeaderLength) < 0)
 
2334
                {
 
2335
                        sdr_cancel_xn(sdr);
 
2336
                        putErrmsg("Can't read ZCO.", NULL);
 
2337
                        return -1;
 
2338
                }
 
2339
 
 
2340
                zco_stop_receiving(sdr, &reader);
 
2341
                crc = computeCRC(buf, pduHeaderLength + pduSourceDataLength);
 
2342
                crc = htons(crc);
 
2343
                oK(zco_append_trailer(sdr, *pdu, (char *) &crc, 2));
 
2344
        }
 
2345
 
 
2346
        /*      Rewrite FDU and exit.                                   */
 
2347
 
 
2348
        sdr_write(sdr, fduObj, (char *) fduBuffer, sizeof(OutFdu));
 
2349
        if (sdr_end_xn(sdr))
 
2350
        {
 
2351
                putErrmsg("UTO can't dequeue outbound PDU.", NULL);
 
2352
                return -1;
 
2353
        }
 
2354
 
 
2355
        if (cfdpvdb->watching & WATCH_p)
 
2356
        {
 
2357
                putchar('p');
 
2358
                fflush(stdout);
 
2359
        }
 
2360
 
 
2361
        return 0;
 
2362
}
 
2363
 
 
2364
/*      *       *       PDU handling functions  *       *       *       */
 
2365
 
 
2366
static int      checkInFduComplete(InFdu *fdu, Object fduObj, Object fduElt)
 
2367
{
 
2368
        CfdpVdb         *cfdpvdb = _cfdpvdb(NULL);
 
2369
        CfdpHandler     handler;
 
2370
 
 
2371
        if (!fdu->metadataReceived)
 
2372
        {
 
2373
                return 0;
 
2374
        }
 
2375
 
 
2376
        if (!fdu->eofReceived)
 
2377
        {
 
2378
                return 0;
 
2379
        }
 
2380
 
 
2381
        if (fdu->bytesReceived < fdu->fileSize) /*      Missing data.   */
 
2382
        {
 
2383
                return 0;
 
2384
        }
 
2385
 
 
2386
        if (cfdpvdb->currentFile != -1)
 
2387
        {
 
2388
                close(cfdpvdb->currentFile);
 
2389
                cfdpvdb->currentFile = -1;
 
2390
        }
 
2391
 
 
2392
        if (fdu->computedChecksum == fdu->eofChecksum)
 
2393
        {
 
2394
                fdu->checksumVerified = 1;
 
2395
        }
 
2396
        else
 
2397
        {
 
2398
                if (handleFault(&fdu->transactionId, CfdpChecksumFailure,
 
2399
                                        &handler) < 0)
 
2400
                {
 
2401
                        putErrmsg("Can't check FDU completion.", NULL);
 
2402
                        return -1;
 
2403
                }
 
2404
 
 
2405
                switch (handler)
 
2406
                {
 
2407
                case CfdpCancel:
 
2408
                case CfdpAbandon:
 
2409
                        return 0;               /*      Nothing to do.  */
 
2410
 
 
2411
                default:
 
2412
                        break;                  /*      No problem.     */
 
2413
                }
 
2414
        }
 
2415
 
 
2416
        return completeInFdu(fdu, fduObj, fduElt, CfdpNoError, 0);
 
2417
}
 
2418
 
 
2419
static int      getFileName(InFdu *fdu, char *stringBuf, int bufLen)
 
2420
{
 
2421
        Sdr             sdr = getIonsdr();
 
2422
        unsigned long   sourceEntityId;
 
2423
        unsigned long   transactionNbr;
 
2424
 
 
2425
        if (fdu->workingFileName == 0)
 
2426
        {
 
2427
                cfdp_decompress_number(&sourceEntityId,
 
2428
                                &fdu->transactionId.sourceEntityNbr);
 
2429
                cfdp_decompress_number(&transactionNbr,
 
2430
                                &fdu->transactionId.transactionNbr);
 
2431
                isprintf(stringBuf, bufLen, "%s%ccfdp.%lu.%lu",
 
2432
                                getIonWorkingDirectory(), ION_PATH_DELIMITER,
 
2433
                                sourceEntityId, transactionNbr);
 
2434
                fdu->workingFileName = sdr_string_create(sdr, stringBuf);
 
2435
                if (fdu->workingFileName == 0)
 
2436
                {
 
2437
                        putErrmsg("Can't retain working file name.", NULL);
 
2438
                        return -1;
 
2439
                }
 
2440
        }
 
2441
        else
 
2442
        {
 
2443
                sdr_string_read(sdr, stringBuf, fdu->workingFileName);
 
2444
        }
 
2445
 
 
2446
        return 0;
 
2447
}
 
2448
 
 
2449
static int      handleFilestoreRejection(InFdu *fdu, int returnCode,
 
2450
                        CfdpHandler *handler)
 
2451
{
 
2452
        if (handleFault(&fdu->transactionId, CfdpFilestoreRejection,
 
2453
                                handler) < 0)
 
2454
        {
 
2455
                putErrmsg("Can't handle filestore rejection.", NULL);
 
2456
                returnCode = -1;
 
2457
        }
 
2458
 
 
2459
        return returnCode;
 
2460
}
 
2461
 
 
2462
static int      writeSegmentData(InFdu *fdu, unsigned char **cursor,
 
2463
                        int *bytesRemaining, unsigned int *segmentOffset,
 
2464
                        int bytesToWrite)
 
2465
{
 
2466
        CfdpVdb         *cfdpvdb = _cfdpvdb(NULL);
 
2467
        CfdpHandler     handler;
 
2468
        int             remainder;
 
2469
 
 
2470
        if (cfdpvdb->corruptionModulus)
 
2471
        {
 
2472
                remainder = rand() % cfdpvdb->corruptionModulus;
 
2473
                if (remainder == 0)
 
2474
                {
 
2475
                        (**cursor)++;   /*      Introduce corruption.   */
 
2476
                        writeMemo("CFDP corrupted a byte.");
 
2477
                }
 
2478
        }
 
2479
 
 
2480
        if (write(cfdpvdb->currentFile, *cursor, bytesToWrite) < 0)
 
2481
        {
 
2482
                putSysErrmsg("Can't write to file", itoa(bytesToWrite));
 
2483
                return handleFilestoreRejection(fdu, -1, &handler);
 
2484
        }
 
2485
 
 
2486
        fdu->bytesReceived += bytesToWrite;
 
2487
        while (bytesToWrite > 0)
 
2488
        {
 
2489
                addToChecksum(**cursor, segmentOffset, &fdu->computedChecksum);
 
2490
                (*cursor)++;
 
2491
                (*bytesRemaining)--;
 
2492
                bytesToWrite--;
 
2493
        }
 
2494
 
 
2495
        return 0;
 
2496
}
 
2497
 
 
2498
static int      handleFileDataPdu(unsigned char *cursor, int bytesRemaining,
 
2499
                        int dataFieldLength, InFdu *fdu, Object fduObj,
 
2500
                        Object fduElt)
 
2501
{
 
2502
        int             firstSegment = (fdu->progress == 0);
 
2503
        int             i;
 
2504
        unsigned int    segmentOffset = 0;
 
2505
        CfdpEvent       event;
 
2506
        unsigned int    segmentEnd;
 
2507
        CfdpHandler     handler;
 
2508
        Sdr             sdr = getIonsdr();
 
2509
        CfdpVdb         *cfdpvdb = _cfdpvdb(NULL);
 
2510
        CfdpDB          cfdpdb;
 
2511
        Object          elt;
 
2512
        Object          addr;
 
2513
        CfdpExtent      extent;
 
2514
        unsigned int    extentEnd = 0;
 
2515
        Object          nextElt = 0;
 
2516
        unsigned int    bytesToSkip;
 
2517
        char            stringBuf[256];
 
2518
        char            workingNameBuffer[MAXPATHLEN + 2];
 
2519
        off_t           endOfFile;
 
2520
        unsigned int    fileLength;
 
2521
        Object          nextAddr;
 
2522
        CfdpExtent      nextExtent;
 
2523
        unsigned int    bytesToWrite;
 
2524
        unsigned int    nextExtentEnd;
 
2525
 
 
2526
        if (bytesRemaining < 4) return 0;       /*      Malformed.      */
 
2527
        for (i = 0; i < 4; i++)
 
2528
        {
 
2529
                segmentOffset = (segmentOffset << 8) + *cursor;
 
2530
                cursor++;
 
2531
                bytesRemaining--;
 
2532
        }
 
2533
 
 
2534
        if (bytesRemaining == 0)                /*      No file data.   */
 
2535
        {
 
2536
                return 0;                       /*      Nothing to do.  */
 
2537
        }
 
2538
 
 
2539
        sdr_read(sdr, (char *) &cfdpdb, getCfdpDbObject(), sizeof(CfdpDB));
 
2540
        fdu->inactivityDeadline += cfdpdb.transactionInactivityLimit;
 
2541
 
 
2542
        /*      Prepare to issue indication.                            */
 
2543
 
 
2544
        memset((char *) &event, 0, sizeof(CfdpEvent));
 
2545
        event.type = CfdpFileSegmentRecvInd;
 
2546
        memcpy((char *) &event.transactionId, (char *) &fdu->transactionId,
 
2547
                        sizeof(CfdpTransactionId));
 
2548
        event.offset = segmentOffset;
 
2549
        event.length = bytesRemaining;
 
2550
 
 
2551
        /*      Update reception progress, check for fault.             */
 
2552
 
 
2553
        segmentEnd = segmentOffset + bytesRemaining;
 
2554
        if (segmentEnd > fdu->progress)
 
2555
        {
 
2556
                fdu->progress = segmentEnd;
 
2557
                if (fdu->eofReceived && fdu->progress > fdu->fileSize)
 
2558
                {
 
2559
                        if (handleFault(&fdu->transactionId, CfdpFileSizeError,
 
2560
                                        &handler) < 0)
 
2561
                        {
 
2562
                                putErrmsg("Can't handle EOF PDU.", NULL);
 
2563
                                return -1;
 
2564
                        }
 
2565
 
 
2566
                        switch (handler)
 
2567
                        {
 
2568
                        case CfdpCancel:
 
2569
                        case CfdpAbandon:
 
2570
                                return 0;       /*      Nothing to do.  */
 
2571
 
 
2572
                        default:
 
2573
                                break;          /*      No problem.     */
 
2574
                        }
 
2575
                }
 
2576
        }
 
2577
 
 
2578
        /*      Figure out how much of the file data PDU is new data.   */
 
2579
 
 
2580
        for (elt = sdr_list_first(sdr, fdu->extents); elt;
 
2581
                        elt = sdr_list_next(sdr, elt))
 
2582
        {
 
2583
                addr = sdr_list_data(sdr, elt);
 
2584
                sdr_stage(sdr, (char *) &extent, addr, sizeof(CfdpExtent));
 
2585
                extentEnd = extent.offset + extent.length;
 
2586
#if CFDPDEBUG
 
2587
printf("Viewing extent from %d to %d.\n", extent.offset, extent.offset + extent.length);
 
2588
#endif
 
2589
                if (extentEnd < segmentOffset)  /*      No relation.    */
 
2590
                {
 
2591
                        continue;       /*      Look for later extent.  */
 
2592
                }
 
2593
 
 
2594
                /*      This extent ends at or after the start of
 
2595
                 *      this segment.  Don't search any further in
 
2596
                 *      the extents.                                    */
 
2597
 
 
2598
                if (extent.offset <= segmentOffset)
 
2599
                {
 
2600
                        /*      This extent starts before the start
 
2601
                         *      of the segment, i.e., part or all of
 
2602
                         *      this segment has already been received. */
 
2603
 
 
2604
                        bytesToSkip = extentEnd - segmentOffset;
 
2605
                        if (bytesToSkip >= bytesRemaining)
 
2606
                        {
 
2607
                                return 0;       /*      Ignore.         */
 
2608
                        }
 
2609
 
 
2610
                        /*      This segment extends this extent.       */
 
2611
 
 
2612
                        extent.length = segmentEnd - extent.offset;
 
2613
                        sdr_write(sdr, addr, (char *) &extent,
 
2614
                                        sizeof(CfdpExtent));
 
2615
#if CFDPDEBUG
 
2616
printf("Rewriting extent at %d, to %d.\n", extent.offset, extent.offset + extent.length);
 
2617
#endif
 
2618
                        extentEnd = extent.offset + extent.length;
 
2619
 
 
2620
                        /*      Skip over any repeated data at the
 
2621
                         *      start of the segment.                   */
 
2622
 
 
2623
                        segmentOffset += bytesToSkip;
 
2624
                        cursor += bytesToSkip;
 
2625
                        bytesRemaining -= bytesToSkip;
 
2626
#if CFDPDEBUG
 
2627
printf("Skipping %d bytes, segmentOffset changed to %d.\n", bytesToSkip, segmentOffset);
 
2628
#endif
 
2629
                }
 
2630
                else    /*      This segment starts a new extent.       */
 
2631
                {
 
2632
                        nextElt = elt;
 
2633
                        elt = 0;        /*      New extent needed.      */
 
2634
                }
 
2635
 
 
2636
                break;
 
2637
        }
 
2638
 
 
2639
        /*      Insert new extent if necessary.                         */
 
2640
 
 
2641
        if (elt == 0)   /*      Must write the new extent to database.  */
 
2642
        {
 
2643
                extent.offset = segmentOffset;
 
2644
                extent.length = bytesRemaining;
 
2645
                addr = sdr_malloc(sdr, sizeof (CfdpExtent));
 
2646
                if (addr == 0
 
2647
                || (elt = (nextElt == 0 ?
 
2648
                        sdr_list_insert_last(sdr, fdu->extents, addr)
 
2649
                                        :
 
2650
                        sdr_list_insert_before(sdr, nextElt, addr))) == 0)
 
2651
                {
 
2652
                        putErrmsg("Can't insert extent.", NULL);
 
2653
                        return -1;
 
2654
                }
 
2655
 
 
2656
                sdr_write(sdr, addr, (char *) &extent, sizeof(CfdpExtent));
 
2657
#if CFDPDEBUG
 
2658
printf("Writing extent from %d to %d.\n", extent.offset, extent.offset + extent.length);
 
2659
#endif
 
2660
                extentEnd = extent.offset + extent.length;
 
2661
        }
 
2662
 
 
2663
        nextElt = sdr_list_next(sdr, elt);
 
2664
 
 
2665
        /*      Open the file (possibly a temporary working file) if
 
2666
         *      it's not the currently open file.  First figure out
 
2667
         *      the file's fully-qualified name.                        */
 
2668
 
 
2669
        if (getFileName(fdu, stringBuf, sizeof stringBuf) < 0)
 
2670
        {
 
2671
                putErrmsg("Can't get file name.", NULL);
 
2672
                return -1;
 
2673
        }
 
2674
 
 
2675
        getQualifiedFileName(workingNameBuffer, sizeof workingNameBuffer,
 
2676
                        stringBuf, firstSegment);
 
2677
 
 
2678
        /*      Now open the file, creating it if necessary.            */
 
2679
 
 
2680
        if (cfdpvdb->currentFdu != fduObj)      /*      Switching FDU.  */
 
2681
        {
 
2682
                if (cfdpvdb->currentFile != -1)
 
2683
                {
 
2684
                        close(cfdpvdb->currentFile);
 
2685
                        cfdpvdb->currentFile = -1;
 
2686
                }
 
2687
 
 
2688
                cfdpvdb->currentFdu = fduObj;
 
2689
                cfdpvdb->currentFile = iopen(workingNameBuffer,
 
2690
                                O_RDWR | O_CREAT, 0777);
 
2691
                if (cfdpvdb->currentFile < 0)
 
2692
                {
 
2693
                        putSysErrmsg("Can't open working file",
 
2694
                                        workingNameBuffer);
 
2695
                        return handleFilestoreRejection(fdu, 0, &handler);
 
2696
                }
 
2697
        }
 
2698
 
 
2699
        /*      Write leading fill characters as necessary.             */
 
2700
 
 
2701
        endOfFile = lseek(cfdpvdb->currentFile, 0, SEEK_END);
 
2702
        if (endOfFile == (off_t) -1)
 
2703
        {
 
2704
                putSysErrmsg("Can't lseek in file", workingNameBuffer);
 
2705
                return handleFilestoreRejection(fdu, -1, &handler);
 
2706
        }
 
2707
 
 
2708
        fileLength = endOfFile;
 
2709
        while (fileLength < segmentOffset)
 
2710
        {
 
2711
                if (write(cfdpvdb->currentFile,
 
2712
                                &(cfdpdb.fillCharacter), 1) < 0)
 
2713
                {
 
2714
                        putSysErrmsg("Can't write to file", workingNameBuffer);
 
2715
                        return handleFilestoreRejection(fdu, -1, &handler);
 
2716
                }
 
2717
 
 
2718
                fileLength++;
 
2719
        }
 
2720
 
 
2721
        /*      Reposition at offset of new file data bytes.            */
 
2722
 
 
2723
        if (lseek(cfdpvdb->currentFile, segmentOffset, SEEK_SET) == (off_t) -1)
 
2724
        {
 
2725
                putSysErrmsg("Can't lseek in file", workingNameBuffer);
 
2726
                return handleFilestoreRejection(fdu, -1, &handler);
 
2727
        }
 
2728
 
 
2729
        /*      Now write new file data, updating checksum in the
 
2730
         *      process.  While doing this, collapse subsequent
 
2731
         *      extents into the current one until an unbridged gap
 
2732
         *      in continuity is reached.  This may entail filling
 
2733
         *      any number of inter-extent gaps.                        */
 
2734
 
 
2735
        while (nextElt)
 
2736
        {
 
2737
                nextAddr = sdr_list_data(sdr, nextElt);
 
2738
                sdr_stage(sdr, (char *) &nextExtent, nextAddr,
 
2739
                                sizeof(CfdpExtent));
 
2740
#if CFDPDEBUG
 
2741
printf("Continuing to extent from %d to %d; segmentOffset is %d.\n", nextExtent.offset, nextExtent.offset + nextExtent.length, segmentOffset);
 
2742
#endif
 
2743
                if (nextExtent.offset > segmentEnd)
 
2744
                {
 
2745
                        break;  /*      Reached an unbridged gap.       */
 
2746
                }
 
2747
 
 
2748
                /*      This extent will be subsumed into prior extent.
 
2749
                 *      First, bridge gap to the start of this extent.  */
 
2750
 
 
2751
                bytesToWrite = nextExtent.offset - segmentOffset;
 
2752
                if (writeSegmentData(fdu, &cursor, &bytesRemaining,
 
2753
                                &segmentOffset, bytesToWrite) < 0)
 
2754
                {
 
2755
                        putErrmsg("Can't write segment data.",
 
2756
                                        workingNameBuffer);
 
2757
                        return -1;
 
2758
                }
 
2759
 
 
2760
                /*      Now skip over all data that were written when
 
2761
                 *      this extent was posted.                         */
 
2762
 
 
2763
                bytesToSkip = nextExtent.length;
 
2764
                segmentOffset += bytesToSkip;
 
2765
                cursor += bytesToSkip;
 
2766
                bytesRemaining -= bytesToSkip;
 
2767
 
 
2768
                /*      Now subsume the extent into the prior extent.   */
 
2769
 
 
2770
                nextExtentEnd = nextExtent.offset + nextExtent.length;
 
2771
                if (nextExtentEnd > extentEnd)
 
2772
                {
 
2773
                        /*      Extend the prior extent.                */
 
2774
 
 
2775
                        extent.length = nextExtentEnd - extent.offset;
 
2776
                        sdr_write(sdr, addr, (char *) &extent,
 
2777
                                        sizeof(CfdpExtent));
 
2778
                        extentEnd = extent.offset + extent.length;
 
2779
                }
 
2780
 
 
2781
                elt = sdr_list_next(sdr, nextElt);
 
2782
                sdr_free(sdr, nextAddr);
 
2783
                sdr_list_delete(sdr, nextElt, NULL, NULL);
 
2784
                nextElt = elt;
 
2785
        }
 
2786
 
 
2787
        /*      Write final hunk of segment data.                       */
 
2788
 
 
2789
        if (segmentEnd > segmentOffset)
 
2790
        {
 
2791
                bytesToWrite = segmentEnd - segmentOffset;
 
2792
                if (writeSegmentData(fdu, &cursor, &bytesRemaining,
 
2793
                                &segmentOffset, bytesToWrite) < 0)
 
2794
                {
 
2795
                        putErrmsg("Can't write segment data.",
 
2796
                                        workingNameBuffer);
 
2797
                        return -1;
 
2798
                }
 
2799
        }
 
2800
 
 
2801
#ifdef TargetFFS
 
2802
        close(cfdpvdb->currentFile);
 
2803
        cfdpvdb->currentFile = -1;
 
2804
#endif
 
2805
        /*      Deliver File-Segment-Recv indication.                   */
 
2806
 
 
2807
        if (enqueueCfdpEvent(&event) < 0)
 
2808
        {
 
2809
                putErrmsg("Can't post File-Segment-Recv indication.", NULL);
 
2810
                return -1;
 
2811
        }
 
2812
 
 
2813
        sdr_write(sdr, fduObj, (char *) fdu, sizeof(InFdu));
 
2814
        return checkInFduComplete(fdu, fduObj, fduElt);
 
2815
}
 
2816
 
 
2817
static int      parseFilestoreRequestTLV(InFdu *fdu, unsigned char **cursor,
 
2818
                        int length, int *bytesRemaining)
 
2819
{
 
2820
        FilestoreRequest        req;
 
2821
        Sdr                     sdr = getIonsdr();
 
2822
        char                    firstNameBuf[256];
 
2823
        int                     firstNameLength;
 
2824
        char                    secondNameBuf[256];
 
2825
        int                     secondNameLength;
 
2826
        Object                  reqObj;
 
2827
 
 
2828
        if (length < 2)                         /*      Malformed.      */
 
2829
        {
 
2830
                *bytesRemaining = 0;            /*      End TLV loop.   */
 
2831
                return 0;                       /*      End TLV loop.   */
 
2832
        }
 
2833
 
 
2834
        req.action = (**cursor >> 4) & 0x0f;
 
2835
        (*cursor)++;
 
2836
        (*bytesRemaining)--;
 
2837
        length--;
 
2838
        firstNameLength = **cursor;
 
2839
        (*cursor)++;
 
2840
        (*bytesRemaining)--;
 
2841
        length--;
 
2842
        if (firstNameLength == 0 || firstNameLength > length)
 
2843
        {
 
2844
                *bytesRemaining = 0;            /*      End TLV loop.   */
 
2845
                return 0;
 
2846
        }
 
2847
 
 
2848
        memcpy(firstNameBuf, *cursor, firstNameLength);
 
2849
        firstNameBuf[firstNameLength] = 0;
 
2850
        *cursor += firstNameLength;
 
2851
        *bytesRemaining -= firstNameLength;
 
2852
        length -= firstNameLength;
 
2853
        if (length < 1)         /*      No length for 2nd file name.    */
 
2854
        {
 
2855
                *bytesRemaining = 0;            /*      End TLV loop.   */
 
2856
                return 0;
 
2857
        }
 
2858
 
 
2859
        secondNameLength = **cursor;
 
2860
        (*cursor)++;
 
2861
        (*bytesRemaining)--;
 
2862
        length--;
 
2863
        if (secondNameLength != length)         /*      Malformed.      */
 
2864
        {
 
2865
                *bytesRemaining = 0;            /*      End TLV loop.   */
 
2866
                return 0;
 
2867
        }
 
2868
 
 
2869
        if (secondNameLength > 0)
 
2870
        {
 
2871
                memcpy(secondNameBuf, *cursor, secondNameLength);
 
2872
                secondNameBuf[secondNameLength] = 0;
 
2873
                *cursor += secondNameLength;
 
2874
                *bytesRemaining -= secondNameLength;
 
2875
        }
 
2876
 
 
2877
        switch (req.action)
 
2878
        {
 
2879
        case CfdpCreateFile:
 
2880
        case CfdpDeleteFile:
 
2881
        case CfdpCreateDirectory:
 
2882
        case CfdpRemoveDirectory:
 
2883
        case CfdpDenyFile:
 
2884
        case CfdpDenyDirectory:
 
2885
                if (secondNameLength > 0)       /*      Invalid.        */
 
2886
                {
 
2887
                        *bytesRemaining = 0;    /*      End TLV loop.   */
 
2888
                        return 0;
 
2889
                }
 
2890
 
 
2891
                break;
 
2892
 
 
2893
        case CfdpRenameFile:
 
2894
        case CfdpAppendFile:
 
2895
        case CfdpReplaceFile:
 
2896
                if (secondNameLength == 0)      /*      Incomplete.     */
 
2897
                {
 
2898
                        *bytesRemaining = 0;    /*      End TLV loop.   */
 
2899
                        return 0;
 
2900
                }
 
2901
        }
 
2902
 
 
2903
        req.firstFileName = sdr_string_create(sdr, firstNameBuf);
 
2904
        if (req.firstFileName == 0)
 
2905
        {
 
2906
                putErrmsg("Can't retain first file name.", NULL);
 
2907
                return -1;
 
2908
        }
 
2909
 
 
2910
        if (secondNameLength == 0)
 
2911
        {
 
2912
                req.secondFileName = 0;
 
2913
        }
 
2914
        else
 
2915
        {
 
2916
                req.secondFileName = sdr_string_create(sdr, secondNameBuf);
 
2917
                if (req.secondFileName == 0)
 
2918
                {
 
2919
                        putErrmsg("Can't retain second file name.", NULL);
 
2920
                        return -1;
 
2921
                }
 
2922
        }
 
2923
 
 
2924
        reqObj = sdr_malloc(sdr, sizeof(FilestoreRequest));
 
2925
        if (reqObj == 0
 
2926
        || sdr_list_insert_last(sdr, fdu->filestoreRequests, reqObj) == 0)
 
2927
        {
 
2928
                putErrmsg("Can't add filestore request.", NULL);
 
2929
                return -1;
 
2930
        }
 
2931
 
 
2932
        sdr_write(sdr, reqObj, (char *) &req, sizeof(FilestoreRequest));
 
2933
        return 0;
 
2934
}
 
2935
 
 
2936
static int      parseMessageToUserTLV(InFdu *fdu, unsigned char **cursor,
 
2937
                        int length, int *bytesRemaining)
 
2938
{
 
2939
        MsgToUser       msg;
 
2940
        Sdr             sdr = getIonsdr();
 
2941
        Object          msgObj;
 
2942
 
 
2943
        if (length == 0)        /*      Null message.                   */
 
2944
        {
 
2945
                return 0;       /*      Nothing to do.                  */
 
2946
        }
 
2947
 
 
2948
        msg.length = length;
 
2949
        msg.text = sdr_malloc(sdr, msg.length);
 
2950
        if (msg.text)
 
2951
        {
 
2952
                sdr_write(sdr, msg.text, (char *) *cursor, msg.length);
 
2953
        }
 
2954
 
 
2955
        msgObj = sdr_malloc(sdr, sizeof(MsgToUser));
 
2956
        if (msgObj == 0
 
2957
        || sdr_list_insert_last(sdr, fdu->messagesToUser, msgObj) == 0)
 
2958
        {
 
2959
                putErrmsg("Can't add message to user.", NULL);
 
2960
                return -1;
 
2961
        }
 
2962
 
 
2963
        sdr_write(sdr, msgObj, (char *) &msg, sizeof(MsgToUser));
 
2964
        *cursor += msg.length;
 
2965
        *bytesRemaining -= msg.length;
 
2966
        return 0;
 
2967
}
 
2968
 
 
2969
static int      parseFaultHandlerTLV(InFdu *fdu, unsigned char **cursor,
 
2970
                        int length, int *bytesRemaining)
 
2971
{
 
2972
        unsigned int    override;
 
2973
        CfdpCondition   condition;
 
2974
        CfdpHandler     handler;
 
2975
 
 
2976
        if (length != 1)                        /*      Incomplete.     */
 
2977
        {
 
2978
                *bytesRemaining = 0;            /*      End TLV loop.   */
 
2979
                return 0;
 
2980
        }
 
2981
 
 
2982
        override = **cursor;
 
2983
        condition = (override >> 4) & 0x0f;
 
2984
        handler = override & 0x0f;
 
2985
        switch (handler)
 
2986
        {
 
2987
        case CfdpNoHandler:
 
2988
        case CfdpCancel:
 
2989
        case CfdpSuspend:
 
2990
        case CfdpIgnore:
 
2991
        case CfdpAbandon:
 
2992
                break;
 
2993
 
 
2994
        default:                                /*      Invalid.        */
 
2995
                *bytesRemaining = 0;            /*      End TLV loop.   */
 
2996
                return 0;
 
2997
        }
 
2998
 
 
2999
        fdu->faultHandlers[condition] = handler;
 
3000
        *cursor += length;
 
3001
        *bytesRemaining -= length;
 
3002
        return 0;
 
3003
}
 
3004
 
 
3005
static int      parseFlowLabelTLV(InFdu *fdu, unsigned char **cursor,
 
3006
                        int length, int *bytesRemaining)
 
3007
{
 
3008
        Sdr     sdr = getIonsdr();
 
3009
 
 
3010
        if (length == 0)        /*      Null flow label.                */
 
3011
        {
 
3012
                return 0;       /*      Nothing to do.                  */
 
3013
        }
 
3014
 
 
3015
        if (fdu->flowLabel)
 
3016
        {
 
3017
                sdr_free(sdr, fdu->flowLabel);
 
3018
        }
 
3019
 
 
3020
        fdu->flowLabel = sdr_malloc(sdr, length);
 
3021
        if (fdu->flowLabel == 0)
 
3022
        {
 
3023
                putErrmsg("Can't retain flow label.", NULL);
 
3024
                return -1;
 
3025
        }
 
3026
 
 
3027
        sdr_write(sdr, fdu->flowLabel, (char *) *cursor, length);
 
3028
        fdu->flowLabelLength = length;
 
3029
        *cursor += length;
 
3030
        *bytesRemaining -= length;
 
3031
        return 0;
 
3032
}
 
3033
 
 
3034
static int      parseEntityIdTLV(InFdu *fdu, unsigned char **cursor,
 
3035
                        int length, int *bytesRemaining)
 
3036
{
 
3037
        if (length > 8)         /*      Invalid fault location.         */
 
3038
        {
 
3039
                return 0;       /*      Malformed.                      */
 
3040
        }
 
3041
 
 
3042
        fdu->eofFaultLocation.length = length;
 
3043
        memcpy(fdu->eofFaultLocation.buffer, cursor, length);
 
3044
        *cursor += length;
 
3045
        *bytesRemaining -= length;
 
3046
        return 0;
 
3047
}
 
3048
 
 
3049
static int      parseTLV(InFdu *fdu, unsigned char **cursor,
 
3050
                        int *bytesRemaining, int directiveCode)
 
3051
{
 
3052
        int     type;
 
3053
        int     length;
 
3054
 
 
3055
        if (*bytesRemaining < 2)                /*      Malformed.      */
 
3056
        {
 
3057
                *bytesRemaining = 0;            /*      End TLV loop.   */
 
3058
                return 0;
 
3059
        }
 
3060
 
 
3061
        type = **cursor;
 
3062
        length = *(*cursor + 1);
 
3063
        *cursor += 2;
 
3064
        *bytesRemaining -= 2;
 
3065
        if (*bytesRemaining < length)           /*      Malformed.      */
 
3066
        {
 
3067
                *bytesRemaining = 0;            /*      End TLV loop.   */
 
3068
                return 0;
 
3069
        }
 
3070
 
 
3071
        if (directiveCode == 4)                 /*      EOF PDU.        */
 
3072
        {
 
3073
                if (type == 6)
 
3074
                {
 
3075
                        return parseEntityIdTLV(fdu, cursor, length,
 
3076
                                        bytesRemaining);
 
3077
                }
 
3078
 
 
3079
                /*      Invalid.  No other TLV is valid for EOF.        */
 
3080
 
 
3081
                return 0;
 
3082
        }
 
3083
 
 
3084
        /*      Directive code must be 7, Metadata PDU.                 */
 
3085
 
 
3086
        switch (type)
 
3087
        {
 
3088
        case 0:
 
3089
                return parseFilestoreRequestTLV(fdu, cursor, length,
 
3090
                                bytesRemaining);
 
3091
 
 
3092
        case 2:
 
3093
                return parseMessageToUserTLV(fdu, cursor, length,
 
3094
                                bytesRemaining);
 
3095
 
 
3096
        case 4:
 
3097
                return parseFaultHandlerTLV(fdu, cursor, length,
 
3098
                                bytesRemaining);
 
3099
 
 
3100
        case 5:
 
3101
                return parseFlowLabelTLV(fdu, cursor, length,
 
3102
                                bytesRemaining);
 
3103
 
 
3104
        default:                                /*      Invalid.        */
 
3105
                *bytesRemaining = 0;            /*      End TLV loop.   */
 
3106
                return 0;
 
3107
        }
 
3108
}
 
3109
 
 
3110
static int      handleEofPdu(unsigned char *cursor, int bytesRemaining,
 
3111
                        int dataFieldLength, InFdu *fdu, Object fduObj,
 
3112
                        Object fduElt)
 
3113
{
 
3114
        int             i;
 
3115
        CfdpHandler     handler;
 
3116
        CfdpEvent       event;
 
3117
        Sdr             sdr = getIonsdr();
 
3118
        CfdpDB          cfdpdb;
 
3119
 
 
3120
        if (fdu->eofReceived)
 
3121
        {
 
3122
                return 0;       /*      Ignore redundant EOF.           */
 
3123
        }
 
3124
 
 
3125
        if (bytesRemaining < 9) return 0;       /*      Malformed.      */
 
3126
        sdr_read(sdr, (char *) &cfdpdb, getCfdpDbObject(), sizeof(CfdpDB));
 
3127
        fdu->inactivityDeadline += cfdpdb.transactionInactivityLimit;
 
3128
        fdu->eofReceived = 1;
 
3129
        fdu->eofCondition = (*cursor >> 4) & 0x0f;
 
3130
        cursor++;
 
3131
        bytesRemaining--;
 
3132
        for (i = 0; i < 4; i++)
 
3133
        {
 
3134
                fdu->eofChecksum = (fdu->eofChecksum << 8) + *cursor;
 
3135
                cursor++;
 
3136
                bytesRemaining--;
 
3137
        }
 
3138
 
 
3139
        for (i = 0; i < 4; i++)
 
3140
        {
 
3141
                fdu->fileSize = (fdu->fileSize << 8) + *cursor;
 
3142
                cursor++;
 
3143
                bytesRemaining--;
 
3144
        }
 
3145
 
 
3146
        if (bytesRemaining > 0)
 
3147
        {
 
3148
                if (fdu->eofCondition == CfdpNoError)
 
3149
                {
 
3150
                        return 0;               /*      Malformed.      */
 
3151
                }
 
3152
 
 
3153
                if (parseTLV(fdu, &cursor, &bytesRemaining, 4) < 0)
 
3154
                {
 
3155
                        putErrmsg("Failed parsing TLV.", NULL);
 
3156
                        return -1;
 
3157
                }
 
3158
 
 
3159
                if (bytesRemaining > 0)         /*      Extra bytes.    */
 
3160
                {
 
3161
                        return 0;               /*      Malformed.      */
 
3162
                }
 
3163
        }
 
3164
 
 
3165
        /*      Check for file size error.                              */
 
3166
 
 
3167
        if (fdu->progress > fdu->fileSize)
 
3168
        {
 
3169
                if (handleFault(&fdu->transactionId, CfdpFileSizeError,
 
3170
                                &handler) < 0)
 
3171
                {
 
3172
                        putErrmsg("Can't handle EOF PDU.", NULL);
 
3173
                        return -1;
 
3174
                }
 
3175
 
 
3176
                switch (handler)
 
3177
                {
 
3178
                case CfdpCancel:
 
3179
                case CfdpAbandon:
 
3180
                        return 0;               /*      Nothing to do.  */
 
3181
 
 
3182
                default:
 
3183
                        break;                  /*      No problem.     */
 
3184
                }
 
3185
        }
 
3186
 
 
3187
        /*      Deliver EOF-Recv indication.                            */
 
3188
 
 
3189
        memset((char *) &event, 0, sizeof(CfdpEvent));
 
3190
        event.type = CfdpEofRecvInd;
 
3191
        event.fileSize = fdu->fileSize;
 
3192
        memcpy((char *) &event.transactionId, (char *) &fdu->transactionId,
 
3193
                        sizeof(CfdpTransactionId));
 
3194
        if (enqueueCfdpEvent(&event) < 0)
 
3195
        {
 
3196
                putErrmsg("Can't post EOF-Recv indication.", NULL);
 
3197
                return -1;
 
3198
        }
 
3199
 
 
3200
        fdu->checkTime = getUTCTime();
 
3201
        fdu->checkTime += cfdpdb.checkTimerPeriod;
 
3202
        sdr_write(sdr, fduObj, (char *) fdu, sizeof(InFdu));
 
3203
        return checkInFduComplete(fdu, fduObj, fduElt);
 
3204
}
 
3205
 
 
3206
static int      handleMetadataPdu(unsigned char *cursor, int bytesRemaining,
 
3207
                        int dataFieldLength, InFdu *fdu, Object fduObj,
 
3208
                        Object fduElt)
 
3209
{
 
3210
        CfdpDB          cfdpdb;
 
3211
        int             i;
 
3212
        unsigned int    fileSize = 0;           /*      Ignore it.      */
 
3213
        char            stringBuf[256];
 
3214
        Sdr             sdr = getIonsdr();
 
3215
        CfdpEvent       event;
 
3216
        CfdpHandler     handler;
 
3217
 
 
3218
        if (fdu->metadataReceived)
 
3219
        {
 
3220
                return 0;       /*      Ignore redundant metadata.      */
 
3221
        }
 
3222
 
 
3223
        if (bytesRemaining < 5) return 0;       /*      Malformed.      */
 
3224
        sdr_read(sdr, (char *) &cfdpdb, getCfdpDbObject(), sizeof(CfdpDB));
 
3225
        fdu->inactivityDeadline += cfdpdb.transactionInactivityLimit;
 
3226
        fdu->metadataReceived = 1;
 
3227
        fdu->recordBoundsRespected = (*cursor >> 7) & 0x01;
 
3228
        cursor++;
 
3229
        bytesRemaining--;
 
3230
        for (i = 0; i < 4; i++) /*      Get projected file size.        */
 
3231
        {
 
3232
                fileSize = (fileSize << 8) + *cursor;
 
3233
                cursor++;
 
3234
                bytesRemaining--;
 
3235
        }
 
3236
 
 
3237
        /*      Parse source file name LV.                              */
 
3238
 
 
3239
        if (bytesRemaining < 1) return 0;       /*      Malformed.      */
 
3240
        i = *cursor;
 
3241
        cursor++;
 
3242
        bytesRemaining--;
 
3243
        if (bytesRemaining < i) return 0;       /*      Malformed.      */
 
3244
        if (i > 0)
 
3245
        {
 
3246
                memcpy(stringBuf, cursor, i);
 
3247
                cursor += i;
 
3248
                bytesRemaining -= i;
 
3249
                stringBuf[i] = 0;
 
3250
                fdu->sourceFileName = sdr_string_create(sdr, stringBuf);
 
3251
                if (fdu->sourceFileName == 0)
 
3252
                {
 
3253
                        putErrmsg("Can't retain source file name.", stringBuf);
 
3254
                        return -1;
 
3255
                }
 
3256
        }
 
3257
 
 
3258
        /*      Parse destination file name LV.                         */
 
3259
 
 
3260
        if (bytesRemaining < 1) return 0;       /*      Malformed.      */
 
3261
        i = *cursor;
 
3262
        cursor++;
 
3263
        bytesRemaining--;
 
3264
        if (bytesRemaining < i) return 0;       /*      Malformed.      */
 
3265
        if (i > 0)
 
3266
        {
 
3267
                memcpy(stringBuf, cursor, i);
 
3268
                cursor += i;
 
3269
                bytesRemaining -= i;
 
3270
                stringBuf[i] = 0;
 
3271
                fdu->destFileName = sdr_string_create(sdr, stringBuf);
 
3272
                if (fdu->destFileName == 0)
 
3273
                {
 
3274
                        putErrmsg("Can't retain dest file name.", stringBuf);
 
3275
                        return -1;
 
3276
                }
 
3277
 
 
3278
                if (fdu->workingFileName == 0)
 
3279
                {
 
3280
                        fdu->workingFileName = fdu->destFileName;
 
3281
                }
 
3282
 
 
3283
                if (fdu->sourceFileName == 0)
 
3284
                {
 
3285
                        /*      Compressed: use destination file name.  */
 
3286
 
 
3287
                        fdu->sourceFileName = sdr_string_create(sdr,
 
3288
                                        stringBuf);
 
3289
                        if (fdu->sourceFileName == 0)
 
3290
                        {
 
3291
                                putErrmsg("Can't retain source file name.",
 
3292
                                                stringBuf);
 
3293
                                return -1;
 
3294
                        }
 
3295
                }
 
3296
        }
 
3297
 
 
3298
        /*      Parse TLVs.  If at any point a TLV is found to be
 
3299
         *      malformed, parsing of the Metadata PDU terminates
 
3300
         *      but processing continues.                               */
 
3301
 
 
3302
        while (bytesRemaining > 0)
 
3303
        {
 
3304
                if (parseTLV(fdu, &cursor, &bytesRemaining, 7) < 0)
 
3305
                {
 
3306
                        putErrmsg("Failed parsing TLVs.", NULL);
 
3307
                        return -1;
 
3308
                }
 
3309
        }
 
3310
 
 
3311
        /*      Deliver Metadata-Recv indication.                       */
 
3312
 
 
3313
        memset((char *) &event, 0, sizeof(CfdpEvent));
 
3314
        event.type = CfdpMetadataRecvInd;
 
3315
        memcpy((char *) &event.transactionId, (char *) &fdu->transactionId,
 
3316
                        sizeof(CfdpTransactionId));
 
3317
        if (fdu->sourceFileName)
 
3318
        {
 
3319
                sdr_string_read(sdr, stringBuf, fdu->sourceFileName);
 
3320
                event.sourceFileName = sdr_string_create(sdr, stringBuf);
 
3321
        }
 
3322
 
 
3323
        if (fdu->destFileName)
 
3324
        {
 
3325
                sdr_string_read(sdr, stringBuf, fdu->destFileName);
 
3326
                event.destFileName = sdr_string_create(sdr, stringBuf);
 
3327
        }
 
3328
 
 
3329
        event.fileSize = fileSize;      /*      Projected, not actual.  */
 
3330
        event.messagesToUser = fdu->messagesToUser;
 
3331
        fdu->messagesToUser = 0;
 
3332
        if (enqueueCfdpEvent(&event) < 0)
 
3333
        {
 
3334
                putErrmsg("Can't post Metadata-Recv indication.", NULL);
 
3335
                return -1;
 
3336
        }
 
3337
 
 
3338
        sdr_write(sdr, fduObj, (char *) fdu, sizeof(InFdu));
 
3339
 
 
3340
        /*      Metadata PDU has been fully processed.  Now follow up.  */
 
3341
 
 
3342
        if (fdu->destFileName)
 
3343
        {
 
3344
                sdr_string_read(sdr, stringBuf, fdu->destFileName);
 
3345
                if (checkFile(stringBuf) == 1)
 
3346
                {
 
3347
                        /*      This file already exists.               */
 
3348
 
 
3349
                        writeMemoNote("[?] File already exists.", stringBuf);
 
3350
                        if (handleFilestoreRejection(fdu, 0, &handler) < 0)
 
3351
                        {
 
3352
                                return -1;
 
3353
                        }
 
3354
 
 
3355
                        switch (handler)
 
3356
                        {
 
3357
                        case CfdpCancel:
 
3358
                        case CfdpAbandon:
 
3359
                                return 0;       /*      Nothing to do.  */
 
3360
 
 
3361
                        default:
 
3362
                                break;          /*      No problem.     */
 
3363
                        }
 
3364
                }
 
3365
        }
 
3366
 
 
3367
        return checkInFduComplete(fdu, fduObj, fduElt);
 
3368
}
 
3369
 
 
3370
int     cfdpHandleInboundPdu(unsigned char *buf, int length)
 
3371
{
 
3372
        unsigned char           *cursor = buf;
 
3373
        int                     bytesRemaining = length;
 
3374
        int                     pduIsFileData;
 
3375
        int                     modeIsUnacknowledged;
 
3376
        Sdr                     sdr = getIonsdr();
 
3377
        CfdpDB                  *cfdpConstants = _cfdpConstants();
 
3378
        CfdpVdb                 *cfdpvdb = _cfdpvdb(NULL);
 
3379
        int                     crcIsPresent;
 
3380
        int                     dataFieldLength;
 
3381
        int                     entityNbrLength;
 
3382
        int                     transactionNbrLength;
 
3383
        CfdpNumber              sourceEntityNbr;
 
3384
        CfdpNumber              transactionNbr;
 
3385
        CfdpNumber              destinationEntityNbr;
 
3386
        unsigned short          deliveredCRC;
 
3387
        unsigned short          computedCRC;
 
3388
        CfdpTransactionId       transactionId;
 
3389
        CfdpHandler             handler;
 
3390
        Object                  fduObj;
 
3391
        InFdu                   fduBuf;
 
3392
        Object                  fduElt;
 
3393
        int                     directiveCode;
 
3394
        int                     result;
 
3395
 
 
3396
#if CFDPDEBUG
 
3397
printf("...in cfdpHandleInboundPdu...\n"); 
 
3398
#endif
 
3399
        CHKERR(buf);
 
3400
        memset((char *) &sourceEntityNbr, 0, sizeof(CfdpNumber));
 
3401
        memset((char *) &transactionNbr, 0, sizeof(CfdpNumber));
 
3402
        memset((char *) &destinationEntityNbr, 0, sizeof(CfdpNumber));
 
3403
 
 
3404
        /*      Parse PDU header.                                       */
 
3405
 
 
3406
        if (bytesRemaining < 4)
 
3407
        {
 
3408
                return 0;               /*      Malformed PDU.          */
 
3409
        }
 
3410
 
 
3411
        pduIsFileData = ((*cursor) >> 4) & 0x01;
 
3412
        modeIsUnacknowledged = ((*cursor) >> 2) & 0x01;
 
3413
        crcIsPresent = ((*cursor) >> 1) & 0x01;
 
3414
        cursor++;
 
3415
        bytesRemaining--;
 
3416
        dataFieldLength = *cursor << 8;
 
3417
        cursor++;
 
3418
        bytesRemaining--;
 
3419
        dataFieldLength += *cursor;
 
3420
        cursor++;
 
3421
        bytesRemaining--;
 
3422
        entityNbrLength = ((*cursor) >> 4) & 0x07;
 
3423
        transactionNbrLength = *cursor & 0x07;
 
3424
        cursor++;
 
3425
        bytesRemaining--;
 
3426
        entityNbrLength += 1;           /*      De-adjust.              */
 
3427
        transactionNbrLength += 1;      /*      De-adjust.              */
 
3428
        if (bytesRemaining < (entityNbrLength << 1) + transactionNbrLength)
 
3429
        {
 
3430
#if CFDPDEBUG
 
3431
printf("...malformed PDU (missing %d bytes)...\n",
 
3432
((entityNbrLength << 1) + transactionNbrLength) - bytesRemaining); 
 
3433
#endif
 
3434
                return 0;               /*      Malformed PDU.          */
 
3435
        }
 
3436
 
 
3437
        sourceEntityNbr.length = entityNbrLength;
 
3438
        memcpy(sourceEntityNbr.buffer, cursor, entityNbrLength);
 
3439
        cursor += entityNbrLength;
 
3440
        bytesRemaining -= entityNbrLength;
 
3441
        transactionNbr.length = transactionNbrLength;
 
3442
        memcpy(transactionNbr.buffer, cursor, transactionNbrLength);
 
3443
        cursor += transactionNbrLength;
 
3444
        bytesRemaining -= transactionNbrLength;
 
3445
        destinationEntityNbr.length = entityNbrLength;
 
3446
        memcpy(destinationEntityNbr.buffer, cursor, entityNbrLength);
 
3447
        cursor += entityNbrLength;
 
3448
        bytesRemaining -= entityNbrLength;
 
3449
#if CFDPDEBUG
 
3450
printf("...parsed the PDU...\n"); 
 
3451
#endif
 
3452
 
 
3453
        /*      Check CRC if necessary.                                 */
 
3454
 
 
3455
        if (crcIsPresent)
 
3456
        {
 
3457
#if CFDPDEBUG
 
3458
printf("...computing CRC...\n"); 
 
3459
#endif
 
3460
                if (bytesRemaining < 2)
 
3461
                {
 
3462
                        return 0;       /*      Malformed PDU.          */
 
3463
                }
 
3464
 
 
3465
                /*      Omit CRC from PDU processing.                   */
 
3466
 
 
3467
                bytesRemaining -= 2;
 
3468
                length -= 2;
 
3469
 
 
3470
                /*      Check the CRC.                                  */
 
3471
 
 
3472
                memcpy((char *) &deliveredCRC, buf + length, 2);
 
3473
                deliveredCRC = ntohs(deliveredCRC);
 
3474
                computedCRC = computeCRC(buf, length);
 
3475
                if (computedCRC != deliveredCRC)
 
3476
                {
 
3477
#if CFDPDEBUG
 
3478
printf("...CRC validation failed...\n"); 
 
3479
#endif
 
3480
                        return 0;       /*      Corrupted PDU.          */
 
3481
                }
 
3482
        }
 
3483
 
 
3484
        /*      PDU is known not to be corrupt, so process it.          */
 
3485
 
 
3486
#if CFDPDEBUG
 
3487
printf("...PDU known not to be corrupt...\n"); 
 
3488
#endif
 
3489
        if (memcmp((char *) &destinationEntityNbr,
 
3490
                        (char *) &cfdpConstants->ownEntityNbr,
 
3491
                        sizeof(CfdpNumber)) != 0)
 
3492
        {
 
3493
#if CFDPDEBUG
 
3494
printf("...PDU is misdirected...\n"); 
 
3495
#endif
 
3496
                return 0;               /*      Misdirected PDU.        */
 
3497
        }
 
3498
 
 
3499
        if (cfdpvdb->watching & WATCH_q)
 
3500
        {
 
3501
                putchar('q');
 
3502
                fflush(stdout);
 
3503
        }
 
3504
 
 
3505
        memcpy((char *) &transactionId.sourceEntityNbr,
 
3506
                        (char *) &sourceEntityNbr, sizeof(CfdpNumber));
 
3507
        memcpy((char *) &transactionId.transactionNbr,
 
3508
                        (char *) &transactionNbr, sizeof(CfdpNumber));
 
3509
        if (modeIsUnacknowledged == 0)  /*      Unusable PDU.           */
 
3510
        {
 
3511
#if CFDPDEBUG
 
3512
printf("...wrong CFDP transmission mode...\n"); 
 
3513
#endif
 
3514
                return handleFault(&transactionId,
 
3515
                                CfdpInvalidTransmissionMode, &handler);
 
3516
        }
 
3517
 
 
3518
        /*      Get FDU, creating as necessary.                         */
 
3519
 
 
3520
        sdr_begin_xn(sdr);
 
3521
        fduObj = findInFdu(&transactionId, &fduBuf, &fduElt, 1);
 
3522
        if (fduObj == 0)
 
3523
        {
 
3524
                sdr_cancel_xn(sdr);
 
3525
                putErrmsg("Can't create new inbound FDU.", NULL);
 
3526
                return -1;
 
3527
        }
 
3528
 
 
3529
        if (fduBuf.state == FduCanceled)
 
3530
        {
 
3531
                return sdr_end_xn(sdr); /*      Useless PDU.            */
 
3532
        }
 
3533
 
 
3534
        if (pduIsFileData)
 
3535
        {
 
3536
                result = handleFileDataPdu(cursor, bytesRemaining,
 
3537
                                dataFieldLength, &fduBuf, fduObj, fduElt);
 
3538
                if (result < 0)
 
3539
                {
 
3540
                        putErrmsg("UTI can't handle file data PDU.", NULL);
 
3541
                        sdr_cancel_xn(sdr);
 
3542
                        return -1;
 
3543
                }
 
3544
 
 
3545
                return sdr_end_xn(sdr);
 
3546
        }
 
3547
 
 
3548
        if (bytesRemaining < 1)
 
3549
        {
 
3550
                return sdr_end_xn(sdr); /*      Malformed PDU.          */
 
3551
        }
 
3552
 
 
3553
        directiveCode = *cursor;
 
3554
        cursor++;
 
3555
        bytesRemaining--;
 
3556
        switch (directiveCode)
 
3557
        {
 
3558
        case 4:                         /*      EOF PDU.                */
 
3559
                result = handleEofPdu(cursor, bytesRemaining,
 
3560
                                dataFieldLength, &fduBuf, fduObj, fduElt);
 
3561
                break;
 
3562
 
 
3563
        case 7:                         /*      Metadata PDU.           */
 
3564
                result = handleMetadataPdu(cursor, bytesRemaining,
 
3565
                                dataFieldLength, &fduBuf, fduObj, fduElt);
 
3566
                break;
 
3567
 
 
3568
        default:                        /*      Invalid PDU for unack.  */
 
3569
                return sdr_end_xn(sdr);
 
3570
        }
 
3571
 
 
3572
        if (result < 0)
 
3573
        {
 
3574
                putErrmsg("UTI can't handle file directive PDU.", NULL);
 
3575
                sdr_cancel_xn(sdr);
 
3576
                return -1;
 
3577
        }
 
3578
 
 
3579
        return sdr_end_xn(sdr);
 
3580
}