File: Netplex_intro.html

package info (click to toggle)
ocamlnet 2.2.9-8
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 17,724 kB
  • ctags: 10,053
  • sloc: ml: 63,928; ansic: 1,973; makefile: 800; sh: 651
file content (1042 lines) | stat: -rw-r--r-- 44,998 bytes parent folder | download | duplicates (2)
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
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<link rel="stylesheet" href="style.css" type="text/css">
<meta content="text/html; charset=iso-8859-1" http-equiv="Content-Type">
<link rel="Start" href="index.html">
<link rel="previous" href="Netplex_cenv.html">
<link rel="next" href="Netshm.html">
<link rel="Up" href="index.html">
<link title="Index of types" rel=Appendix href="index_types.html">
<link title="Index of exceptions" rel=Appendix href="index_exceptions.html">
<link title="Index of values" rel=Appendix href="index_values.html">
<link title="Index of class attributes" rel=Appendix href="index_attributes.html">
<link title="Index of class methods" rel=Appendix href="index_methods.html">
<link title="Index of classes" rel=Appendix href="index_classes.html">
<link title="Index of class types" rel=Appendix href="index_class_types.html">
<link title="Index of modules" rel=Appendix href="index_modules.html">
<link title="Index of module types" rel=Appendix href="index_module_types.html">
<link title="Uq_gtk" rel="Chapter" href="Uq_gtk.html">
<link title="Equeue" rel="Chapter" href="Equeue.html">
<link title="Unixqueue" rel="Chapter" href="Unixqueue.html">
<link title="Uq_engines" rel="Chapter" href="Uq_engines.html">
<link title="Uq_socks5" rel="Chapter" href="Uq_socks5.html">
<link title="Unixqueue_mt" rel="Chapter" href="Unixqueue_mt.html">
<link title="Equeue_intro" rel="Chapter" href="Equeue_intro.html">
<link title="Uq_ssl" rel="Chapter" href="Uq_ssl.html">
<link title="Uq_tcl" rel="Chapter" href="Uq_tcl.html">
<link title="Netcgi_common" rel="Chapter" href="Netcgi_common.html">
<link title="Netcgi" rel="Chapter" href="Netcgi.html">
<link title="Netcgi_ajp" rel="Chapter" href="Netcgi_ajp.html">
<link title="Netcgi_scgi" rel="Chapter" href="Netcgi_scgi.html">
<link title="Netcgi_cgi" rel="Chapter" href="Netcgi_cgi.html">
<link title="Netcgi_fcgi" rel="Chapter" href="Netcgi_fcgi.html">
<link title="Netcgi_dbi" rel="Chapter" href="Netcgi_dbi.html">
<link title="Netcgi1_compat" rel="Chapter" href="Netcgi1_compat.html">
<link title="Netcgi_test" rel="Chapter" href="Netcgi_test.html">
<link title="Netcgi_porting" rel="Chapter" href="Netcgi_porting.html">
<link title="Netcgi_plex" rel="Chapter" href="Netcgi_plex.html">
<link title="Http_client" rel="Chapter" href="Http_client.html">
<link title="Telnet_client" rel="Chapter" href="Telnet_client.html">
<link title="Ftp_data_endpoint" rel="Chapter" href="Ftp_data_endpoint.html">
<link title="Ftp_client" rel="Chapter" href="Ftp_client.html">
<link title="Nethttpd_types" rel="Chapter" href="Nethttpd_types.html">
<link title="Nethttpd_kernel" rel="Chapter" href="Nethttpd_kernel.html">
<link title="Nethttpd_reactor" rel="Chapter" href="Nethttpd_reactor.html">
<link title="Nethttpd_engine" rel="Chapter" href="Nethttpd_engine.html">
<link title="Nethttpd_services" rel="Chapter" href="Nethttpd_services.html">
<link title="Nethttpd_plex" rel="Chapter" href="Nethttpd_plex.html">
<link title="Nethttpd_intro" rel="Chapter" href="Nethttpd_intro.html">
<link title="Netplex_types" rel="Chapter" href="Netplex_types.html">
<link title="Netplex_mp" rel="Chapter" href="Netplex_mp.html">
<link title="Netplex_mt" rel="Chapter" href="Netplex_mt.html">
<link title="Netplex_log" rel="Chapter" href="Netplex_log.html">
<link title="Netplex_controller" rel="Chapter" href="Netplex_controller.html">
<link title="Netplex_container" rel="Chapter" href="Netplex_container.html">
<link title="Netplex_sockserv" rel="Chapter" href="Netplex_sockserv.html">
<link title="Netplex_workload" rel="Chapter" href="Netplex_workload.html">
<link title="Netplex_main" rel="Chapter" href="Netplex_main.html">
<link title="Netplex_config" rel="Chapter" href="Netplex_config.html">
<link title="Netplex_kit" rel="Chapter" href="Netplex_kit.html">
<link title="Rpc_netplex" rel="Chapter" href="Rpc_netplex.html">
<link title="Netplex_cenv" rel="Chapter" href="Netplex_cenv.html">
<link title="Netplex_intro" rel="Chapter" href="Netplex_intro.html">
<link title="Netshm" rel="Chapter" href="Netshm.html">
<link title="Netshm_data" rel="Chapter" href="Netshm_data.html">
<link title="Netshm_hashtbl" rel="Chapter" href="Netshm_hashtbl.html">
<link title="Netshm_array" rel="Chapter" href="Netshm_array.html">
<link title="Netshm_intro" rel="Chapter" href="Netshm_intro.html">
<link title="Netconversion" rel="Chapter" href="Netconversion.html">
<link title="Netchannels" rel="Chapter" href="Netchannels.html">
<link title="Netstream" rel="Chapter" href="Netstream.html">
<link title="Mimestring" rel="Chapter" href="Mimestring.html">
<link title="Netmime" rel="Chapter" href="Netmime.html">
<link title="Netsendmail" rel="Chapter" href="Netsendmail.html">
<link title="Neturl" rel="Chapter" href="Neturl.html">
<link title="Netaddress" rel="Chapter" href="Netaddress.html">
<link title="Netbuffer" rel="Chapter" href="Netbuffer.html">
<link title="Netdate" rel="Chapter" href="Netdate.html">
<link title="Netencoding" rel="Chapter" href="Netencoding.html">
<link title="Netulex" rel="Chapter" href="Netulex.html">
<link title="Netaccel" rel="Chapter" href="Netaccel.html">
<link title="Netaccel_link" rel="Chapter" href="Netaccel_link.html">
<link title="Nethtml" rel="Chapter" href="Nethtml.html">
<link title="Netstring_str" rel="Chapter" href="Netstring_str.html">
<link title="Netstring_pcre" rel="Chapter" href="Netstring_pcre.html">
<link title="Netstring_mt" rel="Chapter" href="Netstring_mt.html">
<link title="Netmappings" rel="Chapter" href="Netmappings.html">
<link title="Netaux" rel="Chapter" href="Netaux.html">
<link title="Nethttp" rel="Chapter" href="Nethttp.html">
<link title="Netchannels_tut" rel="Chapter" href="Netchannels_tut.html">
<link title="Netmime_tut" rel="Chapter" href="Netmime_tut.html">
<link title="Netsendmail_tut" rel="Chapter" href="Netsendmail_tut.html">
<link title="Netulex_tut" rel="Chapter" href="Netulex_tut.html">
<link title="Neturl_tut" rel="Chapter" href="Neturl_tut.html">
<link title="Netsys" rel="Chapter" href="Netsys.html">
<link title="Netpop" rel="Chapter" href="Netpop.html">
<link title="Rpc_auth_dh" rel="Chapter" href="Rpc_auth_dh.html">
<link title="Rpc_key_service" rel="Chapter" href="Rpc_key_service.html">
<link title="Rpc_time" rel="Chapter" href="Rpc_time.html">
<link title="Rpc_auth_local" rel="Chapter" href="Rpc_auth_local.html">
<link title="Rtypes" rel="Chapter" href="Rtypes.html">
<link title="Xdr" rel="Chapter" href="Xdr.html">
<link title="Rpc" rel="Chapter" href="Rpc.html">
<link title="Rpc_program" rel="Chapter" href="Rpc_program.html">
<link title="Rpc_portmapper_aux" rel="Chapter" href="Rpc_portmapper_aux.html">
<link title="Rpc_packer" rel="Chapter" href="Rpc_packer.html">
<link title="Rpc_transport" rel="Chapter" href="Rpc_transport.html">
<link title="Rpc_client" rel="Chapter" href="Rpc_client.html">
<link title="Rpc_simple_client" rel="Chapter" href="Rpc_simple_client.html">
<link title="Rpc_portmapper_clnt" rel="Chapter" href="Rpc_portmapper_clnt.html">
<link title="Rpc_portmapper" rel="Chapter" href="Rpc_portmapper.html">
<link title="Rpc_server" rel="Chapter" href="Rpc_server.html">
<link title="Rpc_auth_sys" rel="Chapter" href="Rpc_auth_sys.html">
<link title="Rpc_intro" rel="Chapter" href="Rpc_intro.html">
<link title="Rpc_mapping_ref" rel="Chapter" href="Rpc_mapping_ref.html">
<link title="Rpc_ssl" rel="Chapter" href="Rpc_ssl.html">
<link title="Rpc_xti_client" rel="Chapter" href="Rpc_xti_client.html">
<link title="Shell_sys" rel="Chapter" href="Shell_sys.html">
<link title="Shell" rel="Chapter" href="Shell.html">
<link title="Shell_uq" rel="Chapter" href="Shell_uq.html">
<link title="Shell_mt" rel="Chapter" href="Shell_mt.html">
<link title="Shell_intro" rel="Chapter" href="Shell_intro.html">
<link title="Netsmtp" rel="Chapter" href="Netsmtp.html"><link title="Introduction into Netplex" rel="Section" href="#1_IntroductionintoNetplex">
<link title="Netplex RPC systems" rel="Section" href="#rpc_netplex">
<link title="Terminology" rel="Subsection" href="#2_Terminology">
<link title="A Simple Web Server" rel="Subsection" href="#2_ASimpleWebServer">
<link title="Running This Example" rel="Subsection" href="#2_RunningThisExample">
<link title="The Process Model" rel="Subsection" href="#2_TheProcessModel">
<link title="Creating Sockets" rel="Subsection" href="#2_CreatingSockets">
<link title="Services And Processors" rel="Subsection" href="#2_ServicesAndProcessors">
<link title="Defining Custom Processors" rel="Subsection" href="#2_DefiningCustomProcessors">
<link title="Workload Management" rel="Subsection" href="#2_WorkloadManagement">
<link title="Messaging" rel="Subsection" href="#2_Messaging">
<link title="Logging" rel="Subsection" href="#2_Logging">
<title>Ocamlnet 2 Reference Manual : Netplex_intro</title>
</head>
<body>
<div class="navbar"><a href="Netplex_cenv.html">Previous</a>
&nbsp;<a href="index.html">Up</a>
&nbsp;<a href="Netshm.html">Next</a>
</div>
<center><h1>Netplex_intro</h1></center>
<br>
<br>
<a name="1_IntroductionintoNetplex"></a>
<h1>Introduction into Netplex</h1>
<p>

Netplex is a generic (stream) server framework. This means, Netplex
does a lot of things for a network service that are always the same,
regardless of the kind of service:
<p>
<ul>
<li>Creation of server sockets</li>
<li>Accepting new network connections</li>
<li>Organizing multiple threads of execution - either by multiple 
  processes, multiple POSIX threads, or multiplexing</li>
<li>Workload management</li>
<li>Writing log files</li>
<li>Broadcasting messages to all server components</li>
<li>Support for a configuration file format</li>
</ul>

Netplex currently only supports stream sockets (TCP or Unix Domain).
<p>

Ocamlnet already includes Netplex adapters for Nethttpd (the HTTP daemon), 
and RPC servers. It is likely that more adapters for other network
protocols will follow.
<p>

Netplex can bundle several network services into a single system of
components. For example, you could have an RPC service that can be
managed over a web interface provided by Nethttpd. Actually, Netplex
focuses on such systems of interconnected components. RPC plays a
special role in such systems because this is the network protocol
the components use to talk to each other. It is also internally
used by Netplex for its administrative tasks.
<p>

<a name="2_Terminology"></a>
<h2>Terminology</h2>
<p>

In the Netplex world the following words are preferred to refer to
the parts of a Netplex system:
<p>
<ul>
<li>The <b>Netplex controller</b> is the core component of Netplex.
  The controller opens sockets and manages how new connections
  are accepted. For every socket, the controller determines 
  which <b>Netplex container</b> will accept the next connection
  that is tried to be established. Furthermore, the controller
  manages the startup and shutdown of the Netplex system.</li>
</ul>
<ul>
<li>The <b>Netplex services</b> are the user-defined components 
  of a Netplex system. Every service runs in its own process(es)
  (if multi-processing is selected) or in its own thread(s)
  (for POSIX multi-threading). It is up to the user to define
  what a service is.</li>
</ul>
<ul>
<li>The <b>Netplex protocols</b> are the languages spoken by the
  services. A protocol is bound to one or more sockets.
  This means that a service is implemented by a number of
  protocols. </li>
</ul>
<ul>
<li>The <b>Netplex containers</b> are processes or threads that may
  execute a certain service. Every container is bound to a
  specific service. It is possible that only one container
  is used for a particular service, but one can also configure
  that containers are dynamically started and stopped as the
  workload of the system changes.</li>
</ul>

<a name="2_ASimpleWebServer"></a>
<h2>A Simple Web Server</h2>
<p>

In order to create a web server, this main program and the following
configuration file are sufficient. (You find an extended example in
the "examples/nethttpd" directory of the Ocamlnet tarball.)
<p>

<pre><code class="code">let main() =
  (* Create a parser for the standard Netplex command-line arguments: *)
  let (opt_list, cmdline_cfg) = Netplex_main.args() in

  (* Parse the command-line arguments: *)
  Arg.parse
    opt_list
    (fun s -&gt; raise (Arg.Bad ("Don't know what to do with: " ^ s)))
    "usage: netplex [options]";

  (* Select multi-processing: *)
  let parallelizer = Netplex_mp.mp() in  

  (* Start the Netplex system: *)
  Netplex_main.startup
    parallelizer
    Netplex_log.logger_factories
    Netplex_workload.workload_manager_factories
    [ Nethttpd_plex.nethttpd_factory() ]
    cmdline_cfg
;;

Sys.set_signal Sys.sigpipe Sys.Signal_ignore;
main();;
</code></pre>
<p>

The configuration file:
<p>

<pre><code class="code">netplex {
  controller {
    max_level = "debug";    (* Log level *)
    logging {
      type = "stderr";      (* Log to stderr *)
    }
  };
  service {
    name = "My HTTP file service";
    protocol {
      (* This section creates the socket *)
      name = "http";
      address {
        type = "internet";
        bind = "0.0.0.0:80";  (* Port 80 on all interfaces *)
      };
    };
    processor {
      (* This section specifies how to process data of the socket *)
      type = "nethttpd";
      host {
        (* Think of Apache's "virtual hosts" *)
        pref_name = "localhost";
        pref_port = 80;
        names = "*:0";   (* Which requests are matched here: all *)
        uri {
          path = "/";
          service {
            type = "file";
            docroot = "/usr";
            media_types_file = "/etc/mime.types";
            enable_listings = true;
          }
        };
      };
    };
    workload_manager {
      type = "dynamic";
      max_jobs_per_thread = 1;  (* Everything else is senseless *)
      min_free_jobs_capacity = 1;
      max_free_jobs_capacity = 1;
      max_threads = 20;
    };
  }
}
</code></pre>
<p>

As you can see, the main program is extremely simple. Netplex includes
support for command-line parsing, and the rest deals with the question
which Netplex modules are made accessible for the configuration file.
<p>

Here, we have:
<p>
<ul>
<li>The multi-execution provider is <a href="Netplex_mp.html#VALmp"><code class="code">Netplex_mp.mp</code></a> which implements
  multi-processing. (Btw, multi-processing is the preferred 
  parallelizing technique in Netplex.) Replace it with
  <a href="Netplex_mt.html#VALmt"><code class="code">Netplex_mt.mt</code></a> to get multi-threading.</li>
<li>The <a href="Netplex_log.html#VALlogger_factories"><code class="code">Netplex_log.logger_factories</code></a> are the list of all predefined
  logging mechanisms. The configuration file can select one of these
  mechanisms.</li>
<li>The <a href="Netplex_workload.html#VALworkload_manager_factories"><code class="code">Netplex_workload.workload_manager_factories</code></a> are the list of 
  all predefined worload management mechanisms. The configuration
  file can select one of these mechanisms per service.</li>
<li>Finally, we pass <a href="Nethttpd_plex.html#VALnethttpd_factory"><code class="code">Nethttpd_plex.nethttpd_factory</code></a> as the only
  service processor.</li>
</ul>

The configuration file consists of nested sections whose extents are
denoted by curly braces. The sections are partly defined by Netplex
itself (e.g. the controller section and the workload manager section),
and partly by the service provider (almost everything inside 
"processor"). That means that the components of a Netplex system
pick "their" part from the configuration file, and that, depending
on which components are linked into this system, the config files
may look very different.
<p>

Here, we have:
<p>
<ul>
<li>The <code class="code">controller</code> section sets the log level and the logging method.
  The latter is done by naming one of the logger factories as 
  logging <code class="code">type</code>. If the factory needs more parameters to create
  the logger, these can be set inside the <code class="code">logging</code> section.</li>
<li>For every <code class="code">service</code> there is a <code class="code">name</code> (can be freely chosen), one
  or several <code class="code">protocol</code>s, a <code class="code">processor</code>, and a <code class="code">workload_manager</code>.
  The <code class="code">protocol</code> section declare which protocols are available and
  to which sockets they are bound. Here, the "http" protocol (name can again
  be freely chosen) is reachable over TCP port 80 on all network
  interfaces. By having multiple <code class="code">address</code> sections, one can bind
  the same protocol to multiple sockets.</li>
<li>The <code class="code">processor</code> section specifies the <code class="code">type</code> and optionally a 
  lot of parameters (which may be structured into several sections).
  By setting <code class="code">type</code> to "nethttpd" we select the
  <a href="Nethttpd_plex.html#VALnethttpd_factory"><code class="code">Nethttpd_plex.nethttpd_factory</code></a> to create the processor 
  (because "nethttpd" is the default name for this factory).
  This factory now interprets the other parameters of the <code class="code">processor</code>
  section. Here, a static HTTP server is defined that uses /usr
  as document root.</li>
<li>Finally, the <code class="code">workload_manager</code> section says how to deal with
  parallely arriving requests. The <code class="code">type</code> selects the dynamic
  workload manager which is configured by the other parameters.
  Roughly said, one container (i.e. process) is created in advance
  for the next network connection ("pre-fork"), and the upper limit
  of containers is 20.</li>
</ul>

<a name="2_RunningThisExample"></a>
<h2>Running This Example</h2>
<p>

If you start this program without any arguments, it will immediately
fail because it wants to open <code class="code">/etc/netplex.conf</code> - this is the 
default name for the configuration file. Use <code class="code">-conf</code> to pass the
real name of the above file.
<p>

Netplex creates a directory for its internal processing, and this is
by default <code class="code">/tmp/.netplex</code>. You can change this directory by 
setting the <code class="code">socket_directory</code> parameter in the <code class="code">controller</code> section.
In this directory, you can find:
<p>
<ul>
<li>A directory <code class="code">netplex.controller</code> which refers to the controller
  component.</li>
<li>For every service another directory containing local run-time files.
  The directory has the same name as the service.</li>
</ul>

Netplex comes with a generic administration command called
<code class="code">netplex-admin</code>. You can use it to send control messages to Netplex
systems. For example,
<p>

<pre><code class="code"> netplex-admin -list </code></pre>
<p>

outputs the list of services. With 
<p>

<pre><code class="code"> netplex-admin -shutdown </code></pre>
<p>

the system is (gracefully) shut down. It is also possible to broadcast
messages to all components:
<p>

<pre><code class="code"> netplex-admin name arg1 arg2 ... </code></pre>
<p>

It is up to the components to interpret these messages.
<p>

<a name="2_TheProcessModel"></a>
<h2>The Process Model</h2>
<p>

Netplex uses a generalized pre-fork process model. Let me explain this
model a bit, as it is important to know it in order to understand
Netplex fully.
<p>

The most trivial form of a multi-process Unix server is the post-fork
model. Although it is not used by Netplex, it is the model explained
in many books, and it is what many people think a Unix server has to
look like. Actually, the post-fork model has lots of limitations, and
is not suited for high-performance servers.
<p>

In the post-fork model, the master process accepts new network
connections in an endless loop, and whenever a new connection is
established, a sub process (container process) is spawned that processes
the network traffic. There is a serious logical limitation, and a
performance limitation:
<p>
<ul>
<li>In the post-fork model every container process can only deal with
  one connection at a time. The reason is that at the time of
  spawning the container there is only one connection, and one cannot
  assign the container another connection later.</li>
<li>The post-fork model spawns the container processes at a bad moment.
  Spawning is a very expensive operation, and doing it just after
  connection establishment is bad because this means that the
  client has to wait longer for a response. Furthermore, spawning
  for every connection wastes system resources.</li>
</ul>

In the pre-fork model, these disadvantages can be avoided. Here, one
or several processes are spawned in advance. Furthermore, these
processes cannot only manage one connection but any number, and
this can happen sequentially (one connection is processed after the
other) or in parallel (using multiplexing).
<p>

This is achieved by letting the containers themselves accept the new
connections instead of the master process. In the Unix process model
it is possible that server sockets are shared by several processes,
and every container is allowed to accept the next connection. However,
the containers should cooperate, and avoid that several containers call
<code class="code">Unix.accept</code> at the same time (as this leads to performance problems
when a container must be able to watch several ports for new
connections - a problem we do not discuss here). There are many ways to
organize
such cooperation, and for simplicity, Netplex implements this by
exchanging RPC messages with the master process, the controller.
Effectively, the controller has the task of scheduling which of the
containers accepts the next arriving network connection.
<p>

What actually happens is the following. We assume here that we have
a number of idle container processes that could accept the next connection.
<p>
<ul>
<li>The controller selects one of the containers as the one that will get
  the next connection.</li>
<li>The selected container watches the ports for incoming connections.
  Note that this is done in a Unixqueue, so that if there are 
  already connections to be processed, this can be done in a multiplexed
  way in parallel with watching for new connections.</li>
<li>When the next connection arrives, the container accepts it, and
  invokes the service component to process it.</li>
<li>Immediately after connection establishment, the container tells the
  controller what happened, so the controller can watch out for another
  container to take over the role of accepting further connections.</li>
<li>When the connection is fully processed, another control message
  is sent to the controller because the controller must know at all
  times how many connections are being processed by which containers.
  This is simply an important load parameter.</li>
</ul>

The details of this mechanism are not very interesting for using
it. However, one must know that
<p>
<ul>
<li>connections are accepted by the sub processes and not by the
  master process,</li>
<li>the sub processes can accept as many connections as they want to,
  either one after the other, or even several at once,</li>
<li>the controller schedules tasks and determines which connection
  is accepted by which container,</li>
<li>there is a certain protocol between controller and container, and
  although the details are hidden from the user, this has consequences
  for the user interface. In particular, the reason why the 
  <code class="code">when_done</code> function must be called upon connection termination
  is that a control message must be sent to the controller.</li>
</ul>

Another implication of the pre-fork model is that one needs workload
management. As processes are created in advance, the question arises
how many are created, and when the processes are terminated to free
resources. Netplex comes with two workload managers: One manager
simply creates a fixed number of processes which are never terminated, 
and the other manager tries to adapt the number to the load by
dynamically starting and stopping processes. This is discussed below in
detail.
<p>

<a name="2_CreatingSockets"></a>
<h2>Creating Sockets</h2>
<p>

The server sockets are always created by the controller at program
startup. This is a strict requirement because only this ensures that
the created container processes share the same sockets.
<p>

The sockets are descibed in the <code class="code">protocol</code> section of the
configuration file. For an Internet socket this section looks like
<p>

<pre><code class="code">    protocol {
      name = "&lt;name&gt;";
      address {
        type = "internet";
        bind = "&lt;address&gt;:&lt;port&gt;";
      };
    };
</code></pre>
<p>

The <code class="code">&lt;name&gt;</code> is only important when there are several protocols in order
to distinguish between them. The <code class="code">&lt;address&gt;</code> can be:
<p>
<ul>
<li>An IP address of a network interface to bind the socket to this
  particular interface. Both IPv4 and IPv6 addresses are supported.
  IPv4 addresses are simply given in "dotted quad" notation 
  (e.g. <code class="code">192.168.76.23</code>), and IPv6 addresses must be enclosed in brackets
  (e.g. <code class="code">[fe80::250:56ff:fec0:1]</code>).</li>
<li>The special IPv4 address <code class="code">0.0.0.0</code> to bind the socket to all IPv4
  network interfaces, or the special IPv6 address <code class="code">[::0]</code> to bind it
  to all IPv6 network interfaces.</li>
<li>A resolvable host name which is the same as using the corresponding
  IP address.</li>
</ul>

The <code class="code">&lt;port&gt;</code> must be the port number or 0 to use an anonymous port.
<p>

For a local (Unix domain) socket, the <code class="code">protocol</code> section looks like
<p>

<pre><code class="code">    protocol {
      name = "&lt;name&gt;";
      address {
        type = "local";
        path = "&lt;path&gt;";
      };
    };
</code></pre>
<p>

where the <code class="code">&lt;path&gt;</code> is the filename of the socket.
<p>

One can have several <code class="code">address</code> sections to create several sockets for the
same protocol.
<p>

<a name="2_ServicesAndProcessors"></a>
<h2>Services And Processors</h2>
<p>

A Netplex system consists of exactly the services that are enumerated
in the config file. This means it is not sufficient to build in support
for a service into the program, one must also activate it in the config
file. This gives the end user of the program a lot of flexibility when
running the system: By simply changing the config file one can enable
or disable services. It is also possible to run the same program binary
several times with different config files.
<p>

The services are implemented by processors, which are user-defined
objects that handle the network connection after it is accepted by
the component. The <code class="code">processor</code> section of the service selects the
processor by name, and optionally passes configuration parameters to 
it:
<p>

<pre><code class="code">    processor {
        type = "&lt;name&gt;";
        ... further parameters allowed ...
    }
</code></pre>
<p>

The mentioned name of the processor type is used to find the so-called
factory for the processor (an object with a <code class="code">create_processor</code> method).
All factories must be available at Netplex startup so the library
knows which factories exist when the config file is interpreted
(the factories are an argument of <a href="Netplex_main.html#VALstartup"><code class="code">Netplex_main.startup</code></a>).
<p>

Processor objects are somewhat strange in so far as they exist both in
the controller and in the container processes. In particular, these
objects are created by the controller, and they are duplicated once
for all container processes when these are actually created.
<p>

The processor objects (of type <a href="Netplex_types.processor.html"><code class="code">Netplex_types.processor</code></a>) consist of
a number of methods. We have already seen one of them, <code class="code">process</code>,
which is called in the container process when a new connection is
accepted. The other methods are called at other points of interest:
<p>

<b>Methods called on the controller instance of the processor</b>
<p>
<ul>
<li><code class="code">post_add_hook</code> is immediately called after the addtion of the
  service to the controller.</li>
<li><code class="code">post_rm_hook</code> is immediately called after the removal of the
  service from the controller.</li>
<li><code class="code">pre_start_hook</code> is called just before the next container process
  is spawned.</li>
<li><code class="code">post_finish_hook</code> is called after termination of the container.</li>
</ul>

<b>Methods called on the container instance of the processor</b>
<p>
<ul>
<li><code class="code">post_start_hook</code> is called just after the container process
  has been created, but now for the copy of the processor object
  that lives in the container process. This is a very useful hook
  method, because one can initialize the container process
  (e.g. prepare database accesses etc.).</li>
<li><code class="code">pre_finish_hook</code> is called just before the container process
  will (regularly) terminated.</li>
<li><code class="code">receive_message</code> is called when a message from another 
  container arrives.</li>
<li><code class="code">receive_admin_message</code> is called when a message from the
  administrator arrives.</li>
<li><code class="code">shutdown</code> is called when the shutdown notification arrives.
  The shutdown will lead to the termination of the process
  when all network connections managed by Unixqueue are finished.
  This method must terminate such connections if they have been
  created in addition to those Netplex manages.</li>
<li><code class="code">global_exception_handler</code> is called for exceptions falling through
  to the container, and is the last chance to catch them.</li>
</ul>

Because of the instances in the controller and the containers it is
usually a bad idea to store state in the processor object.
<p>

If multi-threading is used instead of multi-processing, there is only
one instance of the processor that is used in the controller and
all containers.
<p>

<a name="2_DefiningCustomProcessors"></a>
<h2>Defining Custom Processors</h2>
<p>

Using predefined processor factories like <a href="Nethttpd_plex.html#VALnethttpd_factory"><code class="code">Nethttpd_plex.nethttpd_factory</code></a>
is very easy. Fortunately, it is not very complicated to define a
custom adapter that makes an arbitrary network service available as
Netplex processor.
<p>

In principle, you must define a class for the type 
<a href="Netplex_types.processor.html"><code class="code">Netplex_types.processor</code></a> and the corresponding factory implementing
the type <a href="Netplex_types.processor_factory.html"><code class="code">Netplex_types.processor_factory</code></a>. To do the first,
simply inherit from <code class="code">Netplex_kit.processor_base</code> and override the
methods that should do something instead of nothing. For example,
to define a service that outputs the line "Hello world" on the
TCP connection, define:
<p>

<pre><code class="code"> 
class hello_world_processor : processor =
  let empty_hooks = new Netplex_kit.empty_processor_hooks() in
object(self)
  inherit Netplex_kit.processor_base empty_hooks

  method process ~when_done container fd proto_name =
    let ch = Unix.out_channel_of_descr fd in
    output_string ch "Hello world\n";
    close_out ch;
    when_done()

  method supported_ptypes = [ `Multi_processing; `Multi_threading ]
end
</code></pre>
<p>

The method <code class="code">process</code> is called whenever a new connection is made.
The <code class="code">container</code> is the object representing the container where the
execution happens (<code class="code">process</code> is always called from the container).
In <code class="code">fd</code> the file descriptor is passed that is the (already accepted)
connection. In <code class="code">proto_name</code> the protocol name is passed - here it is
unused, but it is possible to process the connection in a way that
depends on the name of the protocol.
<p>

The argument <code class="code">when_done</code> is very important. It <b>must</b> be called by
<code class="code">process</code>! For a synchronous processor like this one it is simply called
before <code class="code">process</code> returns to the caller.
<p>

For an asynchronous processor (i.e. a processor that handles several
connections in parallel in the same process/thread), <code class="code">when_done</code> must
be called when the connection is fully processed. This may be at any
time in the future.
<p>

The class <code class="code">hello_world_processor</code> can now be turned into a factory:
<p>

<pre><code class="code">class hello_world_factory : processor_factory =
object(self) 
  method name = "hello_world"
  method create_processor ctrl_cfg cfg_file cfg_addr =
    new hello_world_processor
end
</code></pre>
<p>

As you see, one can simply choose a <code class="code">name</code>. This is the type of
the <code class="code">processor</code> section in the configuration file, i.e. you need
<p>

<pre><code class="code">  ...
  service {
    name = "hello world sample";
    ...
    processor {
      type = "hello_world"
    };
    ...
  }
  ...
</code></pre>
<p>

to activate this factory for a certain service definition. Of course,
the instantiated <code class="code">hello_world_factory</code> must also be passed to
<a href="Netplex_main.html#VALstartup"><code class="code">Netplex_main.startup</code></a> in order to be available at runtime.
<p>

The <code class="code">create_processor</code> method simply creates an object of your class. The
argument <code class="code">ctrl_cfg</code> is the configuration of the controller (e.g.
you find there the name of the socket directory). In <code class="code">cfg_file</code>
the object is passed that accesses the configuration file as
tree of parameters. In <code class="code">cfg_addr</code> the address of the <code class="code">processor</code>
section is made available, so you can look for additional 
configuration parameters.
<p>

You may wonder why it is necessary to first create <code class="code">empty_hooks</code>.
The hook methods are often overridden by the user of processor
classes. In order to simplify this, it is common to allow the 
user to pass a hook object to the processor object:
<p>

<pre><code class="code"> 
class hello_world_processor hooks : processor =
object(self)
  inherit Netplex_kit.processor_base hooks

  method process ~when_done container fd proto_name = ...
  method supported_ptypes = ...
end
</code></pre>
<p>

Now, the user can simply define hooks as in
<p>

<pre><code class="code">class my_hooks =
object(self)
  inherit Netplex_kit.empty_processor_hooks()

  method post_start_hook container = ...
end
</code></pre>
<p>

and pass such a hook object into the factory.
<p>

<a name="2_WorkloadManagement"></a>
<h2>Workload Management</h2>
<p>

Workload managers decide when to start new containers and when to stop
useless ones. The simplest manager is created by the
<a href="Netplex_workload.html#VALconstant_workload_manager_factory"><code class="code">Netplex_workload.constant_workload_manager_factory</code></a>. The user
simply defines how many containers are to be started. In the
config file this is written as
<p>

<pre><code class="code">    workload_manager {
        type = "constant";
        threads = &lt;n&gt;;
    }
</code></pre>
<p>

where <code class="code">&lt;n&gt;</code> is the number of containers &gt; 0. Often this manager is used
to achieve n=1, i.e. to have exactly one container. An example would
be a stateful RPC server where it is important that all network connections
are handled by the same process. (N.B. n=1 for RPC servers does not
enforce that the connections are serialized because Ocamlnet RPC servers
can handle multiple connections in parallel, but of course it is enforced
that the remote procedures are invoked in a strictly sequential way.)
<p>

If n&gt;1, it is tried to achieve that all containers get approximately 
the same load.
<p>

If processes die unexpectedly, the constant workload manager starts
new components until the configured number of processes is again reached.
<p>

The dynamic workload manager (created by 
<a href="Netplex_workload.html#VALdynamic_workload_manager_factory"><code class="code">Netplex_workload.dynamic_workload_manager_factory</code></a>) is able to start
and stop containers dynamically. There are a few parameters that control
the manager. A "thread" is here another word for a started container.
A "job" is an established network connection. Using this terms, the
task of the workload manager is to decide how many threads are needed
to do a varying number of jobs. The parameters now set how many jobs
every thread may execute, and how quickly new threads are created or
destroyed to adapt the available thread capacity to the current job
load.
<p>

If the service processor can only accept one network connection after
the other (like Nethttpd_plex), the only reasonable setting is that
there is at most one job per thread. If one configures a higher number
in this case, unaccepted network connections will queue up resulting
in poor performance.
<p>

If the service processor can handle several connections in parallel it
is possible to allow more than one job per thread. There is no general
rule how many jobs per thread are reasonable, one has to experiment to
find it out. In this mode of having more than one job per thread,
Netplex even allows two service qualities, "normal" and "overload". If
possible, Netplex tries to achieve that all containers deliver normal
quality, but if the load goes beyond that, it is allowed that
containers accept more connections than that. This is called an
overload situation. Often it is better to allow overload than to
refuse new connections.
<p>

The dynamic workload manager is enabled by the section
<p>

<pre><code class="code">    workload_manager {
        type = "dynamic";
	... parameters, see below ...
    }
</code></pre>
<p>

The required parameters are:
<p>
<ul>
<li><code class="code">max_threads</code>: How many containers can be created at maximum for
  this service.</li>
<li><code class="code">max_jobs_per_thread</code>: How many jobs every container can execute
  at maximum. The upper limit for the number of jobs is thus
  <code class="code">max_threads * max_jobs_per_thread</code>.</li>
<li><code class="code">min_free_job_capacity</code>: This parameter controls how quickly new
  containers are started when the load goes up. It is tried to
  ensure that there are as many containers so this number of jobs
  can be additionally performed. This parameter must
  be at least 1.</li>
<li><code class="code">max_free_job_capacity</code>: This parameter controls how quickly 
  containers are stopped when the load goes down. It is tried to
  ensure that unused containers are stopped so the capacity for
  additional jobs is not higher than this parameter. 
  This parameter must be greater or equal than
  <code class="code">min_free_job_capacity</code>.</li>
</ul>

In order to configure the overload mode:
<p>
<ul>
<li><code class="code">recommended_jobs_per_thread</code>: The number of jobs a container
  can do with normal service quality. A higher number is considered
  as overload.</li>
</ul>

The effect of this parameter is that it is avoided that a container
gets more jobs than recommended as long as possible.
<p>

Another parameter is:
<p>
<ul>
<li><code class="code">inactivity_timeout</code>: If a container idles longer than this number
  of seconds and is not needed to ensure <code class="code">min_free_job_capacity</code> it is
  shut down. Defaults to 15 seconds.</li>
</ul>

<a name="2_Messaging"></a>
<h2>Messaging</h2>
<p>

There are two kinds of messages one can send to Netplex containers:
normal messages come from another Netplex container, and admin messages
are sent using the <code class="code">netplex-admin</code> command.
<p>

Messages have a name and a (possibly empty) list of string parameters.
They can be sent to an individual receiver container, or to a number
of containers, even to all. The sender does not get an acknowledgment
when the messages are delivered.
<p>

Messages can e.g. be used 
<p>
<ul>
<li>to signal that internal state is output to log files in order to debug
  a special situation</li>
<li>to enable or disable special features of the running system</li>
<li>to flush caches</li>
</ul>

and for other comparably simple communication needs.
<p>

In order to receive a normal message, one must define the
<code class="code">receive_message</code> method in the processor object, and to receive an
admin message, one must define the <code class="code">receive_admin_message</code> method.
<p>

A normal message is sent by the container method <code class="code">send_message</code>.
The receiver is identified by the service name, i.e. all containers
with the passed name get the message. The name may even contain
the wildcard <code class="code">*</code> to select the containers by a name pattern.
<p>

An admin message is sent using the <code class="code">netplex-admin</code> command.
<p>

There are a few predefined messages understood by all containers:
<p>
<ul>
<li>The admin message <code class="code">netplex.threadlist</code> outputs to the log file
  which process executes which service, and how loaded the processes are.</li>
<li>The admin message <code class="code">netplex.logger.set_max_level</code> changes the maximum
  log level for the container.</li>
<li>The admin message <code class="code">netplex.debug_scheduling</code> enables debug messages
  of the Netplex scheduler.</li>
<li>The admin message <code class="code">netplex.debug_containers</code> enables debug messages
  of the container implementation.</li>
</ul>

In general, messages starting with "netplex." are reserved for 
Netplex itself.
<p>

<a name="2_Logging"></a>
<h2>Logging</h2>
<p>

Log messages can be written in the containers. The messages are first
sent to the controller where they are written to stderr, to files, or
to any object of the type <a href="Netplex_types.logger.html"><code class="code">Netplex_types.logger</code></a>. That the messages
are first sent to the controller has a lot of advantages: The messages
are implicitly serialized, no locking is needed, and it is easy to
support log file rotation.
<p>

In order to write a log message, one needs the container object.
The module <code class="code">Netplex_cenv</code> always knows the container object of the 
caller, to get it:
<p>

<pre><code class="code">let cont = Netplex_cenv.self_cont()
</code></pre>
<p>

If you call <code class="code">self_conf</code> outside a container, the exception
<a href="Netplex_cenv.html#EXCEPTIONNot_in_container_thread"><code class="code">Netplex_cenv.Not_in_container_thread</code></a> is raised. This is e.g. the
case if you call it from the <code class="code">pre_start</code> or <code class="code">post_finish</code> callbacks.
<p>

Logging is now done by
<p>

<pre><code class="code">let cont = Netplex_cenv.self_cont() in
cont # log level message
</code></pre>
<p>

where <code class="code">level</code> is one of <code class="code">`Debug</code>, <code class="code">`Info</code>, <code class="code">`Notice</code>, <code class="code">`Warning</code>, <code class="code">`Err</code>,
<code class="code">`Crit</code>, <code class="code">`Alert</code>, <code class="code">`Emerg</code>, and <code class="code">message</code> is a string. The levels are
the same as for syslog. 
<p>

You can also call <a href="Netplex_cenv.html#VALlog"><code class="code">Netplex_cenv.log</code></a> and <a href="Netplex_cenv.html#VALlogf"><code class="code">Netplex_cenv.logf</code></a>,
which simply use <code class="code">self_cont</code> to get the container and call its <code class="code">log</code>
method to write the message.
<p>

The config file controls what to do with the log messages. The easiest
way is to send all messages to stderr:
<p>

<pre><code class="code">  controller {
    max_level = "debug";    (* Log level *)
    logging {
      type = "stderr";      (* Log to stderr *)
    }
  };
</code></pre>
<p>

Further types of logging are documented in the <a href="Netplex_log.html"><code class="code">Netplex_log</code></a> module.
<p>

<a name="rpc_netplex"></a>
<h1>Netplex RPC systems</h1>
<p>

A short description how to build systems of RPC services is given
in <a href="Rpc_intro.html#rpc_netplex"><i>Netplex RPC systems</i></a>.
<br>
</body></html>