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