1 //  The Ironhouse Pattern
2 //
3 //  This is exactly the same example but broken into two threads
4 //  so you can better see what client and server do, separately.
5 
6 #include <czmq.h>
7 
await_term(zsock_t * pipe)8 void await_term (zsock_t *pipe)
9 {
10     bool terminated = false;
11     while (!terminated) {
12         zmsg_t *msg = zmsg_recv (pipe);
13         if (!msg)
14             break;              //  Interrupted
15         char *command = zmsg_popstr (msg);
16         //  All actors must handle $TERM in this way
17         if (streq (command, "$TERM"))
18             terminated = true;
19         else {
20             puts ("E: invalid message to actor");
21             assert (false);
22         }
23         free (command);
24         zmsg_destroy (&msg);
25     }
26 }
27 
28 //  The client task runs in its own context, and receives the
29 //  server public key as an argument.
30 
31 static void
client_task(zsock_t * pipe,void * args)32 client_task (zsock_t *pipe, void *args)
33 {
34     //  Load our persistent certificate from disk
35     zcert_t *client_cert = zcert_load ("client_cert.txt");
36     assert (client_cert);
37 
38     //  Create client socket and configure it to use full encryption
39     zsock_t *client = zsock_new (ZMQ_PULL);
40     assert (client);
41     zcert_apply (client_cert, client);
42     zsock_set_curve_serverkey (client, (char *) args);
43     int rc = zsock_connect (client, "tcp://127.0.0.1:9000");
44     assert (rc == 0);
45 
46     zsock_signal (pipe, 0);
47 
48     //  Wait for our message, that signals the test was successful
49     char *message = zstr_recv (client);
50     assert (streq (message, "Hello"));
51     free (message);
52     puts ("Ironhouse test OK");
53 
54     await_term (pipe);
55 
56     //  Free all memory we used
57     zsock_destroy (&client);
58     zcert_destroy (&client_cert);
59 }
60 
61 static void
server_task(zsock_t * pipe,void * args)62 server_task (zsock_t *pipe, void *args)
63 {
64     //  Start the authenticator and tell it do authenticate clients
65     //  via the certificates stored in the .curve directory.
66     zactor_t *auth = zactor_new (zauth, NULL);
67     assert (auth);
68     assert (zstr_send (auth, "VERBOSE") == 0);
69     assert (zsock_wait (auth) >= 0);
70     assert (zstr_sendx (auth, "ALLOW", "127.0.0.1", NULL) == 0);
71     assert (zsock_wait (auth) >= 0);
72     assert (zstr_sendx (auth, "CURVE", ".curve", NULL) == 0);
73     assert (zsock_wait (auth) >= 0);
74 
75     //  Create server socket and configure it to use full encryption
76     zsock_t *server = zsock_new (ZMQ_PUSH);
77     assert (server);
78     zcert_apply ((zcert_t *) args, server);
79     zsock_set_curve_server (server, 1);
80     int rc = zsock_bind (server, "tcp://*:9000");
81     assert (rc != -1);
82 
83     zsock_signal (pipe, 0);
84 
85     //  Send our test message, just once
86     assert (zstr_send (server, "Hello") == 0);
87 
88     await_term (pipe);
89 
90     //  Free all memory we used
91     zsock_destroy (&server);
92     zactor_destroy (&auth);
93 }
94 
main(void)95 int main (void)
96 {
97     //  Create the certificate store directory and client certs
98     zcert_t *client_cert = zcert_new ();
99     int rc = zsys_dir_create (".curve");
100     assert (rc == 0);
101     zcert_set_meta (client_cert, "name", "Client test certificate");
102     zcert_save_public (client_cert, ".curve/testcert.pub");
103     rc = zcert_save (client_cert, "client_cert.txt");
104     assert (rc == 0);
105     zcert_destroy (&client_cert);
106 
107     //  Create the server certificate
108     zcert_t *server_cert = zcert_new ();
109 
110     //  Now start the two detached threads; each of these has their
111     //  own ZeroMQ context.
112     zactor_t *server_actor = zactor_new (server_task, server_cert);
113     assert (server_actor);
114     zactor_t *client_actor = zactor_new (client_task, (void *) zcert_public_txt (server_cert));
115     assert (client_actor);
116 
117     //  Free the memory we used
118     //  and coordinate process termination with actor termination
119     zactor_destroy (&client_actor);
120     zactor_destroy (&server_actor);
121 
122     return 0;
123 }
124