/*
* Copyright (c) 1998,1999,2000
* Traakan, Inc., Los Altos, CA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Project: NDMJOB
* Ident: $Id: $
*
* Description:
*
********************************************************************
*
* NDMP Elements of a test-data session
*
* +-----+ ###########
* | Job |----># CONTROL #
* +-----+ # Agent #
* # #
* ###########
* | #
* +----------------+ #
* | control connection # CONTROL
* V # impersonates
* ############ # TAPE side of
* # DATA # # image stream
* # Agent # #
* +-----+ # +------+ # image #
* |FILES|====|butype|===================#
* +-----+ # +------+ # stream
* ############
*
*
********************************************************************
*
*/
#include "ndmagents.h"
#ifndef NDMOS_OPTION_NO_CONTROL_AGENT
extern int ndmca_td_wrapper (struct ndm_session *sess,
int (*func)(struct ndm_session *sess));
extern int ndmca_op_test_data (struct ndm_session *sess);
extern int ndmca_td_idle (struct ndm_session *sess);
extern int ndmca_td_listen (struct ndm_session *sess);
extern int ndmca_td_listen_subr (struct ndm_session *sess,
ndmp9_error expect_err,
ndmp9_addr_type addr_type);
extern int ndmca_test_check_data_state (struct ndm_session *sess,
ndmp9_data_state expected, int reason);
extern int ndmca_test_data_get_state (struct ndm_session *sess,
ndmp9_error expect_err);
extern int ndmca_test_data_abort (struct ndm_session *sess,
ndmp9_error expect_err);
extern int ndmca_test_data_stop (struct ndm_session *sess,
ndmp9_error expect_err);
int
ndmca_op_test_data (struct ndm_session *sess)
{
struct ndm_control_agent *ca = &sess->control_acb;
struct ndmconn * conn;
int (*save_call) (struct ndmconn *conn,
struct ndmp_xa_buf *xa);
int rc;
rc = ndmca_connect_data_agent(sess);
if (rc) {
ndmconn_destruct (sess->plumb.data);
return rc;
}
conn = sess->plumb.data;
save_call = conn->call;
conn->call = ndma_call_no_tattle;
/* perform query to find out about TCP and LOCAL support */
rc = ndmca_test_query_conn_types (sess, conn);
if (rc) return rc;
rc = ndmca_td_wrapper (sess, ndmca_td_idle);
if (sess->plumb.data->protocol_version >= 3) {
// version 3 and later adds LISTEN
rc = ndmca_td_wrapper (sess, ndmca_td_listen);
}
ndmca_test_done_series (sess, "test-data");
ca = &sess->control_acb;
if (ca->has_tcp_addr && ca->has_local_addr) {
ndmalogf (sess, "TEST", 0, "LOCAL and TCP addressing tested.");
} else if (ca->has_tcp_addr) {
ndmalogf (sess, "TEST", 0, "TCP addressing ONLY tested.");
} else if (ca->has_local_addr) {
ndmalogf (sess, "TEST", 0, "LOCAL addressing ONLY tested.");
} else {
ndmalogf (sess, "TEST", 0, "Neither TCP or LOCAL addressing tested.");
}
return 0;
}
int
ndmca_td_wrapper (struct ndm_session *sess,
int (*func)(struct ndm_session *sess))
{
int rc;
rc = (*func)(sess);
if (rc != 0) {
ndmalogf (sess, "Test", 1, "Failure");
}
ndmca_test_done_phase (sess);
/* clean up mess */
ndmca_test_log_note (sess, 2, "Cleaning up...");
rc = 0;
return rc;
}
int
ndmca_td_idle (struct ndm_session *sess)
{
int rc;
ndmca_test_phase (sess, "D-IDLE", "Data IDLE State Series");
rc = ndmca_test_check_data_state (sess, NDMP9_DATA_STATE_IDLE, 0);
if (rc) return rc;
rc = ndmca_test_data_abort (sess, NDMP9_ILLEGAL_STATE_ERR);
if (rc) return rc;
rc = ndmca_test_data_stop (sess, NDMP9_ILLEGAL_STATE_ERR);
if (rc) return rc;
return 0; /* pass */
}
#define NDMTEST_CALL(CONN) ndmca_test_call(CONN, xa, expect_err);
int
ndmca_test_data_listen (struct ndm_session *sess, ndmp9_error expect_err,
ndmp9_addr_type addr_type)
{
struct ndmconn * conn = sess->plumb.data;
struct ndm_control_agent *ca = &sess->control_acb;
int rc;
/* close previous test if there is one */
ndmca_test_close (sess);
switch (conn->protocol_version) {
default: return -1234;
#ifndef NDMOS_OPTION_NO_NDMP3
case NDMP3VER:
NDMC_WITH(ndmp3_data_listen, NDMP3VER)
request->addr_type = addr_type;
rc = NDMTEST_CALL(conn);
if (rc) return rc;
if (expect_err == NDMP9_NO_ERR
&& request->addr_type
!= reply->data_connection_addr.addr_type) {
/* TODO: use proper test format */
ndmalogf (sess, "Test", 1,
"DATA_LISTEN addr_type mismatch");
return -1;
}
ndmp_3to9_addr (&reply->data_connection_addr, &ca->data_addr);
NDMC_ENDWITH
break;
#endif /* !NDMOS_OPTION_NO_NDMP3 */
#ifndef NDMOS_OPTION_NO_NDMP4
case NDMP4VER:
NDMC_WITH(ndmp4_data_listen, NDMP4VER)
request->addr_type = addr_type;
rc = NDMTEST_CALL(conn);
if (rc) return rc;
if (expect_err == NDMP9_NO_ERR
&& request->addr_type
!= reply->connect_addr.addr_type) {
/* TODO: use proper test format */
ndmalogf (sess, "Test", 1,
"DATA_LISTEN addr_type mismatch");
return -1;
}
ndmp_4to9_addr (&reply->connect_addr, &ca->data_addr);
NDMC_ENDWITH
break;
#endif /* !NDMOS_OPTION_NO_NDMP4 */
}
return 0;
}
int
ndmca_td_listen (struct ndm_session *sess)
{
struct ndm_control_agent *ca = &sess->control_acb;
int rc;
ndmca_test_phase (sess, "D-LISTEN", "Data LISTEN State Series");
rc = ndmca_test_check_data_state (sess, NDMP9_DATA_STATE_IDLE, 0);
if (rc) return rc;
if (ca->has_tcp_addr) {
rc = ndmca_td_listen_subr (sess, NDMP9_NO_ERR, NDMP9_ADDR_TCP);
if (rc) return rc;
}
if (ca->has_local_addr) {
rc = ndmca_td_listen_subr (sess, NDMP9_NO_ERR, NDMP9_ADDR_LOCAL);
if (rc) return rc;
}
ndmca_test_done_phase (sess);
/*
* Bogus arguments
*/
ndmca_test_phase (sess, "D-LISTEN/bogus-args",
"Data LISTEN State Series w/ bogus args");
rc = ndmca_test_data_listen (sess, NDMP9_ILLEGAL_ARGS_ERR,
123);
if (rc) return rc;
ndmca_test_done_phase (sess);
return 0; /* pass */
}
int
ndmca_td_listen_subr (struct ndm_session *sess,
ndmp9_error expect_err,
ndmp9_addr_type addr_type)
{
int rc;
rc = ndmca_test_check_data_state (sess, NDMP9_DATA_STATE_IDLE, 0);
if (rc) return rc;
rc = ndmca_test_data_listen (sess, expect_err, addr_type);
if (rc) return rc;
if (expect_err != NDMP9_NO_ERR)
return 0; /* got expected error */
rc = ndmca_test_check_data_state (sess, NDMP9_DATA_STATE_LISTEN, 0);
if (rc) return rc;
rc = ndmca_test_data_listen (sess, NDMP9_ILLEGAL_STATE_ERR,
addr_type);
if (rc) return rc;
rc = ndmca_test_data_stop (sess, NDMP9_ILLEGAL_STATE_ERR);
if (rc) return rc;
rc = ndmca_test_data_abort (sess, NDMP9_NO_ERR);
if (rc) return rc;
rc = ndmca_test_check_data_state (sess,
NDMP9_DATA_STATE_HALTED, NDMP9_DATA_HALT_ABORTED);
if (rc) return rc;
rc = ndmca_test_data_stop (sess, NDMP9_NO_ERR);
if (rc) return rc;
rc = ndmca_test_check_data_state (sess, NDMP9_DATA_STATE_IDLE, 0);
if (rc) return rc;
return 0;
}
int
ndmca_test_check_data_state (struct ndm_session *sess,
ndmp9_data_state expected, int reason)
{
struct ndm_control_agent * ca = &sess->control_acb;
ndmp9_data_get_state_reply * ds = &ca->data_state;
int rc;
char * what;
char errbuf[100];
char tmpbuf[256];
/* close previous test if there is one */
ndmca_test_close (sess);
/* open new test */
ndmca_test_open (sess,
"data check",
ndmp9_data_state_to_str (expected));
strcpy (errbuf, "???");
what = "get_state";
rc = ndmca_data_get_state (sess);
if (rc) goto fail;
what = "state self-consistent";
/* make sure the sensed state is self consistent */
switch (ds->state) {
case NDMP9_DATA_STATE_IDLE:
case NDMP9_DATA_STATE_ACTIVE:
case NDMP9_DATA_STATE_LISTEN:
case NDMP9_DATA_STATE_CONNECTED:
if (ds->halt_reason != NDMP9_DATA_HALT_NA) {
strcpy (errbuf, "reason != NA");
goto fail;
}
break;
case NDMP9_DATA_STATE_HALTED:
break;
default:
strcpy (errbuf, "bogus state");
goto fail;
}
what = "state";
if (ds->state != expected) {
sprintf (errbuf, "expected %s got %s",
ndmp9_data_state_to_str (expected),
ndmp9_data_state_to_str (ds->state));
goto fail;
}
what = "reason";
switch (ds->state) {
case NDMP9_DATA_STATE_HALTED:
if (ds->halt_reason != (ndmp9_data_halt_reason)reason) {
sprintf (errbuf, "expected %s got %s",
ndmp9_data_halt_reason_to_str (reason),
ndmp9_data_halt_reason_to_str (ds->halt_reason));
goto fail;
}
break;
default:
break;
}
/* test passed */
ndmca_test_close (sess);
return 0;
fail:
/* test failed */
sprintf(tmpbuf, "%s: %s", what, errbuf);
ndmca_test_fail(sess, tmpbuf);
ndmca_test_close (sess);
return -1;
}
int
ndmca_test_data_get_state (struct ndm_session *sess, ndmp9_error expect_err)
{
struct ndmconn * conn = sess->plumb.data;
int rc;
/* close previous test if there is one */
ndmca_test_close (sess);
rc = ndmca_data_get_state (sess);
rc = ndmca_test_check_expect (conn, rc, expect_err);
return rc;
}
int
ndmca_test_data_abort (struct ndm_session *sess, ndmp9_error expect_err)
{
struct ndmconn * conn = sess->plumb.data;
int rc;
/* close previous test if there is one */
ndmca_test_close (sess);
rc = ndmca_data_abort (sess);
rc = ndmca_test_check_expect (conn, rc, expect_err);
return rc;
}
int
ndmca_test_data_stop (struct ndm_session *sess, ndmp9_error expect_err)
{
struct ndmconn * conn = sess->plumb.data;
int rc;
/* close previous test if there is one */
ndmca_test_close (sess);
rc = ndmca_data_stop (sess);
rc = ndmca_test_check_expect (conn, rc, expect_err);
return rc;
}
#endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */