Files @ c4f66bfa3890
Branch filter:

Location: DistRen/src/server/distrend.c - annotation

binki
frame_watchdog(): fix linked list access
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
a9cef84324c3
86e255a6e35e
a9cef84324c3
a9cef84324c3
a9cef84324c3
a9cef84324c3
a9cef84324c3
a9cef84324c3
a9cef84324c3
a9cef84324c3
a9cef84324c3
a9cef84324c3
a9cef84324c3
a9cef84324c3
a9cef84324c3
a9cef84324c3
a9cef84324c3
a9cef84324c3
a9cef84324c3
a9cef84324c3
a9cef84324c3
a9cef84324c3
a9cef84324c3
a9cef84324c3
12f4253fa8db
bd3a8baa47b6
45bf3be8fb93
1b8c96d2c943
fea8bac851bf
a9cef84324c3
83227db1cee8
49a8e39f40db
83227db1cee8
1a7ea8a134dd
4511fa3bd768
14f43a497bd7
dd9e5549c8a7
a9cef84324c3
13cbfa232eaf
9a81eb0cca5d
9a81eb0cca5d
9a81eb0cca5d
9a81eb0cca5d
13cbfa232eaf
9a81eb0cca5d
4fa20a1a4a19
52bf06710be2
754555c90530
52bf06710be2
52bf06710be2
52bf06710be2
52bf06710be2
52bf06710be2
7c67ae7c57ca
b0180c74a54c
52bf06710be2
a6a648e19f34
f3074254062c
f3074254062c
f3074254062c
f3074254062c
f3074254062c
0cbd80119355
d7b349e0d490
f44df7a5711b
c22ed9637b22
13f3a450ac0c
8b67a70070ef
82e46a3537bb
355de37ac5f1
73285a55be12
11f9a3f8299d
12f4253fa8db
02159cabda3c
66a0bab210f1
4fa20a1a4a19
355de37ac5f1
977179850e7e
977179850e7e
977179850e7e
977179850e7e
977179850e7e
4fa20a1a4a19
4fa20a1a4a19
de2583236e8e
de2583236e8e
de2583236e8e
de2583236e8e
de2583236e8e
a22d893df17e
a22d893df17e
a22d893df17e
a22d893df17e
a22d893df17e
a22d893df17e
477c564bf47e
a22d893df17e
a22d893df17e
a22d893df17e
a22d893df17e
a22d893df17e
f3074254062c
a22d893df17e
a22d893df17e
f3074254062c
a22d893df17e
a22d893df17e
a22d893df17e
f3074254062c
a22d893df17e
a22d893df17e
a22d893df17e
a22d893df17e
a22d893df17e
a22d893df17e
477c564bf47e
477c564bf47e
a22d893df17e
f3074254062c
a22d893df17e
a22d893df17e
a22d893df17e
477c564bf47e
477c564bf47e
a22d893df17e
a22d893df17e
a22d893df17e
a22d893df17e
a22d893df17e
477c564bf47e
477c564bf47e
14f43a497bd7
2649adfbf346
3dde26c84524
3dde26c84524
d7b349e0d490
14f43a497bd7
14f43a497bd7
de2583236e8e
de2583236e8e
de2583236e8e
754555c90530
754555c90530
f3074254062c
f3074254062c
f3074254062c
f3074254062c
5aed1b4859a6
754555c90530
f3074254062c
b0463de161bd
b0463de161bd
c72229e67266
3dde26c84524
3dde26c84524
2a5a620b64ea
25ea5b51c17a
5a4b1484f2ba
73e1c0d6e315
25d211484bef
66a0bab210f1
66a0bab210f1
66a0bab210f1
66a0bab210f1
66a0bab210f1
4fa20a1a4a19
4fa20a1a4a19
355de37ac5f1
3dde26c84524
3dde26c84524
66a0bab210f1
66a0bab210f1
50ff9ed2fc39
66a0bab210f1
66a0bab210f1
66a0bab210f1
66a0bab210f1
66a0bab210f1
50ff9ed2fc39
40f982ba351a
66a0bab210f1
2a5a620b64ea
66a0bab210f1
66a0bab210f1
66a0bab210f1
66a0bab210f1
66a0bab210f1
0072103d825f
66a0bab210f1
73285a55be12
bed606577946
73e1c0d6e315
66a0bab210f1
0072103d825f
0072103d825f
0072103d825f
66a0bab210f1
7fa6b34e407e
486997cdeade
486997cdeade
486997cdeade
486997cdeade
486997cdeade
486997cdeade
486997cdeade
486997cdeade
486997cdeade
486997cdeade
486997cdeade
486997cdeade
486997cdeade
486997cdeade
486997cdeade
486997cdeade
486997cdeade
486997cdeade
486997cdeade
486997cdeade
486997cdeade
486997cdeade
486997cdeade
486997cdeade
486997cdeade
486997cdeade
355de37ac5f1
734207e4d1f8
e735102fe86c
e735102fe86c
e735102fe86c
8ef16b5f6624
7fa6b34e407e
d34baf50c1b1
e735102fe86c
13533b1094bd
0cbd80119355
0cbd80119355
0cbd80119355
0cbd80119355
734207e4d1f8
734207e4d1f8
7fa6b34e407e
7fa6b34e407e
7fa6b34e407e
e735102fe86c
11f9a3f8299d
7fa6b34e407e
2a5a620b64ea
7fa6b34e407e
7fa6b34e407e
7fa6b34e407e
7fa6b34e407e
d34baf50c1b1
02159cabda3c
7fa6b34e407e
7fa6b34e407e
0cbd80119355
4fa20a1a4a19
4fa20a1a4a19
355de37ac5f1
02159cabda3c
7fa6b34e407e
7fa6b34e407e
b00c1848c39d
7fa6b34e407e
ecb6efb70fb1
7fa6b34e407e
7fa6b34e407e
7fa6b34e407e
7fa6b34e407e
ecb6efb70fb1
8ef16b5f6624
8ef16b5f6624
7fa6b34e407e
7fa6b34e407e
bbc92828afdd
bbc92828afdd
5bee5e566377
bbc92828afdd
bbc92828afdd
355de37ac5f1
633e938f261d
73285a55be12
5bee5e566377
633e938f261d
633e938f261d
633e938f261d
2a5a620b64ea
2a5a620b64ea
02159cabda3c
355de37ac5f1
633e938f261d
633e938f261d
633e938f261d
633e938f261d
633e938f261d
633e938f261d
633e938f261d
633e938f261d
633e938f261d
633e938f261d
633e938f261d
633e938f261d
633e938f261d
633e938f261d
633e938f261d
bbc92828afdd
bbc92828afdd
1f986f0a72d1
355de37ac5f1
355de37ac5f1
355de37ac5f1
1f986f0a72d1
1f986f0a72d1
2a5a620b64ea
1f986f0a72d1
d7b349e0d490
d7b349e0d490
d7b349e0d490
093a01362862
0f74d7c8d753
1f986f0a72d1
c88f2cae0705
12f4253fa8db
c88f2cae0705
0f74d7c8d753
1f986f0a72d1
0f74d7c8d753
d7b349e0d490
6bad006318e5
6bad006318e5
2a5a620b64ea
2a5a620b64ea
2a5a620b64ea
2a5a620b64ea
2a5a620b64ea
2a5a620b64ea
6bad006318e5
2a5a620b64ea
2a5a620b64ea
2a5a620b64ea
0f74d7c8d753
2a5a620b64ea
093a01362862
2a5a620b64ea
0f74d7c8d753
5a4b1484f2ba
2a5a620b64ea
2a5a620b64ea
c88f2cae0705
1f986f0a72d1
b00c1848c39d
b00c1848c39d
355de37ac5f1
3dde26c84524
6b468a948714
12f4253fa8db
6b468a948714
4fa20a1a4a19
c4f66bfa3890
00f305617cde
5a6af7ed2d6f
00f305617cde
00f305617cde
c4f66bfa3890
00f305617cde
c4f66bfa3890
3dde26c84524
00f305617cde
00f305617cde
00f305617cde
00f305617cde
2a5a620b64ea
5a6af7ed2d6f
4fa20a1a4a19
9a584f11d162
12f4253fa8db
82e46a3537bb
82e46a3537bb
82e46a3537bb
12f4253fa8db
82e46a3537bb
12f4253fa8db
c88f2cae0705
82e46a3537bb
12f4253fa8db
82e46a3537bb
12f4253fa8db
12f4253fa8db
12f4253fa8db
12f4253fa8db
c88f2cae0705
12f4253fa8db
82e46a3537bb
82e46a3537bb
82e46a3537bb
82e46a3537bb
c5636f3bd7d4
9a584f11d162
c5636f3bd7d4
9a584f11d162
73285a55be12
9a584f11d162
12f4253fa8db
c88f2cae0705
73285a55be12
73285a55be12
73285a55be12
73285a55be12
73285a55be12
c88f2cae0705
73285a55be12
73285a55be12
73285a55be12
73285a55be12
c88f2cae0705
73e1c0d6e315
9a584f11d162
9a584f11d162
4fa20a1a4a19
754555c90530
7c67ae7c57ca
7c67ae7c57ca
7c67ae7c57ca
7c67ae7c57ca
7c67ae7c57ca
7c67ae7c57ca
7c67ae7c57ca
7c67ae7c57ca
7c67ae7c57ca
7c67ae7c57ca
7c67ae7c57ca
7c67ae7c57ca
f3074254062c
f3074254062c
7c67ae7c57ca
7c67ae7c57ca
7c67ae7c57ca
f3074254062c
12f4253fa8db
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
5aed1b4859a6
754555c90530
45bf3be8fb93
45bf3be8fb93
7c67ae7c57ca
21c31a64b0b3
7c67ae7c57ca
7c67ae7c57ca
f3074254062c
7c67ae7c57ca
21c31a64b0b3
f3074254062c
f3074254062c
45bf3be8fb93
7c67ae7c57ca
7c67ae7c57ca
7c67ae7c57ca
7c67ae7c57ca
7c67ae7c57ca
7c67ae7c57ca
f3074254062c
7c67ae7c57ca
7c67ae7c57ca
9a81eb0cca5d
734207e4d1f8
734207e4d1f8
734207e4d1f8
9a81eb0cca5d
9a81eb0cca5d
734207e4d1f8
9a81eb0cca5d
5a096921e9e8
9a81eb0cca5d
5a096921e9e8
5a096921e9e8
9a81eb0cca5d
9a81eb0cca5d
9a81eb0cca5d
9a81eb0cca5d
9a81eb0cca5d
9a81eb0cca5d
5a096921e9e8
5a096921e9e8
9a81eb0cca5d
9a81eb0cca5d
9a81eb0cca5d
734207e4d1f8
734207e4d1f8
734207e4d1f8
734207e4d1f8
9a81eb0cca5d
9a81eb0cca5d
9a81eb0cca5d
9a81eb0cca5d
9a81eb0cca5d
9a81eb0cca5d
9a81eb0cca5d
9a81eb0cca5d
9a81eb0cca5d
9a81eb0cca5d
9a81eb0cca5d
84866df98f7a
84866df98f7a
84866df98f7a
84866df98f7a
84866df98f7a
84866df98f7a
84866df98f7a
db4cf067c338
db4cf067c338
84866df98f7a
84866df98f7a
84866df98f7a
84866df98f7a
84866df98f7a
84866df98f7a
84866df98f7a
84866df98f7a
84866df98f7a
84866df98f7a
84866df98f7a
db4cf067c338
84866df98f7a
84866df98f7a
db4cf067c338
db4cf067c338
db4cf067c338
db4cf067c338
84866df98f7a
84866df98f7a
84866df98f7a
84866df98f7a
84866df98f7a
84866df98f7a
84866df98f7a
84866df98f7a
84866df98f7a
84866df98f7a
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
13cbfa232eaf
846a54c8854c
7a41ccaab4c9
846a54c8854c
616c0b2560d4
616c0b2560d4
616c0b2560d4
754555c90530
7a41ccaab4c9
846a54c8854c
846a54c8854c
846a54c8854c
846a54c8854c
846a54c8854c
846a54c8854c
846a54c8854c
846a54c8854c
846a54c8854c
846a54c8854c
846a54c8854c
846a54c8854c
846a54c8854c
846a54c8854c
7a41ccaab4c9
846a54c8854c
846a54c8854c
7a41ccaab4c9
846a54c8854c
846a54c8854c
846a54c8854c
846a54c8854c
846a54c8854c
7a41ccaab4c9
846a54c8854c
846a54c8854c
846a54c8854c
8f09d07c0f15
846a54c8854c
846a54c8854c
846a54c8854c
846a54c8854c
846a54c8854c
846a54c8854c
846a54c8854c
846a54c8854c
846a54c8854c
846a54c8854c
846a54c8854c
846a54c8854c
846a54c8854c
754555c90530
18e6f04a1092
18e6f04a1092
18e6f04a1092
18e6f04a1092
18e6f04a1092
18e6f04a1092
18e6f04a1092
18e6f04a1092
18e6f04a1092
18e6f04a1092
18e6f04a1092
18e6f04a1092
18e6f04a1092
18e6f04a1092
18e6f04a1092
18e6f04a1092
754555c90530
21c31a64b0b3
9c63ff712e13
9c63ff712e13
9c63ff712e13
1d2016dd3af2
1d2016dd3af2
c728d093bab5
c728d093bab5
1d2016dd3af2
1d2016dd3af2
1d2016dd3af2
1d2016dd3af2
1d2016dd3af2
1d2016dd3af2
1d2016dd3af2
1d2016dd3af2
c728d093bab5
1d2016dd3af2
1d2016dd3af2
484da6c30b71
c728d093bab5
5b5bb72840e6
5b5bb72840e6
a9cef84324c3
6d580bbed7b0
ba5d7bfefee2
ba5d7bfefee2
6d580bbed7b0
0be4e8427de5
0be4e8427de5
0be4e8427de5
0be4e8427de5
0be4e8427de5
0be4e8427de5
0be4e8427de5
6d580bbed7b0
5b5bb72840e6
5b5bb72840e6
5b5bb72840e6
6d580bbed7b0
91e3a9a0628e
a9cef84324c3
8f09d07c0f15
8f09d07c0f15
8f09d07c0f15
8f09d07c0f15
8f09d07c0f15
ca2e4a119505
ca2e4a119505
ca2e4a119505
8f09d07c0f15
734207e4d1f8
734207e4d1f8
8f09d07c0f15
8f09d07c0f15
8f09d07c0f15
484da6c30b71
7a41ccaab4c9
484da6c30b71
484da6c30b71
484da6c30b71
484da6c30b71
484da6c30b71
484da6c30b71
484da6c30b71
484da6c30b71
7a41ccaab4c9
8f09d07c0f15
7a41ccaab4c9
8f09d07c0f15
8f09d07c0f15
8f09d07c0f15
29b335c7f903
8f09d07c0f15
8f09d07c0f15
8f09d07c0f15
8f09d07c0f15
29b335c7f903
8f09d07c0f15
8f09d07c0f15
8f09d07c0f15
8f09d07c0f15
8f09d07c0f15
29b335c7f903
29b335c7f903
8f09d07c0f15
8f09d07c0f15
29b335c7f903
9dfe0cba7fb5
9dfe0cba7fb5
9dfe0cba7fb5
b7680bc5acff
b7680bc5acff
b7680bc5acff
734207e4d1f8
734207e4d1f8
734207e4d1f8
8f09d07c0f15
8f09d07c0f15
29b335c7f903
18e6f04a1092
8f09d07c0f15
8f09d07c0f15
8f09d07c0f15
18e6f04a1092
8f09d07c0f15
484da6c30b71
484da6c30b71
484da6c30b71
7c98a38ebf04
29b335c7f903
8f09d07c0f15
7a41ccaab4c9
7a41ccaab4c9
ba5d7bfefee2
754555c90530
ba5d7bfefee2
ba5d7bfefee2
ba5d7bfefee2
1a741361737a
8b67a70070ef
ba5d7bfefee2
ba5d7bfefee2
59546e9e3870
654ffc1d6179
3dde26c84524
59546e9e3870
80c9092dbaa9
6d580bbed7b0
12f4253fa8db
80c9092dbaa9
654ffc1d6179
0be4e8427de5
0be4e8427de5
2a5a620b64ea
0be4e8427de5
0be4e8427de5
654ffc1d6179
0be4e8427de5
0be4e8427de5
0be4e8427de5
654ffc1d6179
0be4e8427de5
31771fb6594e
31771fb6594e
f3074254062c
355de37ac5f1
59546e9e3870
59546e9e3870
ba5d7bfefee2
ba5d7bfefee2
8b67a70070ef
ba5d7bfefee2
ba5d7bfefee2
a9cef84324c3
ba5d7bfefee2
e2a9aaa01362
/*
  Copyright 2009 Nathan Phillip Brink, Ethan Zonca, Matthew Orlando

  This file is a part of DistRen.

  DistRen is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  DistRen is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License
  along with DistRen.  If not, see <http://www.gnu.org/licenses/>.

*/

/* This file contains the code which both processes (renders) jobs as a slave, and the code which distributes frames to slaves after receiving them from the client portion of the codebase. */

#include "execio.h"
#include "options.h"
#include "distrenjob.h"
#include "protocol.h"
#include "slavefuncs.h"
#include "asprintf.h"

#include <confuse.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <unistd.h> /* getopt */
#include <time.h>
#include <sys/stat.h>
#include <string.h>

#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/encoding.h>
#include <libxml/xmlwriter.h>
#include <libxml/xmlreader.h>

/* ******************* Structs ************************ */

// Gets config info from confs
struct distrend_config
{
  cfg_t *mycfg;
  struct options_common *options;
  struct distrend_listen **listens; /*< Null terminated array of structs */
  char *datadir;
};

struct general_info {
  short int jobs_in_queue; //
  unsigned short int free_clients;
  unsigned short int rendering_clients;//
  unsigned short int total_finished_jobs; //
  unsigned int total_frames_rendered; //
  unsigned int highest_jobnum;
  short int hibernate;
} general_info;



/*
  internally defined funcs's prototypes @TODO: Make all functions nice and proper */
void distrenjob_remove(struct distrenjob *head, struct distrenjob *bj);

struct distrenjob *distrenjob_get(struct distrenjob *head, jobnum_t jobnum);
void distrenjob_enqueue(struct distrenjob *head, struct distrenjob *job);
void mortition(struct distrenjob *head, struct distrenjob *job);

/* Global Vars, eliminate these */
jobnum_t jobnum = 0; // The next job number to create in the queue
int hcfjob; // Highest consecutively finished job
int highest_jobnum; // The job number of the most recently created job, this is used when creating new jobs


/* ********************** Functions ************************* */

/** Dumps all data in RAM to an xml file (such as current jobs, etc) which is parsed by start_data. Remember to invoke this before shutting down! */
int xml_dump()
{
  return 0;
}
/**
   Performs command stored in a client's request.
*/
int distrend_do()
{
  return 0;
}
/**
   Accepts a client's connection
 */
void distrend_accept()
{

}
/**
   Frees the action
*/
void distrend_action_free()
{

}
/**
   Start listening
*/
void distrend_listen()
{

}
/**
   Stop listening
*/
void distrend_unlisten()
{

}
/**
   This is probably just a placeholder for remotio
*/
void remotio_send_to_client()
{
	// I am futile!
}

/** Fill variables after crash / shutdown from XML dumps */
int start_data()
{
  general_info.hibernate = 0;
  struct stat buffer;
  if(stat(SYSCONFDIR "/data.xml", &buffer) == 0){

    // @TODO: retrieve total_finished_jobs and total_finished_frames from xml file

    fprintf(stderr,"Parsing XML files and restoring previous state...\n");
    return 1;
  }
  else{
    general_info.total_finished_jobs = 0;
    general_info.total_frames_rendered = 0;
    fprintf(stderr,"Couldn't find XML dump, starting up fresh.\n");
    return 2;
  }
}

/** Finish-Setter: Sets a frame to the "completed" status.*/
void finish_frame(struct distrenjob *head, struct distrenjob *distrenjob, int frame)
{
  distrenjob->frameset[frame].status = FRAMESETSTATUS_DONE;
  distrenjob->total_render_time = distrenjob->total_render_time + (clock() - distrenjob[jobnum].frameset[frame].start_time);
  distrenjob->completed_frames++;
  distrenjob->assigned_frames--;
  general_info.total_frames_rendered++; // Increase total frames var for stats

  if(distrenjob->completed_frames == distrenjob->total_frames)
    {
      mortition(head, distrenjob);
    }
}

/** "mortition" check to see if a job is actually done by scanning the folder of the job to make sure all frames are present*/
void mortition(struct distrenjob *head, struct distrenjob *job)
{
  short int isJobDone;
  int counter;
  char *path_and_number;
  struct stat buffer;

  isJobDone = 1; // set isJobDone to true
  for(counter = 0; counter < job->total_frames; counter++)
    {
      _distren_asprintf(&path_and_number, "stor/job%d/out/%d.%s", job->jobnum, job->frameset[counter].num, job->output_format);
      if(stat(path_and_number, &buffer) == -1)
        {
          job->frameset[counter].status = FRAMESETSTATUS_UNASSIGNED;
          job->completed_frames--;
          isJobDone = 0; // if a missing frame is found, set isJobDone to false
        }
    }

  if(isJobDone) // if all frames were accounted for
    {
      distrenjob_remove(head, job);
      distrenjob_free(&job);
      general_info.jobs_in_queue--;
    }
  else{
    job->prev_frame_index = 0; // if the job isn't done, have frame_finder() start from the first frame, allowing it to see the frames that are now unassigned
  }
}

/** scans the frames of a job to initialize a job after server */
/* returns 1 if the job is completely done and there are no missing frames */
/* returns 0 if a missing frame is found */
int restoreJobState(struct distrenjob *job)
{
  short int isJobDone;
  int counter;
  char *path_and_number;
  struct stat buffer;

  isJobDone = 1;
  for(counter = 0; counter < job->total_frames; counter++)
    {
      _distren_asprintf(&path_and_number, "stor/job%d/out/%d.%s", job->jobnum, job->frameset[counter].num, job->output_format);
      if(stat(path_and_number, &buffer) == 0)
        {
          job->frameset[counter].status = FRAMESETSTATUS_ASSIGNED;
          job->completed_frames++;
        }
      else
        isJobDone = 0;
    }

  return isJobDone;
}

/** creates a structure from starting data, then calls another function to actually add that struct to the queue */
void prepare_distrenjob(struct distrenjob *head, int type, char *name, char *submitter, char *email, int priority, int start_frame, int end_frame, int width, int height)
{
  int counter2;
  int counter;

  struct distrenjob *distrenjob;
  distrenjob_new(&distrenjob);

  distrenjob->type = 1;
  distrenjob->name = name;
  distrenjob->submitter = submitter;
  distrenjob->email = email;
  distrenjob->priority = priority;
  distrenjob->width = width;
  distrenjob->height = height;
  distrenjob->total_frames = (end_frame - start_frame + 1); // sets the total number of frames in animation for status purposes

  /* prepares all the frames by setting that status to "unassigned" */
  counter2 = start_frame;
  for(counter = 0; counter <= (end_frame- start_frame + 1); counter++){
    distrenjob->frameset[counter].num = counter2;
    distrenjob->frameset[counter].status = FRAMESETSTATUS_UNASSIGNED;

    counter2++;
  }

  /* add job to queue */
  distrenjob_enqueue(head, distrenjob);

  general_info.jobs_in_queue++;
}


/** distrenjob_enqueue: This function adds the job to the queue based on its priority */
void distrenjob_enqueue(struct distrenjob *head, struct distrenjob *job) {
  struct distrenjob *prev_job = head; // create pointer to previous job
  struct distrenjob *current_job;     // create pointer to current_job (which job is being compared to)

  // iterate through linked list of jobs
  for(current_job = head; current_job != NULL; current_job = current_job->next){
    if(current_job == NULL){ // if it has reached the end of the list, add job there
      current_job = job;
      break;
    }
    else if(job->priority < current_job->priority){ // if job's priority is less than current_job's priority, insert job
      prev_job->next = job;                        // keep in mind 1 is the highest priority given to jobs, head has a
      job->next = current_job;                     // priority of zero so it will always be before other jobs
      break;
    }

    prev_job = current_job;
  } /* for(current_job) */
}

/** Changes the priority of an existing (and maybe running) job. @arg head I may end up changing the head if job == head */
void change_job_priority(struct distrenjob *head, struct distrenjob *job, int new_priority){
  distrenjob_remove(head, job);
  job->priority = new_priority;
  struct distrenjob *current_job;
  struct distrenjob *prev_job = head;

  if(job->frameset[0].status == FRAMESETSTATUS_UNASSIGNED)
    /* if job was not yet started */
    distrenjob_enqueue(head, job);
  else{ // if job has already been started, place it before the jobs with the same priority
    // iterate through linked list of jobs
    for(current_job = head; current_job != NULL; current_job = current_job->next){
      if(current_job == NULL){ // if it has reached the end of the list, add job there
        current_job = job;
        break;
      }
      else if(job->priority <= current_job->priority){ // if job's priority is less than or equal to current_job's priority, insert job
        prev_job->next = job;                        // keep in mind 1 is the highest priority given to jobs, head has a
        job->next = current_job;                     // priority of zero so it will always be before other jobs
        break;
      }

      prev_job = current_job;
    }
  }
}

/**
  Frame Finder: matches your computer up with a lovely frame to render, starts looking at oldest job first
  @TODO: We must return both jobnum and framenum
  @TODO: Add calls in main()
  @return 0 success, other: error
*/
int find_jobframe(struct distrenjob *head, struct distrenjob **job, struct frameset **frame)
{
  if(general_info.hibernate)
    return 1;

  unsigned int frame_counter;
  short int your_job_type;
  unsigned short int found;

  struct distrenjob *distrenjob_ptr;

  your_job_type = 0;
  found = 0;
  /* iterate through jobs from first to last */
  for(distrenjob_ptr = head->next; (!found && !distrenjob_ptr) && !distrenjob_ptr->hibernate; distrenjob_ptr = distrenjob_ptr->next)
    for(frame_counter = (distrenjob_ptr->prev_frame_index + 1); !found && frame_counter < distrenjob_ptr->total_frames; frame_counter ++)
      if(distrenjob_ptr->frameset[frame_counter].status == FRAMESETSTATUS_UNASSIGNED) // jobframe found
	{
	  found = 1;
	  your_job_type = distrenjob_ptr->type;
	  distrenjob_ptr->frameset[frame_counter].status = FRAMESETSTATUS_ASSIGNED;
	  distrenjob_ptr->frameset[frame_counter].start_time = clock();
	  distrenjob_ptr->assigned_frames++;
	  distrenjob_ptr->prev_frame_index = frame_counter;
	}

  if(!found)
    {
      fprintf(stderr, "No more jobs to render\n");
      sleep(1); /*< @todo eliminate the need for this line*/
      return 1;
    }

  *job = distrenjob_ptr;
  *frame = &distrenjob_ptr->frameset[frame_counter];

  return 0;
}

/** Checks for dead, latent, or stale slaves */
void frame_watchdog(struct distrenjob *distrenjob_head)
{
  struct distrenjob *distrenjob_ptr;
  unsigned int counter;

  for(distrenjob_ptr = distrenjob_head->next; distrenjob_ptr; distrenjob_ptr = distrenjob_ptr->next)
  /* iterate through jobs */

    /* if the job has been started, checks by seeing if either to first or second frame has been started */
    if(distrenjob_ptr->frameset[0].status != FRAMESETSTATUS_UNASSIGNED || distrenjob_ptr->frameset[1].status != FRAMESETSTATUS_UNASSIGNED)
      /* iterate through all frames for this job: */
      for(counter = 0; counter < distrenjob_ptr->total_frames; counter ++)
	/*watchdog_forgiveness = seconds of forgiveness before frame is re-assigned: */
        if((distrenjob_ptr->frameset[counter].start_time + distrenjob_ptr->watchdog_forgiveness) < clock())
        /*
        If frame is not completed within the number of seconds specified by watchdog_forgiveness
        Then change the frame status to unassigned
        */
          distrenjob_ptr->frameset[counter].status = FRAMESETSTATUS_UNASSIGNED;
}

/**
   Finds a distrenjob struct based on the jobnum
   @arg jobnum job number to search for
   @return NULL on job doesn't exist
 */
struct distrenjob *distrenjob_get(struct distrenjob *head, jobnum_t jobnum)
{
  struct distrenjob *distrenjob_ptr;

  /*
    The conditions of the for loop will leave distrenjob_ptr at NULL if the end of the list is reached. It will leave it pointing to the correct job if it is found.
   */
  for(distrenjob_ptr = head;
      distrenjob_ptr
        && distrenjob_ptr->jobnum != jobnum;
      distrenjob_ptr = distrenjob_ptr->next);

  return distrenjob_ptr;
}


/**
   Removes a distrenjob from the distrenjob linked list. It does not free the distrenjob, however. You should do that with distrenjob_free() from distrenjob.h

   @arg head pointer to the head of the linkedlist of distrenjobs
 */
void distrenjob_remove(struct distrenjob *head, struct distrenjob *bj)
{
  struct distrenjob *previous_distrenjob;

  for(previous_distrenjob = head;
      previous_distrenjob
	&& previous_distrenjob->next != bj; /*< stop on the distrenjob that comes before bj */
      previous_distrenjob = previous_distrenjob->next)
    /* all of the action is in the definition of the for loop itself */;

  /*
    This removes references to bj from the linked list. I.E., we now skip bj when iterating through the list
  */
  previous_distrenjob->next = bj->next;

  general_info.jobs_in_queue--;
}


/* Grabs config info from confs */
int distrend_do_config(int argc, char *argv[], struct distrend_config **config)
{
  cfg_opt_t myopts_listen[] =
    {
      CFG_SIMPLE_STR("type", NULL),
      CFG_SIMPLE_STR("path", NULL),
      CFG_SIMPLE_INT("port", NULL),
      CFG_END()
    };
  cfg_opt_t myopts[] =
    {
      CFG_SEC("listen",  /* this must be imported into struct listens (which must still be declared) */
          myopts_listen,
          CFGF_MULTI),
      CFG_SIMPLE_STR("datadir", NULL),
      CFG_END()
    };

  struct distrenjob *distrenjob;

  int tmp;

  xmlinit();
  /*
   * test xml2distrenjob()
   */
  tmp = xml2distrenjob(&distrenjob, "distrenjob.xml.example");
  if(tmp)
    fprintf(stderr, "xml2distrenjob() returned %d. Try to cd to distren/doc if you want to test out the xml2distrenjob() function. (This will only fix this error if the error is due to an inability of the xml library to access distrenjob.xml.example)\n\n", tmp);
  else
    fprintf(stderr, "using email ``%s'' for user ``%s'' -- reading in XML files and pulling data from them using libxml2+XPath works!!!\n", distrenjob->email, distrenjob->submitter);

  fprintf(stderr, "%s:%d running config\n", __FILE__, __LINE__);

  *config = malloc(sizeof(struct distrend_config));
  myopts[1].simple_value = &(*config)->datadir;

  options_init(argc, argv, &(*config)->mycfg, myopts, "server", &(*config)->options);

  fprintf(stderr, "using %s as datadir\n", (*config)->datadir);

  xmlcleanup();
  return 0;
}
int distrend_config_free(struct distrend_config *config)
{
  options_free(config->options);
  free(config);

  return 0;
}
/* ************************** XML Functions ************************* */

// returns 1 on successful completion of xml file
int makeSlaveDataXML(struct distrenjob *job)
{
  xmlTextWriterPtr writer;
  char *tmp; // temporarily holds strings to be given to the xml writer

  _distren_asprintf(&tmp, "stor/job%d/job_info.xml", job->jobnum);

  // create xml document at the location tmp with no compression
  writer = xmlNewTextWriterFilename(tmp, 0);
  xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL);

  // write resolution element and add its attributes
  xmlTextWriterStartElement(writer, (xmlChar*)"distrenjob");
  xmlTextWriterWriteAttribute(writer, (xmlChar*)"name", (xmlChar*)job->name);
  xmlTextWriterWriteAttribute(writer, (xmlChar*)"submitter", (xmlChar*)job->submitter);
  _distren_asprintf(&tmp, "%d", job->priority);
  xmlTextWriterWriteAttribute(writer, (xmlChar*)"priority", (xmlChar*)tmp);

  // write resolution element and add its attributes
  xmlTextWriterStartElement(writer, (xmlChar*)"resolution");
  _distren_asprintf(&tmp, "%d", job->width);
  xmlTextWriterWriteAttribute(writer, (xmlChar*)"width", (xmlChar*)tmp);
  _distren_asprintf(&tmp, "%d", job->height);
  xmlTextWriterWriteAttribute(writer, (xmlChar*)"height", (xmlChar*)tmp);
  xmlTextWriterEndElement(writer);

  // end document
  xmlTextWriterEndDocument(writer);

  // free writer and save xml file to disk
  xmlFreeTextWriter(writer);

  return 1;
}

// returns 1 if successful
// updates job_list.xml which lists all the jobs in the queue
int updateJobListXML(struct distrenjob *head)
{
  struct distrenjob *job;
  xmlTextWriterPtr writer;
  char *tmp;
  char *tmp2;
  int counter;

  _distren_asprintf(&tmp, "job_list.xml");
  writer = xmlNewTextWriterFilename(tmp, 0);
  xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL);

  // create root element job_list
  xmlTextWriterStartElement(writer, (xmlChar*)"job_list");

  _distren_asprintf(&tmp, "%d", general_info.jobs_in_queue);
  xmlTextWriterWriteAttribute(writer, (xmlChar*)"amount", (xmlChar*)tmp);

  counter = 0;
  for(job = head->next; !job; job = job->next)
    {
      _distren_asprintf(&tmp, "jobnum%d", counter);
      _distren_asprintf(&tmp2, "%d", job->jobnum);
      xmlTextWriterWriteElement(writer, (xmlChar*)tmp, (xmlChar*)tmp2);
      counter++;
    }

  // close elements and end document
  xmlTextWriterEndDocument(writer);

  // free writer and save xml file to disk
  xmlFreeTextWriter(writer);
  return 1;
}

// returns 1 if completed successfully, 0 if not
// this reads a list of jobs in the queue before DistRen was shut down
// and then adds the jobs to the queue, as if it were never shut down
int createQueueFromXML(struct distrenjob *head)
{
  xmlChar *tmp2;
  xmlDocPtr doc;  // holds xml document in memory
  xmlNodePtr cur; // points to the current xml element node

  // load xml document
  doc = xmlParseFile("job_list.xml");
  if(doc == NULL)
    {
      fprintf(stderr, "createQueueFromXML: document not found\n");
      return 0;
    }

  // have cur point to the root element of the xml document pointed to by doc
  cur = xmlDocGetRootElement(doc);
  if(cur == NULL)
    {
      fprintf(stderr, "createQueueFromXML: document empty\n");
      return 0;
    }

  if(xmlStrcmp(cur->name, (const xmlChar*)"job_list"))
    {
      fprintf(stderr, "createQueueFromXML: incorrect root element (%s)", (char*)cur->name);
    }

  // moves into the children elements of job_list
  cur = cur->xmlChildrenNode;

  // scans the list of all jobs that were in queue before DistRen shutdown
  while(cur != NULL)
    {
      tmp2 = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
      fprintf(stderr, "adding job: %s", tmp2);
      // add job from job number @TODO create function with parameters (struct distrenjob *head, int job_number)
      // LordOfWar calls dibs on above todo

      cur = cur->next; // go to next child element of job_list element
    }

  return 1;
}

/* ************************** Test Functions ************************* */
void printFrameInfo(struct frameset *frame)
{
  char *status;

  status = NULL;

  switch(frame->status)
  {
    case FRAMESETSTATUS_UNASSIGNED:
      _distren_asprintf(&status, "%s", "unassigned");
      break;
    case FRAMESETSTATUS_ASSIGNED:
      _distren_asprintf(&status, "%s", "assigned");
      break;
    case FRAMESETSTATUS_DONE:
      _distren_asprintf(&status, "%s", "completed");
      break;
    case FRAMESETSTATUS_CANCELED:
      _distren_asprintf(&status, "%s", "canceled");
  }

  printf("frame #: %d --> %s", frame->num, status);
}

void printJob(struct distrenjob *job)
{
  int counter;
  printf("frame_num: status");
  for(counter = 0; counter < job->total_frames; counter++)
    {
      printFrameInfo(&job->frameset[counter]);
    }
}

void printJobInfo(struct distrenjob *job)
{
  printf("type: %d", job->type);
  printf("name: %s", job->email);
  printf("submitter: %s", job->submitter);
  printf("e-mail: %s", job->email);
  printf("priority, %d", job->priority);
  printf("completed: %d", job->completed_frames);
  printf("assigned: %d", job->assigned_frames);
  printf("total: %d", job->total_frames);
  printf("watchdog: %d", job->watchdog_forgiveness);
  printf("hibernate: %d", job->hibernate);
  printf("prev_frame: %d", job->prev_frame_index);
}

void printAllJobnums(struct distrenjob *head)
{
  struct distrenjob *current_job;
  int total_jobs;
  printf("job numbers in the order they will be processed:");

  total_jobs = 0;
  for(current_job = head; !current_job; current_job = current_job->next)
    {
      printf("%d", current_job->jobnum);
      total_jobs++;
    }

  printf("%d jobs in queue", total_jobs);
}

/* ************************** Main ************************* */

int main(int argc, char *argv[])
{

  /* Argument-parser */
  int counter = 0;
  int test = 0; // Have some fun if-ness that does fun stuff when this is 1

  for(counter=0; counter<argc; counter++){
         if(strcmp(argv[counter], "-h") == 0) {
           fprintf(stderr, "Usage: distrend [option] \nStarts the distrend server\n\t-h\tshow this help\n\t-t\tlaunches queue testing interface \n");
           return 2;
          }

          else if(strcmp(argv[counter], "-t") == 0) {
            fprintf(stderr, "Entering into test mode...\n\n");
            test=1;
          }
  }


  struct distrenjob head;
  head.priority = 0; // make head have the highest priority

  int cont;
  struct distrend_listenset *listenset;
  struct distrend_config *config;

  enum clientstatus
  {
    CLIENTSTATUS_UNINITIALIZED = 0,
    CLIENTSTATUS_BUSY = 1,
    CLIENTSTATUS_IDLE = 2
  } clientstatus;

  cont = 1;
  memset(&head, '\0', sizeof(struct distrenjob));

  start_data(); // Starts fresh or loads data from xml dump. Should we grab the return?

  distrend_do_config(argc, argv, &config);

  int command;
  jobnum_t jobnum;
  struct distrenjob *tmp_job;
  struct frameset *tmp_frame;
  int type;
  char *name;
  char *submitter;
  char *email;
  int priority;
  int width;
  int height;
  int start_frame;
  int end_frame;

  while(test == 1)
  {
    fprintf(stderr, "Welcome to DistRen Alpha Interactive Test Mode\n\n");
    fprintf(stderr, "\t1 \tPrint all frames in a job\n");
    fprintf(stderr, "\t2 \tExamine certain job\n");
    fprintf(stderr, "\t3 \tGet a frame to render\n");
    fprintf(stderr, "\t4 \tAdd a job\n");
    fprintf(stderr, "\t5 \tDelete a job\n");
    fprintf(stderr, "\t6 \tPrint jobnums in queue\n");
    fprintf(stderr, "\t7 \tQuit\n");

    scanf("%d", &command);

    switch(command)
    {
    case 1:
      fprintf(stderr, "Job number: ");
      scanf("%d", &jobnum);
      printJob(distrenjob_get(&head, jobnum));
      break;
    case 2:
      fprintf(stderr, "Job number: ");
      scanf("%d", &jobnum);
      printJobInfo(distrenjob_get(&head, jobnum));
      break;
    case 3:
      find_jobframe(&head, &tmp_job, &tmp_frame);
      fprintf(stderr, "\nJob#:%d", tmp_job->jobnum);
      fprintf(stderr, "\nFrame#:%d", tmp_frame->num);
      break;
    case 4:
      fprintf(stderr, "\nType: \n\t 1 \t blender\n\t 2 \t povray\n"); scanf("%d", &type);
      fprintf(stderr, "\nName: ");                     scanf("%s", name);
      fprintf(stderr, "\nSubmitter: ");                scanf("%s", submitter);
      fprintf(stderr, "\nEmail: ");                    scanf("%s", email);
      fprintf(stderr, "\nPriority: ");                 scanf("%d", &priority);
      fprintf(stderr, "\nStart frame: ");              scanf("%d", &start_frame);
      fprintf(stderr, "\nEnd frame: ");                scanf("%d", &end_frame);
      fprintf(stderr, "\nWidth: ");                    scanf("%d", &width);
      fprintf(stderr, "\nHeight: ");                   scanf("%d", &height);
      prepare_distrenjob(&head, type, name, submitter, email, priority, start_frame, end_frame, width, height);
      break;
    case 5:
      fprintf(stderr, "\nJob number: ");
      scanf("%d", &jobnum);
      distrenjob_remove(&head, distrenjob_get(&head, jobnum));
      break;
    case 6:
      printAllJobnums(&head);
      break;
    case 7:
      fprintf(stderr,"Goodbye.\n");
      return 0;
    default:
      fprintf(stderr, "Invalid input, please try again.\n");
    }
  }

  distrend_listen(&listenset, config);
  /* This is called the "main loop" */
  while(cont)
    {
      struct distren_action *action;
      int clientsays = 0; /*< temporary example variable, will be replaced when we can handle messages */

      distrend_accept(&action);
      cont = distrend_do(action);

      /* Make the following code more event-driven */
      frame_watchdog(&head);


      struct frameset *frame;
      struct distrenjob *job;

      /* If the client is idle, must be modified for climbing through linked list of clients (client->clientnum) */
      if(clientstatus == CLIENTSTATUS_IDLE)
	{
	  int returnnum = find_jobframe(&head, &job, &frame); // Finds a frame to render
	  if(returnnum)
	    {
	      fprintf(stderr,"No frames are available to render at this time. Idling...\n");
	      sleep(10);
	    }
	  else
	    remotio_send_to_client(frame->num, job->jobnum); // Pseudo-sends data to client
	}
      /* If the client states that they finished the frame */
      	if(clientsays == DISTREN_REQUEST_DONEFRAME){
      	  clientstatus = CLIENTSTATUS_IDLE; // Sets the client back to idle
      	  finish_frame(&head, job, frame->num); // @TODO: Make sure this actually works.
      	}

      distrend_action_free(action);
    }

  distrend_unlisten(listenset);
  distrend_config_free(config);

  return 0;
}