lib: Add unix_msg
[obnox/samba/samba-obnox.git] / source3 / lib / unix_msg / tests.c
1 #include "replace.h"
2 #include "unix_msg.h"
3 #include "poll_funcs/poll_funcs_tevent.h"
4 #include "tevent.h"
5
6 struct cb_state {
7         unsigned num_received;
8         uint8_t *buf;
9         size_t buflen;
10 };
11
12 static void recv_cb(struct unix_msg_ctx *ctx,
13                     uint8_t *msg, size_t msg_len,
14                     void *private_data);
15
16 static void expect_messages(struct tevent_context *ev, struct cb_state *state,
17                             unsigned num_msgs)
18 {
19         state->num_received = 0;
20
21         while (state->num_received < num_msgs) {
22                 int ret;
23
24                 ret = tevent_loop_once(ev);
25                 if (ret == -1) {
26                         fprintf(stderr, "tevent_loop_once failed: %s\n",
27                                 strerror(errno));
28                         exit(1);
29                 }
30         }
31 }
32
33 int main(void)
34 {
35         struct poll_funcs funcs;
36         const char *sock1 = "sock1";
37         const char *sock2 = "sock2";
38         struct unix_msg_ctx *ctx1, *ctx2;
39         struct tevent_context *ev;
40         struct iovec iov;
41         uint8_t msg;
42         int i, ret;
43         static uint8_t buf[1755];
44
45         struct cb_state state;
46
47         unlink(sock1);
48         unlink(sock2);
49
50         ev = tevent_context_init(NULL);
51         if (ev == NULL) {
52                 perror("tevent_context_init failed");
53                 return 1;
54         }
55         poll_funcs_init_tevent(&funcs, ev);
56
57         ret = unix_msg_init(sock1, &funcs, 256, 1,
58                             recv_cb, &state, &ctx1);
59         if (ret != 0) {
60                 fprintf(stderr, "unix_msg_init failed: %s\n",
61                         strerror(ret));
62                 return 1;
63         }
64
65         ret = unix_msg_init(sock1, &funcs, 256, 1,
66                             recv_cb, &state, &ctx1);
67         if (ret == 0) {
68                 fprintf(stderr, "unix_msg_init succeeded unexpectedly\n");
69                 return 1;
70         }
71         if (ret != EADDRINUSE) {
72                 fprintf(stderr, "unix_msg_init returned %s, expected "
73                         "EADDRINUSE\n", strerror(ret));
74                 return 1;
75         }
76
77         ret = unix_msg_init(sock2, &funcs, 256, 1,
78                             recv_cb, &state, &ctx2);
79         if (ret != 0) {
80                 fprintf(stderr, "unix_msg_init failed: %s\n",
81                         strerror(ret));
82                 return 1;
83         }
84
85         printf("sending a 0-length message\n");
86
87         state.buf = NULL;
88         state.buflen = 0;
89
90         ret = unix_msg_send(ctx1, sock2, NULL, 0);
91         if (ret != 0) {
92                 fprintf(stderr, "unix_msg_send failed: %s\n",
93                         strerror(ret));
94                 return 1;
95         }
96
97         expect_messages(ev, &state, 1);
98
99         printf("sending a small message\n");
100
101         msg = random();
102         iov.iov_base = &msg;
103         iov.iov_len = sizeof(msg);
104         state.buf = &msg;
105         state.buflen = sizeof(msg);
106
107         ret = unix_msg_send(ctx1, sock2, &iov, 1);
108         if (ret != 0) {
109                 fprintf(stderr, "unix_msg_send failed: %s\n",
110                         strerror(ret));
111                 return 1;
112         }
113
114         expect_messages(ev, &state, 1);
115
116         printf("sending six large, interleaved messages\n");
117
118         for (i=0; i<sizeof(buf); i++) {
119                 buf[i] = random();
120         }
121
122         iov.iov_base = buf;
123         iov.iov_len = sizeof(buf);
124         state.buf = buf;
125         state.buflen = sizeof(buf);
126
127         for (i=0; i<3; i++) {
128                 ret = unix_msg_send(ctx1, sock2, &iov, 1);
129                 if (ret != 0) {
130                         fprintf(stderr, "unix_msg_send failed: %s\n",
131                                 strerror(ret));
132                         return 1;
133                 }
134                 ret = unix_msg_send(ctx2, sock2, &iov, 1);
135                 if (ret != 0) {
136                         fprintf(stderr, "unix_msg_send failed: %s\n",
137                                 strerror(ret));
138                         return 1;
139                 }
140         }
141
142         expect_messages(ev, &state, 6);
143
144         printf("sending a few messages in small pieces\n");
145
146         for (i = 0; i<5; i++) {
147                 struct iovec iovs[20];
148                 const size_t num_iovs = ARRAY_SIZE(iovs);
149                 uint8_t *p = buf;
150                 size_t j;
151
152                 for (j=0; j<num_iovs-1; j++) {
153                         size_t chunk = (random() % ((sizeof(buf) * 2) / num_iovs));
154                         size_t space = (sizeof(buf) - (p - buf));
155
156                         if (space == 0) {
157                                 break;
158                         }
159
160                         chunk = MIN(chunk, space);
161
162                         iovs[j].iov_base = p;
163                         iovs[j].iov_len = chunk;
164                         p += chunk;
165                 }
166
167                 if (p < (buf + sizeof(buf))) {
168                         iovs[j].iov_base = p;
169                         iovs[j].iov_len = (sizeof(buf) - (p - buf));
170                         j++;
171                 }
172
173                 ret = unix_msg_send(ctx1, sock1, iovs, j);
174                 if (ret != 0) {
175                         fprintf(stderr, "unix_msg_send failed: %s\n",
176                                 strerror(ret));
177                         return 1;
178                 }
179         }
180
181         expect_messages(ev, &state, 5);
182
183         printf("Filling send queues before freeing\n");
184
185         for (i=0; i<5; i++) {
186                 ret = unix_msg_send(ctx1, sock2, &iov, 1);
187                 if (ret != 0) {
188                         fprintf(stderr, "unix_msg_send failed: %s\n",
189                                 strerror(ret));
190                         return 1;
191                 }
192                 ret = unix_msg_send(ctx1, sock1, &iov, 1);
193                 if (ret != 0) {
194                         fprintf(stderr, "unix_msg_send failed: %s\n",
195                                 strerror(ret));
196                         return 1;
197                 }
198         }
199
200         expect_messages(ev, &state, 1); /* Read just one msg */
201
202         unix_msg_free(ctx1);
203         unix_msg_free(ctx2);
204         talloc_free(ev);
205
206         return 0;
207 }
208
209 static void recv_cb(struct unix_msg_ctx *ctx,
210                     uint8_t *msg, size_t msg_len,
211                     void *private_data)
212 {
213         struct cb_state *state = (struct cb_state *)private_data;
214
215         if (msg_len != state->buflen) {
216                 fprintf(stderr, "expected %u bytes, got %u\n",
217                         (unsigned)state->buflen, (unsigned)msg_len);
218                 exit(1);
219         }
220         if ((msg_len != 0) && (memcmp(msg, state->buf, msg_len) != 0)) {
221                 fprintf(stderr, "message content differs\n");
222                 exit(1);
223         }
224         state->num_received += 1;
225 }