1/* Simple door test. */
2
3#include <door.h>
4#include <errno.h>
5#include <fcntl.h>
6#include <limits.h>
7#include <signal.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <unistd.h>
12#include <sys/mman.h>
13#include <sys/stat.h>
14#include <sys/types.h>
15#include <sys/wait.h>
16
17static char door_file[] = "/tmp/vgtest_door_data.XXXXXX";
18static volatile int exit_now = 0;
19
20static void child_handler(int sig)
21{
22   if (!exit_now) {
23      fprintf(stderr, "Received premature SIGCHLD.\n");
24      unlink(door_file);
25      exit(1);
26   }
27}
28
29/* SERVER CODE */
30static void server_procedure(void *cookie, char *argp, size_t arg_size,
31                             door_desc_t *dp, uint_t n_desc)
32{
33   char data[] = "Hello from server";
34
35   if (!argp)
36      goto out;
37
38   if (arg_size > INT_MAX) {
39      fprintf(stderr, "Value received from a client is too big.\n");
40      goto out;
41   }
42
43   printf("SERVER: %.*s\n", (int)arg_size, argp);
44   fflush(stdout);
45
46out:
47   /* Let server_main() know that we should exit. */
48   *(int*)cookie = 1;
49
50   door_return(data, strlen(data) + 1, NULL, 0);
51
52   /* Function door_return() should never return. */
53   perror("door_return");
54   exit(1);
55}
56
57static int server_main(void)
58{
59   int res = 1;
60   int did = -1;
61   int attached = 0;
62
63   /* Make sure nothing else is attached. */
64   fdetach(door_file);
65
66   if ((did = door_create(server_procedure, (void*)&exit_now, 0)) < 0) {
67      perror("door_create");
68      return 1;
69   }
70
71   /* Attach to file system. */
72   if (fattach(did, door_file) < 0) {
73      char str[100];
74      snprintf(str, sizeof(str), "fattach %s", door_file);
75      perror(str);
76      goto out;
77   }
78   attached = 1;
79
80   /* Poor man's termination. */
81   while (!exit_now)
82      sleep(1);
83
84   res = 0;
85
86out:
87   if (attached && unlink(door_file)) {
88      char str[100];
89      snprintf(str, sizeof(str), "unlink %s", door_file);
90      perror(str);
91   }
92   if (did >= 0 && door_revoke(did))
93      perror("door_revoke");
94
95   return res;
96}
97
98/* CLIENT CODE */
99static int client_main(void)
100{
101   int did;
102   char buf[128];
103   int tries;
104   door_arg_t params;
105   struct door_info info;
106
107   tries = 0;
108   while (1) {
109      /* Open the door file. */
110      if ((did = open(door_file, O_RDWR)) >= 0)
111         if (!door_info(did, &info))
112            break;
113
114      close(did);
115
116      if (tries > 10) {
117         char str[100];
118         snprintf(str, sizeof(str), "door_info %s", door_file);
119         perror(str);
120         return 1;
121      }
122
123      tries++;
124      sleep(1);
125   }
126
127   /* Set call parameters. */
128   snprintf(buf, sizeof(buf), "Hello from client");
129   params.data_ptr = buf;
130   params.data_size = strlen(buf) + 1;
131   params.desc_ptr = NULL;
132   params.desc_num = 0;
133   params.rbuf = buf;
134   params.rsize = sizeof(buf);
135
136   /* Make the call. */
137   if (door_call(did, &params)) {
138      perror("door_call");
139      close(did);
140      return 1;
141   }
142
143   close(did);
144
145   /* Print a result of the call. */
146   printf("CLIENT: %.*s\n", (int)params.rsize, params.rbuf);
147   fflush(stdout);
148
149   /* It's possible that the system allocated a new memory for rbuf.  Unmap it
150      if it's the case */
151   if (params.rbuf != buf)
152      if (munmap(params.rbuf, params.rsize) != 0) {
153         perror("munmap");
154         return 1;
155      }
156
157   return 0;
158}
159
160/* MAIN CODE */
161int main(void)
162{
163   struct sigaction sa;
164   pid_t pid;
165   int door_fd;
166
167   /* Establish handler for client error exit. */
168   sa.sa_handler = child_handler;
169   sa.sa_flags = SA_NOCLDSTOP;
170   if (sigemptyset(&sa.sa_mask)) {
171      perror("sigemptyset");
172      return 1;
173   }
174   if (sigaction(SIGCHLD, &sa, NULL)) {
175      perror("sigaction");
176      return 1;
177   }
178
179   door_fd = mkstemp(door_file);
180   if (door_fd < 0) {
181      perror("mkstemp");
182      return 1;
183   }
184   close(door_fd);
185
186   pid = fork();
187   if (pid == -1) {
188      perror("fork");
189      return 1;
190   }
191
192   if (pid == 0) {
193      return client_main();
194   } else {
195      int res = server_main();
196      if (res == 0) {
197         do {
198            if (wait(NULL) == pid)
199               break;
200            if (errno != EINTR) {
201               perror("wait");
202               res = 1;
203            }
204         } while (errno == EINTR);
205      }
206      return res;
207   }
208}
209