1 /*
2  * Copyright (c) 1998,1999,2000
3  *      Traakan, Inc., Los Altos, CA
4  *      All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice unmodified, this list of conditions, and the following
11  *    disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 /*
30  * Project:  NDMJOB
31  * Ident:    $Id: $
32  *
33  * Description:
34  *
35  ********************************************************************
36  *
37  * NDMP Elements of a test-data session
38  *
39  *                   +-----+     ###########
40  *                   | Job |----># CONTROL #
41  *                   +-----+     #  Agent  #
42  *                               #         #
43  *                               ###########
44  *                                 |      #
45  *                +----------------+      #
46  *                | control connection    #     CONTROL
47  *                V                       #     impersonates
48  *           ############                 #     TAPE side of
49  *           #  DATA    #                 #     image stream
50  *           #  Agent   #                 #
51  *  +-----+  # +------+ # image           #
52  *  |FILES|====|butype|===================#
53  *  +-----+  # +------+ # stream
54  *           ############
55  *
56  *
57  ********************************************************************
58  *
59  */
60 
61 
62 #include "ndmagents.h"
63 
64 
65 #if !defined(NDMOS_OPTION_NO_CONTROL_AGENT) && \
66     !defined(NDMOS_OPTION_NO_TEST_AGENTS)
67 
68 
69 extern int ndmca_td_wrapper(struct ndm_session* sess,
70                             int (*func)(struct ndm_session* sess));
71 
72 
73 extern int ndmca_op_test_data(struct ndm_session* sess);
74 extern int ndmca_td_idle(struct ndm_session* sess);
75 
76 extern int ndmca_td_listen(struct ndm_session* sess);
77 extern int ndmca_td_listen_subr(struct ndm_session* sess,
78                                 ndmp9_error expect_err,
79                                 ndmp9_addr_type addr_type);
80 extern int ndmca_test_check_data_state(struct ndm_session* sess,
81                                        ndmp9_data_state expected,
82                                        int reason);
83 extern int ndmca_test_data_get_state(struct ndm_session* sess,
84                                      ndmp9_error expect_err);
85 extern int ndmca_test_data_abort(struct ndm_session* sess,
86                                  ndmp9_error expect_err);
87 extern int ndmca_test_data_stop(struct ndm_session* sess,
88                                 ndmp9_error expect_err);
89 
90 
ndmca_op_test_data(struct ndm_session * sess)91 int ndmca_op_test_data(struct ndm_session* sess)
92 {
93   struct ndm_control_agent* ca = sess->control_acb;
94   struct ndmconn* conn;
95   int (*save_call)(struct ndmconn * conn, struct ndmp_xa_buf * xa);
96   int rc;
97 
98   rc = ndmca_connect_data_agent(sess);
99   if (rc) {
100     ndmconn_destruct(sess->plumb.data);
101     sess->plumb.data = NULL;
102     return rc;
103   }
104 
105   conn = sess->plumb.data;
106   save_call = conn->call;
107   conn->call = ndma_call_no_tattle;
108 
109   /* perform query to find out about TCP and LOCAL support */
110   rc = ndmca_test_query_conn_types(sess, conn);
111   if (rc) return rc;
112 
113   rc = ndmca_td_wrapper(sess, ndmca_td_idle);
114   if (sess->plumb.data->protocol_version >= 3) {
115     // version 3 and later adds LISTEN
116     rc = ndmca_td_wrapper(sess, ndmca_td_listen);
117   }
118 
119   ndmca_test_done_series(sess, "test-data");
120 
121   ca = sess->control_acb;
122   if (ca->has_tcp_addr && ca->has_local_addr) {
123     ndmalogf(sess, "TEST", 0, "LOCAL and TCP addressing tested.");
124   } else if (ca->has_tcp_addr) {
125     ndmalogf(sess, "TEST", 0, "TCP addressing ONLY tested.");
126   } else if (ca->has_local_addr) {
127     ndmalogf(sess, "TEST", 0, "LOCAL addressing ONLY tested.");
128   } else {
129     ndmalogf(sess, "TEST", 0, "Neither TCP or LOCAL addressing tested.");
130   }
131 
132   return 0;
133 }
134 
ndmca_td_wrapper(struct ndm_session * sess,int (* func)(struct ndm_session * sess))135 int ndmca_td_wrapper(struct ndm_session* sess,
136                      int (*func)(struct ndm_session* sess))
137 {
138   int rc;
139 
140   rc = (*func)(sess);
141 
142   if (rc != 0) { ndmalogf(sess, "Test", 1, "Failure"); }
143 
144   ndmca_test_done_phase(sess);
145 
146   /* clean up mess */
147   ndmca_test_log_note(sess, 2, "Cleaning up...");
148 
149   rc = 0;
150 
151   return rc;
152 }
153 
ndmca_td_idle(struct ndm_session * sess)154 int ndmca_td_idle(struct ndm_session* sess)
155 {
156   int rc;
157 
158   ndmca_test_phase(sess, "D-IDLE", "Data IDLE State Series");
159 
160   rc = ndmca_test_check_data_state(sess, NDMP9_DATA_STATE_IDLE, 0);
161   if (rc) return rc;
162 
163   rc = ndmca_test_data_abort(sess, NDMP9_ILLEGAL_STATE_ERR);
164   if (rc) return rc;
165 
166   rc = ndmca_test_data_stop(sess, NDMP9_ILLEGAL_STATE_ERR);
167   if (rc) return rc;
168 
169   return 0; /* pass */
170 }
171 
172 
173 #define NDMTEST_CALL(CONN) ndmca_test_call(CONN, xa, expect_err);
174 
175 
ndmca_test_data_listen(struct ndm_session * sess,ndmp9_error expect_err,ndmp9_addr_type addr_type)176 int ndmca_test_data_listen(struct ndm_session* sess,
177                            ndmp9_error expect_err,
178                            ndmp9_addr_type addr_type)
179 {
180   struct ndmconn* conn = sess->plumb.data;
181   struct ndm_control_agent* ca = sess->control_acb;
182   int rc;
183 
184   /* close previous test if there is one */
185   ndmca_test_close(sess);
186 
187   switch (conn->protocol_version) {
188     default:
189       return -1234;
190 
191 #ifndef NDMOS_OPTION_NO_NDMP3
192     case NDMP3VER:
193       NDMC_WITH(ndmp3_data_listen, NDMP3VER)
194       request->addr_type = addr_type;
195 
196       rc = NDMTEST_CALL(conn);
197       if (rc) return rc;
198 
199       if (expect_err == NDMP9_NO_ERR &&
200           request->addr_type != reply->data_connection_addr.addr_type) {
201         /* TODO: use proper test format */
202         ndmalogf(sess, "Test", 1, "DATA_LISTEN addr_type mismatch");
203         return -1;
204       }
205       ndmp_3to9_addr(&reply->data_connection_addr, &ca->data_addr);
206       NDMC_ENDWITH
207       break;
208 #endif /* !NDMOS_OPTION_NO_NDMP3 */
209 #ifndef NDMOS_OPTION_NO_NDMP4
210     case NDMP4VER:
211       NDMC_WITH(ndmp4_data_listen, NDMP4VER)
212       request->addr_type = addr_type;
213 
214       rc = NDMTEST_CALL(conn);
215       if (rc) return rc;
216 
217       if (expect_err == NDMP9_NO_ERR &&
218           request->addr_type != reply->connect_addr.addr_type) {
219         /* TODO: use proper test format */
220         ndmalogf(sess, "Test", 1, "DATA_LISTEN addr_type mismatch");
221         return -1;
222       }
223       ndmp_4to9_addr(&reply->connect_addr, &ca->data_addr);
224       NDMC_ENDWITH
225       break;
226 #endif /* !NDMOS_OPTION_NO_NDMP4 */
227   }
228 
229   return 0;
230 }
231 
232 
ndmca_td_listen(struct ndm_session * sess)233 int ndmca_td_listen(struct ndm_session* sess)
234 {
235   struct ndm_control_agent* ca = sess->control_acb;
236   int rc;
237 
238   ndmca_test_phase(sess, "D-LISTEN", "Data LISTEN State Series");
239 
240   rc = ndmca_test_check_data_state(sess, NDMP9_DATA_STATE_IDLE, 0);
241   if (rc) return rc;
242 
243   if (ca->has_tcp_addr) {
244     rc = ndmca_td_listen_subr(sess, NDMP9_NO_ERR, NDMP9_ADDR_TCP);
245     if (rc) return rc;
246   }
247 
248   if (ca->has_local_addr) {
249     rc = ndmca_td_listen_subr(sess, NDMP9_NO_ERR, NDMP9_ADDR_LOCAL);
250     if (rc) return rc;
251   }
252 
253   ndmca_test_done_phase(sess);
254 
255   /*
256    * Bogus arguments
257    */
258   ndmca_test_phase(sess, "D-LISTEN/bogus-args",
259                    "Data LISTEN State Series w/ bogus args");
260 
261   rc = ndmca_test_data_listen(sess, NDMP9_ILLEGAL_ARGS_ERR, 123);
262   if (rc) return rc;
263 
264   ndmca_test_done_phase(sess);
265 
266 
267   return 0; /* pass */
268 }
269 
ndmca_td_listen_subr(struct ndm_session * sess,ndmp9_error expect_err,ndmp9_addr_type addr_type)270 int ndmca_td_listen_subr(struct ndm_session* sess,
271                          ndmp9_error expect_err,
272                          ndmp9_addr_type addr_type)
273 {
274   int rc;
275 
276   rc = ndmca_test_check_data_state(sess, NDMP9_DATA_STATE_IDLE, 0);
277   if (rc) return rc;
278 
279   rc = ndmca_test_data_listen(sess, expect_err, addr_type);
280   if (rc) return rc;
281 
282   if (expect_err != NDMP9_NO_ERR) return 0; /* got expected error */
283 
284   rc = ndmca_test_check_data_state(sess, NDMP9_DATA_STATE_LISTEN, 0);
285   if (rc) return rc;
286 
287   rc = ndmca_test_data_listen(sess, NDMP9_ILLEGAL_STATE_ERR, addr_type);
288   if (rc) return rc;
289 
290   rc = ndmca_test_data_stop(sess, NDMP9_ILLEGAL_STATE_ERR);
291   if (rc) return rc;
292 
293   rc = ndmca_test_data_abort(sess, NDMP9_NO_ERR);
294   if (rc) return rc;
295 
296   rc = ndmca_test_check_data_state(sess, NDMP9_DATA_STATE_HALTED,
297                                    NDMP9_DATA_HALT_ABORTED);
298   if (rc) return rc;
299 
300   rc = ndmca_test_data_stop(sess, NDMP9_NO_ERR);
301   if (rc) return rc;
302 
303   rc = ndmca_test_check_data_state(sess, NDMP9_DATA_STATE_IDLE, 0);
304   if (rc) return rc;
305 
306   return 0;
307 }
308 
ndmca_test_check_data_state(struct ndm_session * sess,ndmp9_data_state expected,int reason)309 int ndmca_test_check_data_state(struct ndm_session* sess,
310                                 ndmp9_data_state expected,
311                                 int reason)
312 {
313   struct ndm_control_agent* ca = sess->control_acb;
314   ndmp9_data_get_state_reply* ds = &ca->data_state;
315   int rc;
316   char* what;
317   char errbuf[100];
318   char tmpbuf[256];
319 
320   /* close previous test if there is one */
321   ndmca_test_close(sess);
322 
323   /* open new test */
324   ndmca_test_open(sess, "data check", ndmp9_data_state_to_str(expected));
325 
326   strcpy(errbuf, "???");
327 
328   what = "get_state";
329   rc = ndmca_data_get_state(sess);
330   if (rc) goto fail;
331 
332   what = "state self-consistent";
333   /* make sure the sensed state is self consistent */
334   switch (ds->state) {
335     case NDMP9_DATA_STATE_IDLE:
336     case NDMP9_DATA_STATE_ACTIVE:
337     case NDMP9_DATA_STATE_LISTEN:
338     case NDMP9_DATA_STATE_CONNECTED:
339       if (ds->halt_reason != NDMP9_DATA_HALT_NA) {
340         strcpy(errbuf, "reason != NA");
341         goto fail;
342       }
343       break;
344 
345     case NDMP9_DATA_STATE_HALTED:
346       break;
347 
348     default:
349       strcpy(errbuf, "bogus state");
350       goto fail;
351   }
352 
353   what = "state";
354   if (ds->state != expected) {
355     snprintf(errbuf, sizeof(errbuf), "expected %s got %s",
356              ndmp9_data_state_to_str(expected),
357              ndmp9_data_state_to_str(ds->state));
358     goto fail;
359   }
360 
361   what = "reason";
362   switch (ds->state) {
363     case NDMP9_DATA_STATE_HALTED:
364       if (ds->halt_reason != (ndmp9_data_halt_reason)reason) {
365         snprintf(errbuf, sizeof(errbuf), "expected %s got %s",
366                  ndmp9_data_halt_reason_to_str(reason),
367                  ndmp9_data_halt_reason_to_str(ds->halt_reason));
368         goto fail;
369       }
370       break;
371 
372     default:
373       break;
374   }
375 
376   /* test passed */
377   ndmca_test_close(sess);
378 
379   return 0;
380 
381 fail:
382   /* test failed */
383   snprintf(tmpbuf, sizeof(tmpbuf), "%s: %s", what, errbuf);
384   ndmca_test_fail(sess, tmpbuf);
385 
386   ndmca_test_close(sess);
387 
388   return -1;
389 }
390 
391 
ndmca_test_data_get_state(struct ndm_session * sess,ndmp9_error expect_err)392 int ndmca_test_data_get_state(struct ndm_session* sess, ndmp9_error expect_err)
393 {
394   struct ndmconn* conn = sess->plumb.data;
395   int rc;
396 
397   /* close previous test if there is one */
398   ndmca_test_close(sess);
399 
400   rc = ndmca_data_get_state(sess);
401 
402   rc = ndmca_test_check_expect(conn, rc, expect_err);
403 
404   return rc;
405 }
406 
ndmca_test_data_abort(struct ndm_session * sess,ndmp9_error expect_err)407 int ndmca_test_data_abort(struct ndm_session* sess, ndmp9_error expect_err)
408 {
409   struct ndmconn* conn = sess->plumb.data;
410   int rc;
411 
412   /* close previous test if there is one */
413   ndmca_test_close(sess);
414 
415   rc = ndmca_data_abort(sess);
416 
417   rc = ndmca_test_check_expect(conn, rc, expect_err);
418 
419   return rc;
420 }
421 
ndmca_test_data_stop(struct ndm_session * sess,ndmp9_error expect_err)422 int ndmca_test_data_stop(struct ndm_session* sess, ndmp9_error expect_err)
423 {
424   struct ndmconn* conn = sess->plumb.data;
425   int rc;
426 
427   /* close previous test if there is one */
428   ndmca_test_close(sess);
429 
430   rc = ndmca_data_stop(sess);
431 
432   rc = ndmca_test_check_expect(conn, rc, expect_err);
433 
434   return rc;
435 }
436 
437 
438 #endif /* !defined(NDMOS_OPTION_NO_CONTROL_AGENT) && \
439           !defined(NDMOS_OPTION_NO_TEST_AGENTS) */
440