xref: /titanic_52/usr/src/cmd/ndmpd/ndmp/ndmpd_data.c (revision 71269a2275bf5a143dad6461eee2710a344e7261)
1 /*
2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * BSD 3 Clause License
8  *
9  * Copyright (c) 2007, The Storage Networking Industry Association.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 	- Redistributions of source code must retain the above copyright
15  *	  notice, this list of conditions and the following disclaimer.
16  *
17  * 	- Redistributions in binary form must reproduce the above copyright
18  *	  notice, this list of conditions and the following disclaimer in
19  *	  the documentation and/or other materials provided with the
20  *	  distribution.
21  *
22  *	- Neither the name of The Storage Networking Industry Association (SNIA)
23  *	  nor the names of its contributors may be used to endorse or promote
24  *	  products derived from this software without specific prior written
25  *	  permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 /* Copyright (c) 2007, The Storage Networking Industry Association. */
40 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
41 
42 #include <sys/types.h>
43 #include <sys/param.h>
44 #include <sys/socket.h>
45 #include <netinet/in.h>
46 #include <errno.h>
47 #include <arpa/inet.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include "ndmpd_common.h"
51 #include "ndmpd.h"
52 
53 
54 static int ndmpd_data_error_send_v4(ndmpd_session_t *session,
55     ndmp_data_halt_reason reason);
56 static int ndmpd_data_error_send(ndmpd_session_t *session,
57     ndmp_data_halt_reason reason);
58 static void data_accept_connection_v3(void *cookie, int fd, ulong_t mode);
59 static int create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr,
60     ushort_t *port);
61 static ndmp_error data_connect_sock_v3(ndmpd_session_t *session, ulong_t addr,
62     ushort_t port);
63 static int discard_data_v3(ndmpd_session_t *session, ulong_t length);
64 static void nlp_release_job_stat(ndmpd_session_t *session);
65 static u_longlong_t ndmpd_data_get_info(ndmpd_session_t *session);
66 static ndmp_error start_backup_v3(ndmpd_session_t *session, char *bu_type,
67     ndmp_pval *env_val, ulong_t env_len);
68 static ndmp_error start_backup(ndmpd_session_t *session, char *bu_type,
69     ndmp_pval *env_val, ulong_t env_len);
70 static ndmp_error start_recover(ndmpd_session_t *session, char *bu_type,
71     ndmp_pval *env_val, ulong_t env_len, ndmp_name *nlist_val,
72     ulong_t nlist_len);
73 static ndmp_error start_recover_v3(ndmpd_session_t *session, char *bu_type,
74     ndmp_pval *env_val, ulong_t env_len, ndmp_name_v3 *nlist_val,
75     ulong_t nlist_len);
76 static ndmp_error start_backup(ndmpd_session_t *session, char *bu_type,
77     ndmp_pval *env_val, ulong_t env_len);
78 static ndmp_error start_recover(ndmpd_session_t *session, char *bu_type,
79     ndmp_pval *env_val, ulong_t env_len, ndmp_name *nlist_val,
80     ulong_t nlist_len);
81 static u_longlong_t ndmpd_data_get_info(ndmpd_session_t *session);
82 static void nlp_release_job_stat(ndmpd_session_t *session);
83 
84 
85 /*
86  * ************************************************************************
87  * NDMP V2 HANDLERS
88  * ************************************************************************
89  */
90 
91 /*
92  * ndmpd_data_get_state_v2
93  *
94  * Request handler. Returns current data state.
95  *
96  * Parameters:
97  *   connection (input) - connection handle.
98  *   body       (input) - request message body.
99  *
100  * Returns:
101  *   void
102  */
103 /*ARGSUSED*/
104 void
105 ndmpd_data_get_state_v2(ndmp_connection_t *connection, void *body)
106 {
107 	ndmp_data_get_state_reply_v2 reply;
108 	ndmpd_session_t *session = ndmp_get_client_data(connection);
109 
110 	reply.error = NDMP_NO_ERR;
111 	reply.operation = session->ns_data.dd_operation;
112 	reply.state = session->ns_data.dd_state;
113 	reply.halt_reason = session->ns_data.dd_halt_reason;
114 
115 	reply.est_time_remain =
116 	    session->ns_data.dd_module.dm_stats.ms_est_time_remaining;
117 	reply.est_bytes_remain =
118 	    long_long_to_quad(
119 	    session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining);
120 
121 	reply.bytes_processed =
122 	    long_long_to_quad(ndmpd_data_get_info(session));
123 
124 	reply.mover = session->ns_data.dd_mover;
125 	reply.read_offset = long_long_to_quad(session->ns_data.dd_read_offset);
126 	reply.read_length = long_long_to_quad(session->ns_data.dd_read_length);
127 
128 	ndmp_send_reply(connection, &reply,
129 	    "sending data_get_state reply");
130 }
131 
132 
133 /*
134  * ndmpd_data_start_backup_v2
135  *
136  * Request handler. Starts a backup.
137  *
138  * Parameters:
139  *   connection (input) - connection handle.
140  *   body       (input) - request message body.
141  *
142  * Returns:
143  *   void
144  */
145 void
146 ndmpd_data_start_backup_v2(ndmp_connection_t *connection, void *body)
147 {
148 	ndmp_data_start_backup_request_v2 *request;
149 	ndmp_data_start_backup_reply_v2 reply;
150 	ndmpd_session_t *session = ndmp_get_client_data(connection);
151 	ndmp_error err;
152 
153 	request = (ndmp_data_start_backup_request_v2 *)body;
154 
155 	reply.error = NDMP_NO_ERR;
156 	session->ns_data.dd_mover = request->mover;
157 
158 	err = start_backup(session, request->bu_type, request->env.env_val,
159 	    request->env.env_len);
160 
161 	/*
162 	 * start_backup sends the reply if the backup is successfully started.
163 	 * Otherwise, send the reply containing the error here.
164 	 */
165 	if (err != NDMP_NO_ERR) {
166 		NDMP_LOG(LOG_DEBUG, "err: %d", err);
167 		reply.error = err;
168 		ndmp_send_reply(connection, &reply,
169 		    "sending data_start_backup reply");
170 		ndmpd_data_cleanup(session);
171 	}
172 }
173 
174 
175 /*
176  * ndmpd_data_start_recover_v2
177  *
178  * Request handler. Starts a restore.
179  *
180  * Parameters:
181  *   connection (input) - connection handle.
182  *   body       (input) - request message body.
183  *
184  * Returns:
185  *   void
186  */
187 void
188 ndmpd_data_start_recover_v2(ndmp_connection_t *connection, void *body)
189 {
190 	ndmp_data_start_recover_request_v2 *request;
191 	ndmp_data_start_recover_reply_v2 reply;
192 	ndmpd_session_t *session = ndmp_get_client_data(connection);
193 	ndmp_error err;
194 
195 	request = (ndmp_data_start_recover_request_v2 *) body;
196 	session->ns_data.dd_mover = request->mover;
197 
198 	err = start_recover(session, request->bu_type, request->env.env_val,
199 	    request->env.env_len, request->nlist.nlist_val,
200 	    request->nlist.nlist_len);
201 	/*
202 	 * start_recover sends the reply if the recover is successfully started.
203 	 * Otherwise, send the reply containing the error here.
204 	 */
205 	if (err != NDMP_NO_ERR) {
206 		reply.error = err;
207 		ndmp_send_reply(connection, &reply,
208 		    "sending ndmp_data_start_recover_request_v2 reply");
209 		ndmpd_data_cleanup(session);
210 	}
211 }
212 
213 
214 /*
215  * ndmpd_data_get_env_v2
216  *
217  * Request handler. Returns the environment variable array sent
218  * with the backup request. This request may only be sent with
219  * a backup operation is in progress.
220  *
221  * Parameters:
222  *   connection (input) - connection handle.
223  *   body       (input) - request message body.
224  *
225  * Returns:
226  *   void
227  */
228 /*ARGSUSED*/
229 void
230 ndmpd_data_get_env_v2(ndmp_connection_t *connection, void *body)
231 {
232 	ndmp_data_get_env_reply reply;
233 	ndmpd_session_t *session = ndmp_get_client_data(connection);
234 
235 	(void) memset((void*)&reply, 0, sizeof (reply));
236 	if (session->ns_data.dd_operation != NDMP_DATA_OP_BACKUP) {
237 		NDMP_LOG(LOG_ERR, "Backup operation not active.");
238 		reply.error = NDMP_ILLEGAL_STATE_ERR;
239 		reply.env.env_len = 0;
240 	} else {
241 		reply.error = NDMP_NO_ERR;
242 		reply.env.env_len = session->ns_data.dd_env_len;
243 		reply.env.env_val = session->ns_data.dd_env;
244 	}
245 
246 	ndmp_send_reply(connection, &reply, "sending data_get_env reply");
247 }
248 
249 
250 /*
251  * ndmpd_data_stop_v2
252  *
253  * Request handler. Stops the current data operation.
254  *
255  * Parameters:
256  *   connection (input) - connection handle.
257  *   body       (input) - request message body.
258  *
259  * Returns:
260  *   void
261  */
262 /*ARGSUSED*/
263 void
264 ndmpd_data_stop_v2(ndmp_connection_t *connection, void *body)
265 {
266 	ndmp_data_stop_reply reply;
267 	ndmpd_session_t *session = ndmp_get_client_data(connection);
268 
269 	if (session->ns_data.dd_state != NDMP_DATA_STATE_HALTED) {
270 		NDMP_LOG(LOG_ERR, "Invalid state to process stop request.");
271 		reply.error = NDMP_ILLEGAL_STATE_ERR;
272 		ndmp_send_reply(connection, &reply,
273 		    "sending data_stop reply");
274 		return;
275 	}
276 	ndmp_waitfor_op(session);
277 	ndmpd_data_cleanup(session);
278 	ndmpd_file_history_cleanup(session, FALSE);
279 
280 	nlp_release_job_stat(session);
281 
282 	/* prepare for another data operation */
283 	(void) ndmpd_data_init(session);
284 	ndmpd_file_history_init(session);
285 
286 	reply.error = NDMP_NO_ERR;
287 	ndmp_send_reply(connection, &reply, "sending data_stop reply");
288 }
289 
290 
291 /*
292  * ndmpd_data_abort_v2
293  *
294  * Request handler. Aborts the current backup/restore. The operation
295  * state is not changed to the halted state until after the operation
296  * has actually been aborted and the notify_halt request has been sent.
297  *
298  * Parameters:
299  *   connection (input) - connection handle.
300  *   body       (input) - request message body.
301  *
302  * Returns:
303  *   void
304  */
305 /*ARGSUSED*/
306 void
307 ndmpd_data_abort_v2(ndmp_connection_t *connection, void *body)
308 {
309 	ndmp_data_abort_reply reply;
310 	ndmpd_session_t *session = ndmp_get_client_data(connection);
311 
312 	if (session->ns_data.dd_state == NDMP_DATA_STATE_IDLE ||
313 	    session->ns_data.dd_state == NDMP_DATA_STATE_HALTED) {
314 		NDMP_LOG(LOG_ERR, "Invalid state to process abort request.");
315 		reply.error = NDMP_ILLEGAL_STATE_ERR;
316 		ndmp_send_reply(connection, &reply,
317 		    "sending data_abort reply");
318 		return;
319 	}
320 	/*
321 	 * Don't go to HALTED state yet. Need to wait for data operation to
322 	 * abort. When this happens, ndmpd_done will get called and will
323 	 * perform the halt processing.
324 	 */
325 	session->ns_data.dd_abort = TRUE;
326 	(*session->ns_data.dd_module.dm_abort_func)(
327 	    session->ns_data.dd_module.dm_module_cookie);
328 
329 	reply.error = NDMP_NO_ERR;
330 	ndmp_send_reply(connection, &reply, "sending data_abort reply");
331 }
332 
333 /*
334  * ************************************************************************
335  * NDMP V3 HANDLERS
336  * ************************************************************************
337  */
338 
339 /*
340  * ndmpd_data_get_state_v3
341  *
342  * Request handler. Returns current data state.
343  *
344  * Parameters:
345  *   connection (input) - connection handle.
346  *   body       (input) - request message body.
347  *
348  * Returns:
349  *   void
350  */
351 /*ARGSUSED*/
352 void
353 ndmpd_data_get_state_v3(ndmp_connection_t *connection, void *body)
354 {
355 	ndmp_data_get_state_reply_v3 reply;
356 	ndmpd_session_t *session = ndmp_get_client_data(connection);
357 
358 	(void) memset((void*)&reply, 0, sizeof (reply));
359 
360 	reply.error = NDMP_NO_ERR;
361 	reply.invalid = NDMP_DATA_STATE_EST_BYTES_REMAIN_INVALID
362 	    | NDMP_DATA_STATE_EST_TIME_REMAIN_INVALID;
363 	reply.operation = session->ns_data.dd_operation;
364 	reply.state = session->ns_data.dd_state;
365 	reply.halt_reason = session->ns_data.dd_halt_reason;
366 
367 	if (reply.operation == NDMP_DATA_OP_BACKUP)
368 		reply.bytes_processed =
369 		    long_long_to_quad(
370 		    session->ns_data.dd_module.dm_stats.ms_bytes_processed);
371 	else
372 		reply.bytes_processed =
373 		    long_long_to_quad(ndmpd_data_get_info(session));
374 
375 	reply.est_bytes_remain = long_long_to_quad(0LL);
376 	reply.est_time_remain = 0;
377 	if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE)
378 		ndmp_copy_addr_v3(&reply.data_connection_addr,
379 		    &session->ns_data.dd_data_addr);
380 	reply.read_offset = long_long_to_quad(session->ns_data.dd_read_offset);
381 	reply.read_length = long_long_to_quad(session->ns_data.dd_read_length);
382 
383 	ndmp_send_reply(connection, &reply,
384 	    "sending ndmp_data_get_state_v3 reply");
385 }
386 
387 
388 /*
389  * ndmpd_data_start_backup_v3
390  *
391  * Request handler. Starts a backup.
392  *
393  * Parameters:
394  *   connection (input) - connection handle.
395  *   body       (input) - request message body.
396  *
397  * Returns:
398  *   void
399  */
400 void
401 ndmpd_data_start_backup_v3(ndmp_connection_t *connection, void *body)
402 {
403 	ndmp_data_start_backup_request_v3 *request;
404 	ndmp_data_start_backup_reply_v3 reply;
405 	ndmpd_session_t *session = ndmp_get_client_data(connection);
406 	ndmp_error err;
407 
408 	request = (ndmp_data_start_backup_request_v3 *)body;
409 
410 	(void) memset((void*)&reply, 0, sizeof (reply));
411 
412 	err = start_backup_v3(session, request->bu_type, request->env.env_val,
413 	    request->env.env_len);
414 
415 	/*
416 	 * start_backup_v3 sends the reply if the backup is
417 	 * successfully started.  Otherwise, send the reply
418 	 * containing the error here.
419 	 */
420 	if (err != NDMP_NO_ERR) {
421 		reply.error = err;
422 		ndmp_send_reply(connection, &reply,
423 		    "sending data_start_backup_v3 reply");
424 		ndmpd_data_cleanup(session);
425 	}
426 }
427 
428 
429 /*
430  * ndmpd_data_start_recover_v3
431  *
432  * Request handler. Starts a restore.
433  *
434  * Parameters:
435  *   connection (input) - connection handle.
436  *   body       (input) - request message body.
437  *
438  * Returns:
439  *   void
440  */
441 void
442 ndmpd_data_start_recover_v3(ndmp_connection_t *connection, void *body)
443 {
444 	ndmp_data_start_recover_request_v3 *request;
445 	ndmp_data_start_recover_reply_v3 reply;
446 	ndmpd_session_t *session = ndmp_get_client_data(connection);
447 	ndmp_error err;
448 
449 	request = (ndmp_data_start_recover_request_v3 *)body;
450 
451 	(void) memset((void*)&reply, 0, sizeof (reply));
452 
453 	err = start_recover_v3(session, request->bu_type, request->env.env_val,
454 	    request->env.env_len, request->nlist.nlist_val,
455 	    request->nlist.nlist_len);
456 
457 	/*
458 	 * start_recover_v3 sends the reply if the recover is
459 	 * successfully started.  Otherwise, send the reply
460 	 * containing the error here.
461 	 */
462 	if (err != NDMP_NO_ERR) {
463 		reply.error = err;
464 		ndmp_send_reply(connection, &reply,
465 		    "sending data_start_recover_v3 reply");
466 		ndmpd_data_error(session, NDMP_DATA_HALT_INTERNAL_ERROR);
467 		ndmpd_data_cleanup(session);
468 	}
469 }
470 
471 
472 /*
473  * ndmpd_data_abort_v3
474  *
475  * Request handler. Aborts the current backup/restore. The operation
476  * state is not changed to the halted state until after the operation
477  * has actually been aborted and the notify_halt request has been sent.
478  *
479  * Parameters:
480  *   connection (input) - connection handle.
481  *   body       (input) - request message body.
482  *
483  * Returns:
484  *   void
485  */
486 /*ARGSUSED*/
487 void
488 ndmpd_data_abort_v3(ndmp_connection_t *connection, void *body)
489 {
490 	ndmp_data_abort_reply reply;
491 	ndmpd_session_t *session = ndmp_get_client_data(connection);
492 
493 	switch (session->ns_data.dd_state) {
494 	case NDMP_DATA_STATE_IDLE:
495 		reply.error = NDMP_ILLEGAL_STATE_ERR;
496 		NDMP_LOG(LOG_ERR, "Invalid state to process abort request.");
497 		break;
498 
499 	case NDMP_DATA_STATE_ACTIVE:
500 		/*
501 		 * Don't go to HALTED state yet.  Need to wait for data
502 		 * operation to abort.  When this happens, ndmpd_done_v3
503 		 * will get called and will perform the halt processing.
504 		 */
505 		reply.error = NDMP_NO_ERR;
506 		session->ns_data.dd_abort = TRUE;
507 		if (session->ns_data.dd_module.dm_abort_func)
508 			(*session->ns_data.dd_module.dm_abort_func)(
509 			    session->ns_data.dd_module.dm_module_cookie);
510 		break;
511 
512 	case NDMP_DATA_STATE_HALTED:
513 	case NDMP_DATA_STATE_LISTEN:
514 	case NDMP_DATA_STATE_CONNECTED:
515 		reply.error = NDMP_NO_ERR;
516 		session->ns_data.dd_abort = TRUE;
517 		ndmpd_data_error(session, NDMP_DATA_HALT_ABORTED);
518 		break;
519 	default:
520 		reply.error = NDMP_ILLEGAL_STATE_ERR;
521 		NDMP_LOG(LOG_DEBUG, "Unknown data V3 state %d",
522 		    session->ns_data.dd_state);
523 	}
524 
525 	ndmp_send_reply(connection, &reply,
526 	    "sending data_abort_v3 reply");
527 }
528 
529 
530 /*
531  * ndmpd_data_stop_v3
532  *
533  * Request handler. Stops the current data operation.
534  *
535  * Parameters:
536  *   connection (input) - connection handle.
537  *   body       (input) - request message body.
538  *
539  * Returns:
540  *   void
541  */
542 /*ARGSUSED*/
543 void
544 ndmpd_data_stop_v3(ndmp_connection_t *connection, void *body)
545 {
546 	ndmp_data_stop_reply reply;
547 	ndmpd_session_t *session = ndmp_get_client_data(connection);
548 
549 	if (session->ns_data.dd_state != NDMP_DATA_STATE_HALTED) {
550 		NDMP_LOG(LOG_ERR, "Invalid state to process stop request.");
551 		reply.error = NDMP_ILLEGAL_STATE_ERR;
552 		ndmp_send_reply(connection, &reply,
553 		    "sending data_stop_v3 reply");
554 		return;
555 	}
556 	ndmp_waitfor_op(session);
557 	ndmpd_data_cleanup(session);
558 	ndmpd_file_history_cleanup(session, FALSE);
559 
560 	/* prepare for another data operation */
561 	(void) ndmpd_data_init(session);
562 	ndmpd_file_history_init(session);
563 
564 	reply.error = NDMP_NO_ERR;
565 	ndmp_send_reply(connection, &reply,
566 	    "sending data_stop_v3 reply");
567 }
568 
569 
570 /*
571  * ndmpd_data_listen_v3
572  *
573  * Request handler. Configures the server to listen for a connection
574  * from a remote mover.
575  *
576  * Parameters:
577  *   connection (input) - connection handle.
578  *   body       (input) - request message body.
579  *
580  * Returns:
581  *   void
582  */
583 void
584 ndmpd_data_listen_v3(ndmp_connection_t *connection, void *body)
585 {
586 	ndmp_data_listen_request_v3 *request;
587 	ndmp_data_listen_reply_v3 reply;
588 	ndmpd_session_t *session = ndmp_get_client_data(connection);
589 	ulong_t addr;
590 	ushort_t port;
591 
592 	request = (ndmp_data_listen_request_v3 *)body;
593 
594 	(void) memset((void*)&reply, 0, sizeof (reply));
595 
596 	if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
597 		reply.error = NDMP_ILLEGAL_STATE_ERR;
598 		NDMP_LOG(LOG_ERR,
599 		    "Invalid internal data state to process listen request.");
600 	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
601 		reply.error = NDMP_ILLEGAL_STATE_ERR;
602 		NDMP_LOG(LOG_ERR,
603 		    "Invalid mover state to process listen request.");
604 	} else {
605 		reply.error = NDMP_NO_ERR;
606 	}
607 
608 	if (reply.error != NDMP_NO_ERR) {
609 		ndmp_send_reply(connection, &reply,
610 		    "ndmp_data_listen_request_v3 reply");
611 		return;
612 	}
613 
614 	switch (request->addr_type) {
615 	case NDMP_ADDR_LOCAL:
616 		reply.data_connection_addr.addr_type = request->addr_type;
617 		session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_LOCAL;
618 		break;
619 	case NDMP_ADDR_TCP:
620 		if (create_listen_socket_v3(session, &addr, &port) < 0) {
621 			reply.error = NDMP_IO_ERR;
622 			break;
623 		}
624 
625 		reply.error = NDMP_NO_ERR;
626 		reply.data_connection_addr.addr_type = request->addr_type;
627 		reply.data_connection_addr.tcp_ip_v3 = htonl(addr);
628 		reply.data_connection_addr.tcp_port_v3 = htons(port);
629 		session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_TCP;
630 		session->ns_data.dd_data_addr.tcp_ip_v3 = addr;
631 		session->ns_data.dd_data_addr.tcp_port_v3 = ntohs(port);
632 		NDMP_LOG(LOG_DEBUG, "listen_socket: %d",
633 		    session->ns_data.dd_listen_sock);
634 		break;
635 
636 	default:
637 		NDMP_LOG(LOG_DEBUG, "Invalid address type: %d",
638 		    request->addr_type);
639 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
640 		break;
641 	}
642 
643 	if (reply.error == NDMP_NO_ERR)
644 		session->ns_data.dd_state = NDMP_DATA_STATE_LISTEN;
645 
646 	ndmp_send_reply(connection, &reply,
647 	    "ndmp_data_listen_request_v3 reply");
648 }
649 
650 
651 /*
652  * ndmpd_data_connect_v3
653  *
654  * Request handler. Connects the data server to either a local
655  * or remote mover.
656  *
657  * Parameters:
658  *   connection (input) - connection handle.
659  *   body       (input) - request message body.
660  *
661  * Returns:
662  *   void
663  */
664 void
665 ndmpd_data_connect_v3(ndmp_connection_t *connection, void *body)
666 {
667 	ndmp_data_connect_request_v3 *request;
668 	ndmp_data_connect_reply_v3 reply;
669 	ndmpd_session_t *session = ndmp_get_client_data(connection);
670 
671 	request = (ndmp_data_connect_request_v3 *)body;
672 
673 	(void) memset((void*)&reply, 0, sizeof (reply));
674 
675 	if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
676 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
677 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
678 		    request->addr.addr_type);
679 	} else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
680 		reply.error = NDMP_ILLEGAL_STATE_ERR;
681 		NDMP_LOG(LOG_ERR, "Invalid state to process connect request.");
682 	} else {
683 		reply.error = NDMP_NO_ERR;
684 	}
685 
686 	if (reply.error != NDMP_NO_ERR) {
687 		ndmp_send_reply(connection, &reply,
688 		    "sending ndmp_data_connect_v3 reply");
689 		return;
690 	}
691 
692 	switch (request->addr.addr_type) {
693 	case NDMP_ADDR_LOCAL:
694 		/*
695 		 * Verify that the mover is listening for a
696 		 * local connection
697 		 */
698 		if (session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN ||
699 		    session->ns_mover.md_listen_sock != -1) {
700 			reply.error = NDMP_ILLEGAL_STATE_ERR;
701 			NDMP_LOG(LOG_ERR,
702 			    "Mover is not in local listen state.");
703 		} else {
704 			session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
705 		}
706 		break;
707 
708 	case NDMP_ADDR_TCP:
709 		reply.error = data_connect_sock_v3(session,
710 		    request->addr.tcp_ip_v3, request->addr.tcp_port_v3);
711 		break;
712 
713 	default:
714 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
715 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
716 		    request->addr.addr_type);
717 	}
718 
719 	if (reply.error == NDMP_NO_ERR)
720 		session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
721 
722 	ndmp_send_reply(connection, &reply,
723 	    "sending ndmp_data_connect_v3 reply");
724 }
725 
726 
727 /*
728  * ************************************************************************
729  * NDMP V4 HANDLERS
730  * ************************************************************************
731  */
732 
733 /*
734  * ndmpd_data_get_env_v4
735  *
736  * Request handler. Returns the environment variable array sent
737  * with the backup request. This request may only be sent with
738  * a backup operation is in progress.
739  *
740  * Parameters:
741  *   connection (input) - connection handle.
742  *   body       (input) - request message body.
743  *
744  * Returns:
745  *   void
746  */
747 /*ARGSUSED*/
748 void
749 ndmpd_data_get_env_v4(ndmp_connection_t *connection, void *body)
750 {
751 	ndmp_data_get_env_reply reply;
752 	ndmpd_session_t *session = ndmp_get_client_data(connection);
753 
754 	(void) memset((void*)&reply, 0, sizeof (reply));
755 
756 	if (session->ns_data.dd_state != NDMP_DATA_STATE_ACTIVE &&
757 	    session->ns_data.dd_state != NDMP_DATA_STATE_HALTED) {
758 		NDMP_LOG(LOG_ERR, "Invalid state for the data server.");
759 		reply.error = NDMP_ILLEGAL_STATE_ERR;
760 		reply.env.env_len = 0;
761 	} else if (session->ns_data.dd_operation != NDMP_DATA_OP_BACKUP) {
762 		NDMP_LOG(LOG_ERR, "Backup operation not active.");
763 		reply.error = NDMP_ILLEGAL_STATE_ERR;
764 		reply.env.env_len = 0;
765 	} else {
766 		reply.error = NDMP_NO_ERR;
767 		reply.env.env_len = session->ns_data.dd_env_len;
768 		reply.env.env_val = session->ns_data.dd_env;
769 	}
770 
771 	ndmp_send_reply(connection, &reply, "sending data_get_env reply");
772 }
773 
774 /*
775  * ndmpd_data_get_state_v4
776  *
777  * Request handler. Returns current data state.
778  *
779  * Parameters:
780  *   connection (input) - connection handle.
781  *   body       (input) - request message body.
782  *
783  * Returns:
784  *   void
785  */
786 /*ARGSUSED*/
787 void
788 ndmpd_data_get_state_v4(ndmp_connection_t *connection, void *body)
789 {
790 	ndmp_data_get_state_reply_v4 reply;
791 	ndmpd_session_t *session = ndmp_get_client_data(connection);
792 
793 	(void) memset((void*)&reply, 0, sizeof (reply));
794 
795 	reply.error = NDMP_NO_ERR;
796 	reply.unsupported = NDMP_DATA_STATE_EST_BYTES_REMAIN_INVALID
797 	    | NDMP_DATA_STATE_EST_TIME_REMAIN_INVALID;
798 	reply.operation = session->ns_data.dd_operation;
799 	reply.state = session->ns_data.dd_state;
800 	reply.halt_reason = session->ns_data.dd_halt_reason;
801 
802 	if (reply.operation == NDMP_DATA_OP_BACKUP)
803 		reply.bytes_processed = long_long_to_quad(
804 		    session->ns_data.dd_module.dm_stats.ms_bytes_processed);
805 	else
806 		reply.bytes_processed =
807 		    long_long_to_quad(ndmpd_data_get_info(session));
808 
809 	reply.est_bytes_remain = long_long_to_quad(0LL);
810 	reply.est_time_remain = 0;
811 	if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE)
812 		ndmp_copy_addr_v4(&reply.data_connection_addr,
813 		    &session->ns_data.dd_data_addr_v4);
814 
815 	reply.read_offset = long_long_to_quad(session->ns_data.dd_read_offset);
816 	reply.read_length = long_long_to_quad(session->ns_data.dd_read_length);
817 
818 	ndmp_send_reply(connection, &reply,
819 	    "sending ndmp_data_get_state_v4 reply");
820 	free(reply.data_connection_addr.tcp_addr_v4);
821 }
822 
823 
824 /*
825  * ndmpd_data_connect_v4
826  *
827  * Request handler. Connects the data server to either a local
828  * or remote mover.
829  *
830  * Parameters:
831  *   connection (input) - connection handle.
832  *   body       (input) - request message body.
833  *
834  * Returns:
835  *   void
836  */
837 void
838 ndmpd_data_connect_v4(ndmp_connection_t *connection, void *body)
839 {
840 	ndmp_data_connect_request_v4 *request;
841 	ndmp_data_connect_reply_v4 reply;
842 	ndmpd_session_t *session = ndmp_get_client_data(connection);
843 
844 	request = (ndmp_data_connect_request_v4 *)body;
845 
846 	(void) memset((void*)&reply, 0, sizeof (reply));
847 
848 	if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
849 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
850 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
851 		    request->addr.addr_type);
852 	} else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
853 		reply.error = NDMP_ILLEGAL_STATE_ERR;
854 		NDMP_LOG(LOG_ERR, "Invalid state to process connect request.");
855 	} else {
856 		reply.error = NDMP_NO_ERR;
857 	}
858 
859 	if (reply.error != NDMP_NO_ERR) {
860 		ndmp_send_reply(connection, &reply,
861 		    "sending ndmp_data_connect_v4 reply");
862 		return;
863 	}
864 
865 	switch (request->addr.addr_type) {
866 	case NDMP_ADDR_LOCAL:
867 		/*
868 		 * Verify that the mover is listening for a
869 		 * local connection
870 		 */
871 		if (session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN ||
872 		    session->ns_mover.md_listen_sock != -1) {
873 			reply.error = NDMP_ILLEGAL_STATE_ERR;
874 			NDMP_LOG(LOG_ERR,
875 			    "Mover is not in local listen state.");
876 		} else {
877 			session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
878 		}
879 		break;
880 
881 	case NDMP_ADDR_TCP:
882 		reply.error = data_connect_sock_v3(session,
883 		    request->addr.tcp_ip_v4(0), request->addr.tcp_port_v4(0));
884 		break;
885 
886 	default:
887 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
888 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
889 		    request->addr.addr_type);
890 	}
891 
892 	if (reply.error == NDMP_NO_ERR)
893 		session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
894 
895 	ndmp_send_reply(connection, &reply,
896 	    "sending ndmp_data_connect_v4 reply");
897 }
898 
899 /*
900  * ndmpd_data_listen_v4
901  *
902  * Request handler. Configures the server to listen for a connection
903  * from a remote mover.
904  *
905  * Parameters:
906  *   connection (input) - connection handle.
907  *   body       (input) - request message body.
908  *
909  * Returns:
910  *   void
911  */
912 void
913 ndmpd_data_listen_v4(ndmp_connection_t *connection, void *body)
914 {
915 	ndmp_data_listen_request_v4 *request;
916 	ndmp_data_listen_reply_v4 reply;
917 	ndmpd_session_t *session = ndmp_get_client_data(connection);
918 	ulong_t addr;
919 	ushort_t port;
920 
921 	request = (ndmp_data_listen_request_v4 *)body;
922 
923 	(void) memset((void*)&reply, 0, sizeof (reply));
924 
925 	if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
926 		reply.error = NDMP_ILLEGAL_STATE_ERR;
927 		NDMP_LOG(LOG_ERR,
928 		    "Invalid internal data state to process listen request.");
929 	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
930 		reply.error = NDMP_ILLEGAL_STATE_ERR;
931 		NDMP_LOG(LOG_ERR,
932 		    "Invalid mover state to process listen request.");
933 	} else {
934 		reply.error = NDMP_NO_ERR;
935 	}
936 
937 	if (reply.error != NDMP_NO_ERR) {
938 		ndmp_send_reply(connection, &reply,
939 		    "ndmp_data_listen_request_v4 reply");
940 		return;
941 	}
942 
943 	switch (request->addr_type) {
944 	case NDMP_ADDR_LOCAL:
945 		reply.connect_addr.addr_type = request->addr_type;
946 		session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_LOCAL;
947 		break;
948 	case NDMP_ADDR_TCP:
949 		if (create_listen_socket_v3(session, &addr, &port) < 0) {
950 			reply.error = NDMP_IO_ERR;
951 			break;
952 		}
953 
954 		reply.error = NDMP_NO_ERR;
955 		reply.connect_addr.addr_type = request->addr_type;
956 		reply.connect_addr.tcp_addr_v4 =
957 		    ndmp_malloc(sizeof (ndmp_tcp_addr_v4));
958 
959 		reply.connect_addr.tcp_ip_v4(0) = htonl(addr);
960 		reply.connect_addr.tcp_port_v4(0) = htons(port);
961 		reply.connect_addr.tcp_len_v4 = 1;
962 
963 		session->ns_data.dd_data_addr_v4.addr_type = NDMP_ADDR_TCP;
964 		session->ns_data.dd_data_addr_v4.tcp_addr_v4 =
965 		    ndmp_malloc(sizeof (ndmp_tcp_addr_v4));
966 
967 		session->ns_data.dd_data_addr_v4.tcp_ip_v4(0) = addr;
968 		session->ns_data.dd_data_addr_v4.tcp_port_v4(0) = ntohs(port);
969 		session->ns_data.dd_data_addr_v4.tcp_len_v4 = 1;
970 
971 		/* Copy that to data_addr for compatibility */
972 		session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_TCP;
973 		session->ns_data.dd_data_addr.tcp_ip_v3 = addr;
974 		session->ns_data.dd_data_addr.tcp_port_v3 = ntohs(port);
975 		NDMP_LOG(LOG_DEBUG, "listen_socket: %d",
976 		    session->ns_data.dd_listen_sock);
977 		break;
978 
979 	default:
980 		NDMP_LOG(LOG_DEBUG, "Invalid address type: %d",
981 		    request->addr_type);
982 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
983 		break;
984 	}
985 
986 	if (reply.error == NDMP_NO_ERR)
987 		session->ns_data.dd_state = NDMP_DATA_STATE_LISTEN;
988 
989 	ndmp_send_reply(connection, &reply,
990 	    "ndmp_data_listen_request_v4 reply");
991 }
992 
993 
994 /*
995  * ndmpd_data_start_recover_filehist_v4
996  *
997  * Request handler. Recovers the file history (not supported yet)
998  * This command has an optional support in V4.
999  *
1000  * Parameters:
1001  *   connection (input) - connection handle.
1002  *   body       (input) - request message body.
1003  *
1004  * Returns:
1005  *   void
1006  */
1007 /*ARGSUSED*/
1008 void
1009 ndmpd_data_start_recover_filehist_v4(ndmp_connection_t *connection, void *body)
1010 {
1011 	ndmp_data_start_recover_filehist_reply_v4 reply;
1012 
1013 	NDMP_LOG(LOG_DEBUG, "Request not supported");
1014 	reply.error = NDMP_NOT_SUPPORTED_ERR;
1015 
1016 	ndmp_send_reply(connection, &reply,
1017 	    "sending ndmp_data_start_recover_filehist_reply_v4 reply");
1018 }
1019 
1020 /*
1021  * ************************************************************************
1022  * LOCALS
1023  * ************************************************************************
1024  */
1025 
1026 /*
1027  * ndmpd_data_error_send
1028  *
1029  * This function sends the notify message to the client.
1030  *
1031  * Parameters:
1032  *   session (input) - session pointer.
1033  *   reason  (input) - halt reason.
1034  *
1035  * Returns:
1036  *   Error code
1037  */
1038 /*ARGSUSED*/
1039 static int
1040 ndmpd_data_error_send(ndmpd_session_t *session, ndmp_data_halt_reason reason)
1041 {
1042 	ndmp_notify_data_halted_request req;
1043 
1044 	req.reason = session->ns_data.dd_halt_reason;
1045 	req.text_reason = "";
1046 
1047 	return (ndmp_send_request(session->ns_connection,
1048 	    NDMP_NOTIFY_DATA_HALTED, NDMP_NO_ERR, &req, 0));
1049 }
1050 
1051 
1052 /*
1053  * ndmpd_data_error_send_v4
1054  *
1055  * This function sends the notify message to the client.
1056  *
1057  * Parameters:
1058  *   session (input) - session pointer.
1059  *   reason  (input) - halt reason.
1060  *
1061  * Returns:
1062  *   Error code
1063  */
1064 /*ARGSUSED*/
1065 static int
1066 ndmpd_data_error_send_v4(ndmpd_session_t *session, ndmp_data_halt_reason reason)
1067 {
1068 	ndmp_notify_data_halted_request_v4 req;
1069 
1070 	req.reason = session->ns_data.dd_halt_reason;
1071 
1072 	return ndmp_send_request(session->ns_connection,
1073 	    NDMP_NOTIFY_DATA_HALTED, NDMP_NO_ERR, &req, 0);
1074 }
1075 
1076 
1077 /*
1078  * ndmpd_data_error
1079  *
1080  * This function is called when a data error has been detected.
1081  * A notify message is sent to the client and the data server is
1082  * placed into the halted state.
1083  *
1084  * Parameters:
1085  *   session (input) - session pointer.
1086  *   reason  (input) - halt reason.
1087  *
1088  * Returns:
1089  *   void
1090  */
1091 void
1092 ndmpd_data_error(ndmpd_session_t *session, ndmp_data_halt_reason reason)
1093 {
1094 	if (session->ns_data.dd_state == NDMP_DATA_STATE_IDLE ||
1095 	    session->ns_data.dd_state == NDMP_DATA_STATE_HALTED)
1096 		return;
1097 
1098 	if (session->ns_data.dd_operation == NDMP_DATA_OP_BACKUP) {
1099 		/*
1100 		 * Send/discard any buffered file history data.
1101 		 */
1102 		ndmpd_file_history_cleanup(session,
1103 		    (reason == NDMP_DATA_HALT_SUCCESSFUL ? TRUE : FALSE));
1104 
1105 		/*
1106 		 * If mover local and successful backup, write any
1107 		 * remaining buffered data to tape.
1108 		 */
1109 		if (session->ns_data.dd_data_addr.addr_type
1110 		    == NDMP_ADDR_LOCAL && reason == NDMP_DATA_HALT_SUCCESSFUL)
1111 			(void) ndmpd_local_write_v3(session, 0, 0);
1112 	}
1113 
1114 	session->ns_data.dd_state = NDMP_DATA_STATE_HALTED;
1115 	session->ns_data.dd_halt_reason = reason;
1116 
1117 	if (session->ns_protocol_version == NDMPV4) {
1118 		if (ndmpd_data_error_send_v4(session, reason) < 0)
1119 			NDMP_LOG(LOG_DEBUG,
1120 			    "Error sending notify_data_halted request");
1121 	} else {
1122 		if (ndmpd_data_error_send(session, reason) < 0)
1123 			NDMP_LOG(LOG_DEBUG,
1124 			    "Error sending notify_data_halted request");
1125 	}
1126 
1127 	if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_TCP) {
1128 		if (session->ns_data.dd_sock != -1) {
1129 			(void) ndmpd_remove_file_handler(session,
1130 			    session->ns_data.dd_sock);
1131 			/*
1132 			 * ndmpcopy: we use the same socket for the mover,
1133 			 * so expect to close when mover is done!
1134 			 */
1135 			if (session->ns_data.dd_sock !=
1136 			    session->ns_mover.md_sock)
1137 				(void) close(session->ns_data.dd_sock);
1138 
1139 			session->ns_data.dd_sock = -1;
1140 		}
1141 		if (session->ns_data.dd_listen_sock != -1) {
1142 			(void) ndmpd_remove_file_handler(session,
1143 			    session->ns_data.dd_listen_sock);
1144 
1145 			(void) close(session->ns_data.dd_listen_sock);
1146 			session->ns_data.dd_listen_sock = -1;
1147 		}
1148 	} else {
1149 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
1150 	}
1151 }
1152 
1153 
1154 /*
1155  * data_accept_connection_v3
1156  *
1157  * Accept a data connection from a remote mover.
1158  * Called by ndmpd_select when a connection is pending on
1159  * the data listen socket.
1160  *
1161  * Parameters:
1162  *   cookie  (input) - session pointer.
1163  *   fd      (input) - file descriptor.
1164  *   mode    (input) - select mode.
1165  *
1166  * Returns:
1167  *   void
1168  */
1169 /*ARGSUSED*/
1170 static void
1171 data_accept_connection_v3(void *cookie, int fd, ulong_t mode)
1172 {
1173 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
1174 	int from_len;
1175 	struct sockaddr_in from;
1176 	int flag = 1;
1177 
1178 	from_len = sizeof (from);
1179 	session->ns_data.dd_sock = accept(fd, (struct sockaddr *)&from,
1180 	    &from_len);
1181 
1182 	NDMP_LOG(LOG_DEBUG, "sock fd: %d",
1183 	    session->ns_data.dd_sock);
1184 	NDMP_LOG(LOG_DEBUG, "sin: port %d addr %s",
1185 	    ntohs(from.sin_port),
1186 	    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)));
1187 
1188 	(void) ndmpd_remove_file_handler(session, fd);
1189 	(void) close(session->ns_data.dd_listen_sock);
1190 	session->ns_data.dd_listen_sock = -1;
1191 
1192 	if (session->ns_data.dd_sock < 0) {
1193 		NDMP_LOG(LOG_DEBUG, "Accept error: %m");
1194 		ndmpd_data_error(session, NDMP_DATA_HALT_CONNECT_ERROR);
1195 		return;
1196 	}
1197 
1198 	/*
1199 	 * Save the peer address.
1200 	 */
1201 	session->ns_data.dd_data_addr.tcp_ip_v3 = from.sin_addr.s_addr;
1202 	session->ns_data.dd_data_addr.tcp_port_v3 = ntohs(from.sin_port);
1203 
1204 	/*
1205 	 * Set the parameter of the new socket.
1206 	 */
1207 	(void) setsockopt(session->ns_data.dd_sock, SOL_SOCKET, SO_KEEPALIVE,
1208 	    &flag, sizeof (flag));
1209 	ndmp_set_socket_nodelay(session->ns_data.dd_sock);
1210 	if (ndmp_sbs > 0)
1211 		ndmp_set_socket_snd_buf(session->ns_data.dd_sock,
1212 		    ndmp_sbs * KILOBYTE);
1213 	if (ndmp_rbs > 0)
1214 		ndmp_set_socket_rcv_buf(session->ns_data.dd_sock,
1215 		    ndmp_rbs * KILOBYTE);
1216 
1217 	session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
1218 }
1219 
1220 
1221 /*
1222  * create_listen_socket_v3
1223  *
1224  * Creates the data sockets for listening for a remote mover/data
1225  * incoming connections.
1226  */
1227 static int
1228 create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
1229 {
1230 	session->ns_data.dd_listen_sock = ndmp_create_socket(addr, port);
1231 	if (session->ns_data.dd_listen_sock < 0)
1232 		return (-1);
1233 
1234 	/*
1235 	 * Add a file handler for the listen socket.
1236 	 * ndmpd_select will call data_accept_connection when a
1237 	 * connection is ready to be accepted.
1238 	 */
1239 	if (ndmpd_add_file_handler(session, (void*)session,
1240 	    session->ns_data.dd_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
1241 	    data_accept_connection_v3) < 0) {
1242 		(void) close(session->ns_data.dd_listen_sock);
1243 		session->ns_data.dd_listen_sock = -1;
1244 		return (-1);
1245 	}
1246 	NDMP_LOG(LOG_DEBUG, "addr: %s:%d",
1247 	    inet_ntoa(IN_ADDR(*addr)), ntohs(*port));
1248 
1249 	return (0);
1250 }
1251 
1252 
1253 /*
1254  * data_connect_sock_v3
1255  *
1256  * Connect the data interface socket to the specified ip/port
1257  *
1258  * Parameters:
1259  *   session (input) - session pointer.
1260  *   addr    (input) - IP address
1261  *   port    (input) - port number
1262  *
1263  * Returns:
1264  *   NDMP_NO_ERR - backup successfully started.
1265  *   otherwise - error code of backup start error.
1266  */
1267 static ndmp_error
1268 data_connect_sock_v3(ndmpd_session_t *session, ulong_t addr, ushort_t port)
1269 {
1270 	int sock;
1271 
1272 	sock = ndmp_connect_sock_v3(addr, port);
1273 	if (sock < 0)
1274 		return (NDMP_CONNECT_ERR);
1275 
1276 	session->ns_data.dd_sock = sock;
1277 	session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_TCP;
1278 	session->ns_data.dd_data_addr.tcp_ip_v3 = ntohl(addr);
1279 	session->ns_data.dd_data_addr.tcp_port_v3 = port;
1280 
1281 	return (NDMP_NO_ERR);
1282 }
1283 
1284 
1285 /*
1286  * start_backup_v3
1287  *
1288  * Start the backup work
1289  *
1290  * Parameters:
1291  *   session (input) - session pointer.
1292  *   bu_type (input) - backup type.
1293  *   env_val (input) - environment variable array.
1294  *   env_len (input) - length of env_val.
1295  *
1296  * Returns:
1297  *   NDMP_NO_ERR - backup successfully started.
1298  *   otherwise - error code of backup start error.
1299  */
1300 static ndmp_error
1301 start_backup_v3(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val,
1302     ulong_t env_len)
1303 {
1304 	int err;
1305 	ndmp_lbr_params_t *nlp;
1306 	ndmpd_module_params_t *params;
1307 	ndmp_data_start_backup_reply_v3 reply;
1308 
1309 	(void) memset((void*)&reply, 0, sizeof (reply));
1310 
1311 	if (session->ns_data.dd_state != NDMP_DATA_STATE_CONNECTED) {
1312 		NDMP_LOG(LOG_ERR,
1313 		    "Can't start new backup in current state.");
1314 		NDMP_LOG(LOG_ERR,
1315 		    "Connection to the mover is not established.");
1316 		return (NDMP_ILLEGAL_STATE_ERR);
1317 	}
1318 
1319 	if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_LOCAL) {
1320 		if (session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
1321 			NDMP_LOG(LOG_ERR, "Write protected device.");
1322 			return (NDMP_WRITE_PROTECT_ERR);
1323 		}
1324 	}
1325 
1326 	if (strcmp(bu_type, NDMP_DUMP_TYPE) != 0 &&
1327 	    strcmp(bu_type, NDMP_TAR_TYPE) != 0) {
1328 		NDMP_LOG(LOG_ERR, "Invalid backup type: %s.", bu_type);
1329 		NDMP_LOG(LOG_ERR, "Supported backup types are tar and dump.");
1330 		return (NDMP_ILLEGAL_ARGS_ERR);
1331 	}
1332 
1333 	err = ndmpd_save_env(session, env_val, env_len);
1334 	if (err != NDMP_NO_ERR)
1335 		return (err);
1336 
1337 	nlp = ndmp_get_nlp(session);
1338 	NDMP_FREE(nlp->nlp_params);
1339 	params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t));
1340 	if (!params)
1341 		return (NDMP_NO_MEM_ERR);
1342 
1343 	params->mp_daemon_cookie = (void *)session;
1344 	params->mp_module_cookie = &session->ns_data.dd_module.dm_module_cookie;
1345 	params->mp_protocol_version = session->ns_protocol_version;
1346 	params->mp_operation = NDMP_DATA_OP_BACKUP;
1347 	params->mp_get_env_func = ndmpd_api_get_env;
1348 	params->mp_add_env_func = ndmpd_api_add_env;
1349 	params->mp_set_env_func = ndmpd_api_set_env;
1350 	params->mp_get_name_func = 0;
1351 	params->mp_dispatch_func = ndmpd_api_dispatch;
1352 	params->mp_done_func = ndmpd_api_done_v3;
1353 	if (session->ns_protocol_version == NDMPV4)
1354 		params->mp_log_func_v3 = ndmpd_api_log_v4;
1355 	else
1356 		params->mp_log_func_v3 = ndmpd_api_log_v3;
1357 
1358 	params->mp_add_file_handler_func = ndmpd_api_add_file_handler;
1359 	params->mp_remove_file_handler_func = ndmpd_api_remove_file_handler;
1360 	params->mp_write_func = ndmpd_api_write_v3;
1361 	params->mp_read_func = 0;
1362 	params->mp_file_recovered_func = 0;
1363 	params->mp_stats = &session->ns_data.dd_module.dm_stats;
1364 	session->ns_data.dd_module.dm_module_cookie = 0;
1365 
1366 	if (strcmp(bu_type, NDMP_DUMP_TYPE) == 0) {
1367 		NLP_SET(nlp, NLPF_DUMP);
1368 		params->mp_file_history_path_func = 0;
1369 		params->mp_file_history_dir_func =
1370 		    ndmpd_api_file_history_dir_v3;
1371 		params->mp_file_history_node_func =
1372 		    ndmpd_api_file_history_node_v3;
1373 	} else if (strcmp(bu_type, NDMP_TAR_TYPE) == 0) {
1374 		NLP_SET(nlp, NLPF_TAR);
1375 		params->mp_file_history_path_func =
1376 		    ndmpd_api_file_history_file_v3;
1377 		params->mp_file_history_dir_func = 0;
1378 		params->mp_file_history_node_func = 0;
1379 	} else {
1380 		NLP_UNSET(nlp, NLPF_DUMP);
1381 		NLP_UNSET(nlp, NLPF_TAR);
1382 	}
1383 
1384 	session->ns_data.dd_module.dm_start_func = ndmpd_tar_backup_starter_v3;
1385 	session->ns_data.dd_module.dm_abort_func = ndmpd_tar_backup_abort_v3;
1386 
1387 	session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
1388 	session->ns_data.dd_module.dm_stats.ms_est_time_remaining  = 0;
1389 	session->ns_data.dd_nlist_v3 = 0;
1390 	session->ns_data.dd_nlist_len = 0;
1391 	session->ns_data.dd_bytes_left_to_read = 0;
1392 	session->ns_data.dd_position = 0;
1393 	session->ns_data.dd_discard_length = 0;
1394 	session->ns_data.dd_read_offset = 0;
1395 	session->ns_data.dd_read_length = 0;
1396 
1397 	reply.error = ndmp_backup_get_params_v3(session, params);
1398 	if (reply.error != NDMP_NO_ERR) {
1399 		NDMP_LOG(LOG_DEBUG, "err: %d", err);
1400 		NDMP_FREE(nlp->nlp_params);
1401 		return (reply.error);
1402 	}
1403 
1404 	reply.error = NDMP_NO_ERR;
1405 	if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
1406 	    &reply) < 0) {
1407 		NDMP_LOG(LOG_DEBUG, "Sending data_start_backup_v3 reply");
1408 		return (NDMP_NO_ERR);
1409 	}
1410 
1411 	NS_INC(nbk);
1412 	session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
1413 	session->ns_data.dd_operation = NDMP_DATA_OP_BACKUP;
1414 	session->ns_data.dd_abort = FALSE;
1415 
1416 	/*
1417 	 * perform the backup
1418 	 *
1419 	 * Cannot wait for the thread to exit as we are replying the
1420 	 * client request here.
1421 	 */
1422 	err = pthread_create(NULL, NULL,
1423 	    (funct_t)session->ns_data.dd_module.dm_start_func,
1424 	    params);
1425 	if (err != 0) {
1426 		NDMP_LOG(LOG_ERR, "Can't start backup session.");
1427 		return (NDMP_ILLEGAL_ARGS_ERR);
1428 	}
1429 
1430 	return (NDMP_NO_ERR);
1431 }
1432 
1433 
1434 /*
1435  * start_recover_v3
1436  *
1437  * Start the restore work
1438  *
1439  * Parameters:
1440  *   session (input) - session pointer.
1441  *   bu_type   (input) - backup type.
1442  *   env_val   (input) - environment variable array.
1443  *   env_len   (input) - length of env_val.
1444  *
1445  * Returns:
1446  *   NDMP_NO_ERR - recover successfully started.
1447  *   otherwise   - error code of recover start error.
1448  */
1449 static ndmp_error
1450 start_recover_v3(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val,
1451     ulong_t env_len, ndmp_name_v3 *nlist_val, ulong_t nlist_len)
1452 {
1453 	ndmp_data_start_recover_reply_v3 reply;
1454 	ndmpd_module_params_t *params;
1455 	ndmp_lbr_params_t *nlp;
1456 	int err;
1457 
1458 	(void) memset((void*)&reply, 0, sizeof (reply));
1459 
1460 	if (session->ns_data.dd_state != NDMP_DATA_STATE_CONNECTED) {
1461 		NDMP_LOG(LOG_ERR, "Can't start new recover in current state.");
1462 		return (NDMP_ILLEGAL_STATE_ERR);
1463 	}
1464 	if (strcmp(bu_type, NDMP_DUMP_TYPE) != 0 &&
1465 	    strcmp(bu_type, NDMP_TAR_TYPE) != 0) {
1466 		NDMP_LOG(LOG_ERR, "Invalid backup type: %s.", bu_type);
1467 		NDMP_LOG(LOG_ERR, "Supported backup types are tar and dump.");
1468 		return (NDMP_ILLEGAL_ARGS_ERR);
1469 	}
1470 
1471 	nlp = ndmp_get_nlp(session);
1472 	NDMP_FREE(nlp->nlp_params);
1473 	params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t));
1474 	if (!params) {
1475 		return (NDMP_NO_MEM_ERR);
1476 	}
1477 
1478 	reply.error = ndmpd_save_env(session, env_val, env_len);
1479 	if (reply.error != NDMP_NO_ERR) {
1480 		NDMP_FREE(nlp->nlp_params);
1481 		return (NDMP_NO_MEM_ERR);
1482 	}
1483 
1484 	reply.error = ndmpd_save_nlist_v3(session, nlist_val, nlist_len);
1485 	if (reply.error != NDMP_NO_ERR) {
1486 		NDMP_FREE(nlp->nlp_params);
1487 		return (NDMP_NO_MEM_ERR);
1488 	}
1489 
1490 	/*
1491 	 * Setup restore parameters.
1492 	 */
1493 	params->mp_daemon_cookie = (void *)session;
1494 	params->mp_module_cookie = &session->ns_data.dd_module.dm_module_cookie;
1495 	params->mp_protocol_version = session->ns_protocol_version;
1496 	params->mp_operation = NDMP_DATA_OP_RECOVER;
1497 	params->mp_get_env_func = ndmpd_api_get_env;
1498 	params->mp_add_env_func = ndmpd_api_add_env;
1499 	params->mp_set_env_func = ndmpd_api_set_env;
1500 	params->mp_get_name_func = ndmpd_api_get_name_v3;
1501 	params->mp_dispatch_func = ndmpd_api_dispatch;
1502 	params->mp_done_func = ndmpd_api_done_v3;
1503 	if (session->ns_protocol_version == NDMPV4) {
1504 		params->mp_log_func_v3 = ndmpd_api_log_v4;
1505 		params->mp_file_recovered_func = ndmpd_api_file_recovered_v4;
1506 	} else {
1507 		params->mp_log_func_v3 = ndmpd_api_log_v3;
1508 		params->mp_file_recovered_func = ndmpd_api_file_recovered_v3;
1509 	}
1510 
1511 	params->mp_add_file_handler_func = ndmpd_api_add_file_handler;
1512 	params->mp_remove_file_handler_func = ndmpd_api_remove_file_handler;
1513 	params->mp_write_func = 0;
1514 	params->mp_file_history_path_func = 0;
1515 	params->mp_file_history_dir_func = 0;
1516 	params->mp_file_history_node_func = 0;
1517 	params->mp_read_func = ndmpd_api_read_v3;
1518 	params->mp_seek_func = ndmpd_api_seek_v3;
1519 	params->mp_stats = &session->ns_data.dd_module.dm_stats;
1520 
1521 	session->ns_data.dd_module.dm_module_cookie = 0;
1522 	session->ns_data.dd_module.dm_start_func = ndmpd_tar_restore_starter_v3;
1523 	session->ns_data.dd_module.dm_abort_func = ndmpd_tar_restore_abort_v3;
1524 	session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
1525 	session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0;
1526 	session->ns_data.dd_bytes_left_to_read = 0;
1527 	session->ns_data.dd_position = 0;
1528 	session->ns_data.dd_discard_length = 0;
1529 	session->ns_data.dd_read_offset = 0;
1530 	session->ns_data.dd_read_length = 0;
1531 
1532 	err = ndmp_restore_get_params_v3(session, params);
1533 	if (err != NDMP_NO_ERR) {
1534 		NDMP_FREE(nlp->nlp_params);
1535 		return (err);
1536 	}
1537 
1538 	reply.error = NDMP_NO_ERR;
1539 	if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
1540 	    &reply) < 0) {
1541 		NDMP_FREE(nlp->nlp_params);
1542 		ndmpd_free_nlist_v3(session);
1543 		NDMP_LOG(LOG_DEBUG,
1544 		    "Error sending ndmp_data_start_recover_reply");
1545 		ndmpd_data_error(session, NDMP_DATA_HALT_CONNECT_ERROR);
1546 		return (NDMP_NO_ERR);
1547 	}
1548 
1549 	NS_INC(nrs);
1550 	session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
1551 	session->ns_data.dd_operation = NDMP_DATA_OP_RECOVER;
1552 	session->ns_data.dd_abort = FALSE;
1553 
1554 	/*
1555 	 * perform the restore
1556 	 *
1557 	 * Cannot wait for the thread to exit as we are replying to the
1558 	 * client request here.
1559 	 */
1560 	err = pthread_create(NULL, NULL,
1561 	    (funct_t)session->ns_data.dd_module.dm_start_func,
1562 	    params);
1563 
1564 	if (err != 0) {
1565 		NDMP_LOG(LOG_ERR, "Can't start recover session.");
1566 		return (NDMP_ILLEGAL_ARGS_ERR);
1567 	}
1568 	return (NDMP_NO_ERR);
1569 }
1570 
1571 
1572 /*
1573  * discard_data_v3
1574  *
1575  * Read and discard data from the data connection.
1576  * Called when a module has called ndmpd_seek() prior to
1577  * reading all of the data from the previous seek.
1578  *
1579  * Parameters:
1580  *   session (input) - session pointer.
1581  *
1582  * Returns:
1583  *   number of bytes read and discarded.
1584  *  -1 - error.
1585  */
1586 static int
1587 discard_data_v3(ndmpd_session_t *session, ulong_t length)
1588 {
1589 	static char buf[MAX_RECORD_SIZE];
1590 	int n, toread;
1591 
1592 	toread = (length < MAX_RECORD_SIZE) ? length :
1593 	    MAX_RECORD_SIZE;
1594 
1595 	NDMP_LOG(LOG_DEBUG, "discard data, length = %u", length);
1596 
1597 	/* Read and discard the data. */
1598 	n = read(session->ns_data.dd_sock, buf, toread);
1599 	if (n < 0) {
1600 		NDMP_LOG(LOG_ERR, "Socket read error: %m.");
1601 		n = -1;
1602 	}
1603 
1604 	return (n);
1605 }
1606 
1607 
1608 /*
1609  * ndmpd_remote_read_v3
1610  *
1611  * Reads data from the remote mover.
1612  *
1613  * Parameters:
1614  *   session (input) - session pointer.
1615  *   data    (input) - data to be written.
1616  *   length  (input) - data length.
1617  *
1618  * Returns:
1619  *   0 - data successfully read.
1620  *  -1 - error.
1621  */
1622 int
1623 ndmpd_remote_read_v3(ndmpd_session_t *session, char *data, ulong_t length)
1624 {
1625 	ulong_t count;
1626 	ulong_t len;
1627 	ssize_t n;
1628 	ndmp_notify_data_read_request request;
1629 	tlm_job_stats_t *jstat;
1630 	longlong_t fsize;
1631 
1632 	NDMP_LOG(LOG_DEBUG, "ns_data.dd_xx: [%llu, %llu, %llu, %llu, %llu]",
1633 	    session->ns_data.dd_bytes_left_to_read,
1634 	    session->ns_data.dd_read_offset,
1635 	    session->ns_data.dd_read_length,
1636 	    session->ns_data.dd_position,
1637 	    session->ns_data.dd_discard_length);
1638 
1639 	count = 0;
1640 	while (count < length) {
1641 		len = length - count;
1642 
1643 		/*
1644 		 * If the end of the seek window has been reached then
1645 		 * send an ndmp_read request to the client.
1646 		 * The NDMP client will then send a mover_data_read request to
1647 		 * the remote mover and the mover will send more data.
1648 		 * This condition can occur if the module attempts to read past
1649 		 * a seek window set via a prior call to ndmpd_seek() or
1650 		 * the module has not issued a seek. If no seek was issued then
1651 		 * pretend that a seek was issued to read the entire tape.
1652 		 */
1653 		if (session->ns_data.dd_bytes_left_to_read == 0) {
1654 			/* ndmpd_seek() never called? */
1655 			if (session->ns_data.dd_read_length == 0) {
1656 				session->ns_data.dd_bytes_left_to_read = ~0LL;
1657 				session->ns_data.dd_read_offset = 0LL;
1658 				session->ns_data.dd_read_length = ~0LL;
1659 			} else {
1660 				/*
1661 				 * While restoring a file, restoreFile()
1662 				 * records the number of bytes still need to
1663 				 * be restored.  We use this as a guidance
1664 				 * when asking for data from the tape.
1665 				 */
1666 				jstat = session->ns_ndmp_lbr_params->nlp_jstat;
1667 				fsize = jstat->js_bytes_in_file;
1668 
1669 				NDMP_LOG(LOG_DEBUG, "bytes_left [%llu / %u]",
1670 				    fsize, len);
1671 
1672 				/*
1673 				 * Fall back to the old way if fsize if too
1674 				 * small.
1675 				 */
1676 				if (fsize < len)
1677 					fsize = len;
1678 
1679 				session->ns_data.dd_bytes_left_to_read = fsize;
1680 				session->ns_data.dd_read_offset =
1681 				    session->ns_data.dd_position;
1682 				session->ns_data.dd_read_length = fsize;
1683 			}
1684 
1685 			request.offset =
1686 			    long_long_to_quad(session->ns_data.dd_read_offset);
1687 			request.length =
1688 			    long_long_to_quad(session->ns_data.dd_read_length);
1689 
1690 			NDMP_LOG(LOG_DEBUG, "to NOTIFY_DATA_READ [%llu, %llu]",
1691 			    session->ns_data.dd_read_offset,
1692 			    session->ns_data.dd_read_length);
1693 
1694 			if (ndmp_send_request(session->ns_connection,
1695 			    NDMP_NOTIFY_DATA_READ, NDMP_NO_ERR,
1696 			    &request, 0) < 0) {
1697 				NDMP_LOG(LOG_DEBUG,
1698 				    "Sending notify_data_read request");
1699 				return (-1);
1700 			}
1701 		}
1702 
1703 		/*
1704 		 * If the module called ndmpd_seek() prior to reading all of the
1705 		 * data that the remote mover was requested to send, then the
1706 		 * excess data from the seek has to be discarded.
1707 		 */
1708 		if (session->ns_data.dd_discard_length != 0) {
1709 			n = discard_data_v3(session,
1710 			    (ulong_t)session->ns_data.dd_discard_length);
1711 			if (n < 0)
1712 				return (-1);
1713 
1714 			session->ns_data.dd_discard_length -= n;
1715 			continue;
1716 		}
1717 
1718 		/*
1719 		 * Don't attempt to read more data than the remote is sending.
1720 		 */
1721 		if (len > session->ns_data.dd_bytes_left_to_read)
1722 			len = session->ns_data.dd_bytes_left_to_read;
1723 
1724 		if ((n = read(session->ns_data.dd_sock, &data[count],
1725 		    len)) < 0) {
1726 			NDMP_LOG(LOG_ERR, "Socket read error: %m.");
1727 			return (-1);
1728 		}
1729 
1730 		/* read returns 0 if the connection was closed */
1731 		if (n == 0) {
1732 			NDMP_LOG(LOG_DEBUG, "n 0 errno %d",
1733 			    errno);
1734 			return (-1);
1735 		}
1736 
1737 		count += n;
1738 		session->ns_data.dd_bytes_left_to_read -= n;
1739 		session->ns_data.dd_position += n;
1740 	}
1741 
1742 	return (0);
1743 }
1744 
1745 
1746 /*
1747  * nlp_release_job_stat
1748  *
1749  * Unreference the job statistics
1750  *
1751  * Parameters:
1752  *   session (input) - session pointer.
1753  *
1754  * Returns:
1755  *   void
1756  */
1757 static void
1758 nlp_release_job_stat(ndmpd_session_t *session)
1759 {
1760 	ndmp_lbr_params_t *nlp;
1761 
1762 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
1763 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1764 		return;
1765 	}
1766 	if (nlp->nlp_jstat != NULL) {
1767 		nlp->nlp_bytes_total =
1768 		    (u_longlong_t)nlp->nlp_jstat->js_bytes_total;
1769 		tlm_un_ref_job_stats(nlp->nlp_jstat->js_job_name);
1770 		nlp->nlp_jstat = NULL;
1771 	} else
1772 		NDMP_LOG(LOG_DEBUG, "JSTAT == NULL");
1773 }
1774 
1775 
1776 /* *** ndmpd global internal functions *********************************** */
1777 
1778 /*
1779  * ndmpd_data_init
1780  *
1781  * Initializes data specific session variables.
1782  *
1783  * Parameters:
1784  *   session (input) - session pointer.
1785  *
1786  * Returns:
1787  *   void
1788  */
1789 int
1790 ndmpd_data_init(ndmpd_session_t *session)
1791 {
1792 	session->ns_data.dd_operation = NDMP_DATA_OP_NOACTION;
1793 	session->ns_data.dd_state = NDMP_DATA_STATE_IDLE;
1794 	session->ns_data.dd_halt_reason = NDMP_DATA_HALT_NA;
1795 	session->ns_data.dd_abort = FALSE;
1796 	session->ns_data.dd_env = 0;
1797 	session->ns_data.dd_env_len = 0;
1798 	session->ns_data.dd_nlist = 0;
1799 	session->ns_data.dd_nlist_len = 0;
1800 	session->ns_data.dd_mover.addr_type = NDMP_ADDR_LOCAL;
1801 	session->ns_data.dd_sock = -1;
1802 	session->ns_data.dd_read_offset = 0;
1803 	session->ns_data.dd_read_length = 0;
1804 	session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
1805 	session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0;
1806 	/*
1807 	 * NDMP V3
1808 	 */
1809 	session->ns_data.dd_state = NDMP_DATA_STATE_IDLE;
1810 	session->ns_data.dd_nlist_v3 = 0;
1811 	session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_LOCAL;
1812 	session->ns_data.dd_listen_sock = -1;
1813 	session->ns_data.dd_bytes_left_to_read = 0LL;
1814 	session->ns_data.dd_position = 0LL;
1815 	session->ns_data.dd_discard_length = 0LL;
1816 	return (0);
1817 }
1818 
1819 
1820 
1821 /*
1822  * ndmpd_data_cleanup
1823  *
1824  * Releases resources allocated during a data operation.
1825  *
1826  * Parameters:
1827  *   session (input) - session pointer.
1828  *
1829  * Returns:
1830  *   void
1831  */
1832 void
1833 ndmpd_data_cleanup(ndmpd_session_t *session)
1834 {
1835 	if (session->ns_data.dd_listen_sock != -1) {
1836 		NDMP_LOG(LOG_DEBUG, "data.listen_sock: %d",
1837 		    session->ns_data.dd_listen_sock);
1838 		(void) ndmpd_remove_file_handler(session,
1839 		    session->ns_data.dd_listen_sock);
1840 		(void) close(session->ns_data.dd_listen_sock);
1841 		session->ns_data.dd_listen_sock = -1;
1842 	}
1843 	if (session->ns_data.dd_sock != -1) {
1844 		NDMP_LOG(LOG_DEBUG, "data.sock: %d",
1845 		    session->ns_data.dd_sock);
1846 
1847 		/*
1848 		 * ndmpcopy: we use the same socket for the mover,
1849 		 * so expect to close when mover is done!
1850 		 */
1851 		if (session->ns_data.dd_sock != session->ns_mover.md_sock)
1852 			(void) close(session->ns_data.dd_sock);
1853 
1854 		session->ns_data.dd_sock = -1;
1855 	}
1856 
1857 	ndmpd_free_env(session);
1858 	ndmpd_free_nlist(session);
1859 }
1860 
1861 
1862 /*
1863  * ndmp_data_get_mover_mode
1864  *
1865  * Return the mover mode
1866  *
1867  * Parameters:
1868  *   session (input) - session pointer.
1869  *
1870  * Returns:
1871  *   remote - remote backup
1872  *   local  - local backup
1873  */
1874 char *
1875 ndmp_data_get_mover_mode(ndmpd_session_t *session)
1876 {
1877 	char *rv;
1878 
1879 	switch (session->ns_protocol_version) {
1880 	case NDMPV2:
1881 		rv = ((session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP)
1882 		    ? "remote" : "local");
1883 		break;
1884 	case NDMPV3:
1885 		rv = ((session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_TCP)
1886 		    ? "remote" : "local");
1887 		break;
1888 	case NDMPV4:
1889 		rv = ((session->ns_data.dd_data_addr.addr_type ==
1890 		    NDMP_ADDR_TCP ||
1891 		    (session->ns_data.dd_data_addr_v4.addr_type ==
1892 		    NDMP_ADDR_TCP)) ? "remote" : "local");
1893 		break;
1894 	default:
1895 		rv = "Uknonwn";
1896 		NDMP_LOG(LOG_ERR, "Invalid protocol version %d.",
1897 		    session->ns_protocol_version);
1898 	}
1899 
1900 	return (rv);
1901 }
1902 
1903 /* *** static functions ******************************************** */
1904 
1905 /*
1906  * start_backup
1907  *
1908  * Request handling code common to version 1 and
1909  * version 2 data_start_backup request handlers.
1910  *
1911  * Parameters:
1912  *   session   (input) - session pointer.
1913  *   bu_type   (input) - backup type.
1914  *   env_val   (input) - environment variable array.
1915  *   env_len   (input) - length of env_val.
1916  *
1917  * Returns:
1918  *   NDMP_NO_ERR - backup successfully started.
1919  *   otherwise - error code of backup start error.
1920  */
1921 static ndmp_error
1922 start_backup(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val,
1923     ulong_t env_len)
1924 {
1925 	ndmp_data_start_backup_reply reply;
1926 	ndmpd_module_params_t *params;
1927 	ndmp_lbr_params_t *nlp;
1928 	int err;
1929 
1930 	if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
1931 		NDMP_LOG(LOG_ERR, "Can't start new backup in current state.");
1932 		return (NDMP_ILLEGAL_STATE_ERR);
1933 	}
1934 	if (strcmp(bu_type, NDMP_DUMP_TYPE) != 0 &&
1935 	    strcmp(bu_type, NDMP_TAR_TYPE) != 0) {
1936 		NDMP_LOG(LOG_ERR, "Invalid backup type: %s.", bu_type);
1937 		NDMP_LOG(LOG_ERR, "Supported backup types are tar and dump.");
1938 		return (NDMP_ILLEGAL_ARGS_ERR);
1939 	}
1940 	if ((err = ndmpd_save_env(session, env_val, env_len)) != NDMP_NO_ERR)
1941 		return (err);
1942 
1943 	nlp = ndmp_get_nlp(session);
1944 	NDMP_FREE(nlp->nlp_params);
1945 	params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t));
1946 	if (params == NULL)
1947 		return (NDMP_NO_MEM_ERR);
1948 
1949 	params->mp_daemon_cookie = (void *)session;
1950 	params->mp_module_cookie = &session->ns_data.dd_module.dm_module_cookie;
1951 	params->mp_protocol_version = session->ns_protocol_version;
1952 	params->mp_operation = NDMP_DATA_OP_BACKUP;
1953 	params->mp_get_env_func = ndmpd_api_get_env;
1954 	params->mp_add_env_func = ndmpd_api_add_env;
1955 	params->mp_get_name_func = ndmpd_api_get_name;
1956 	params->mp_dispatch_func = ndmpd_api_dispatch;
1957 	params->mp_done_func = ndmpd_api_done_v2;
1958 	params->mp_log_func = ndmpd_api_log_v2;
1959 	params->mp_add_file_handler_func = ndmpd_api_add_file_handler;
1960 	params->mp_remove_file_handler_func = ndmpd_api_remove_file_handler;
1961 	params->mp_write_func = ndmpd_api_write_v2;
1962 	params->mp_read_func = 0;
1963 	params->mp_file_recovered_func = 0;
1964 	params->mp_stats = &session->ns_data.dd_module.dm_stats;
1965 
1966 	session->ns_data.dd_module.dm_module_cookie = 0;
1967 	if (strcmp(bu_type, NDMP_DUMP_TYPE) == 0) {
1968 		NLP_SET(nlp, NLPF_DUMP);
1969 		params->mp_file_history_path_func = 0;
1970 		params->mp_file_history_dir_func =
1971 		    ndmpd_api_file_history_dir_v2;
1972 		params->mp_file_history_node_func =
1973 		    ndmpd_api_file_history_node_v2;
1974 	} else if (strcmp(bu_type, NDMP_TAR_TYPE) == 0) {
1975 		/* backup type == NDMP_TAR_TYPE */
1976 		NLP_SET(nlp, NLPF_TAR);
1977 		params->mp_file_history_path_func =
1978 		    ndmpd_api_file_history_path_v2;
1979 		params->mp_file_history_dir_func = 0;
1980 		params->mp_file_history_node_func = 0;
1981 	} else {
1982 		NLP_UNSET(nlp, NLPF_DUMP);
1983 		NLP_UNSET(nlp, NLPF_TAR);
1984 	}
1985 
1986 	session->ns_data.dd_module.dm_start_func = ndmpd_tar_backup_starter;
1987 	session->ns_data.dd_module.dm_abort_func = ndmpd_tar_backup_abort;
1988 
1989 	session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
1990 	session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0;
1991 	session->ns_data.dd_nlist = 0;
1992 	session->ns_data.dd_nlist_len = 0;
1993 	session->ns_data.dd_read_offset = 0;
1994 	session->ns_data.dd_read_length = 0;
1995 
1996 	if ((err = ndmp_backup_extract_params(session,
1997 	    params)) != NDMP_NO_ERR) {
1998 		NDMP_LOG(LOG_DEBUG, "err: %d", err);
1999 		NDMP_FREE(nlp->nlp_params);
2000 		return (err);
2001 	}
2002 
2003 	err = ndmpd_mover_connect(session, NDMP_MOVER_MODE_READ);
2004 	if (err != NDMP_NO_ERR) {
2005 		NDMP_LOG(LOG_DEBUG,
2006 		    "mover connect err: %d", err);
2007 		NDMP_FREE(nlp->nlp_params);
2008 		return (err);
2009 	}
2010 
2011 	session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
2012 
2013 	session->ns_data.dd_operation = NDMP_DATA_OP_BACKUP;
2014 	session->ns_data.dd_abort = FALSE;
2015 
2016 	NDMP_LOG(LOG_DEBUG, "starting backup");
2017 
2018 	reply.error = NDMP_NO_ERR;
2019 	if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
2020 	    &reply) < 0) {
2021 		NDMP_LOG(LOG_DEBUG, "Sending data_start_backup reply");
2022 		NDMP_FREE(nlp->nlp_params);
2023 		if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP) {
2024 			/*
2025 			 * ndmpcopy: we use the same socket for the mover,
2026 			 * so expect to close when mover is done!
2027 			 */
2028 			if (session->ns_data.dd_sock !=
2029 			    session->ns_mover.md_sock)
2030 				(void) close(session->ns_data.dd_sock);
2031 
2032 			session->ns_data.dd_sock = -1;
2033 		} else
2034 			ndmpd_mover_error(session,
2035 			    NDMP_MOVER_HALT_CONNECT_CLOSED);
2036 		return (NDMP_NO_ERR);
2037 	}
2038 
2039 	/*
2040 	 * perform the backup
2041 	 *
2042 	 * Cannot wait for the thread to exit as we are replying to the
2043 	 * client request here.
2044 	 */
2045 	(void) pthread_create(NULL, NULL,
2046 	    (funct_t)session->ns_data.dd_module.dm_start_func,
2047 	    params);
2048 
2049 	return (NDMP_NO_ERR);
2050 }
2051 
2052 
2053 /*
2054  * start_recover
2055  *
2056  * The main recover/restore function
2057  *
2058  * Parameters:
2059  *   session   (input) - session pointer.
2060  *   bu_type   (input) - backup type.
2061  *   env_val   (input) - environment variable array.
2062  *   env_len   (input) - length of env_val.
2063  *   nlist_val (input) - list of files
2064  *   nlist_len (input) - length of nlist_val
2065  *
2066  * Returns:
2067  *   NDMP_NO_ERR - recover successfully started.
2068  *   otherwise - error code of backup start error.
2069  */
2070 static ndmp_error
2071 start_recover(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val,
2072     ulong_t env_len, ndmp_name *nlist_val, ulong_t nlist_len)
2073 {
2074 	ndmp_data_start_recover_reply_v2 reply;
2075 	ndmpd_module_params_t *params;
2076 	ndmp_lbr_params_t *nlp;
2077 	int err;
2078 
2079 	if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
2080 		NDMP_LOG(LOG_ERR, "Can't start new recover in current state.");
2081 		return (NDMP_ILLEGAL_STATE_ERR);
2082 	}
2083 
2084 	if (strcmp(bu_type, NDMP_DUMP_TYPE) != 0 &&
2085 	    strcmp(bu_type, NDMP_TAR_TYPE) != 0) {
2086 		NDMP_LOG(LOG_ERR, "Invalid backup type: %s.", bu_type);
2087 		NDMP_LOG(LOG_ERR, "Supported backup types are tar and dump.");
2088 		return (NDMP_ILLEGAL_ARGS_ERR);
2089 	}
2090 
2091 	reply.error = ndmpd_save_env(session, env_val, env_len);
2092 	if (reply.error != NDMP_NO_ERR)
2093 		return (NDMP_NO_MEM_ERR);
2094 
2095 	reply.error = ndmpd_save_nlist_v2(session, nlist_val, nlist_len);
2096 	if (reply.error != NDMP_NO_ERR)
2097 		return (NDMP_NO_MEM_ERR);
2098 
2099 	nlp = ndmp_get_nlp(session);
2100 	NDMP_FREE(nlp->nlp_params);
2101 	params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t));
2102 	if (params == NULL)
2103 		return (NDMP_NO_MEM_ERR);
2104 
2105 	/*
2106 	 * Setup restore parameters.
2107 	 */
2108 	params->mp_daemon_cookie = (void *)session;
2109 	params->mp_module_cookie = &session->ns_data.dd_module.dm_module_cookie;
2110 	params->mp_protocol_version = session->ns_protocol_version;
2111 	params->mp_operation = NDMP_DATA_OP_RECOVER;
2112 	params->mp_get_env_func = ndmpd_api_get_env;
2113 	params->mp_add_env_func = ndmpd_api_add_env;
2114 	params->mp_get_name_func = ndmpd_api_get_name;
2115 	params->mp_dispatch_func = ndmpd_api_dispatch;
2116 	params->mp_done_func = ndmpd_api_done_v2;
2117 	params->mp_log_func = ndmpd_api_log_v2;
2118 	params->mp_add_file_handler_func = ndmpd_api_add_file_handler;
2119 	params->mp_remove_file_handler_func = ndmpd_api_remove_file_handler;
2120 	params->mp_write_func = 0;
2121 	params->mp_file_history_path_func = 0;
2122 	params->mp_file_history_dir_func = 0;
2123 	params->mp_file_history_node_func = 0;
2124 	params->mp_read_func = ndmpd_api_read_v2;
2125 	params->mp_seek_func = ndmpd_api_seek_v2;
2126 	params->mp_file_recovered_func = ndmpd_api_file_recovered_v2;
2127 	params->mp_stats = &session->ns_data.dd_module.dm_stats;
2128 
2129 	session->ns_data.dd_module.dm_module_cookie = 0;
2130 	session->ns_data.dd_module.dm_start_func = ndmpd_tar_restore_starter;
2131 	session->ns_data.dd_module.dm_abort_func = ndmpd_tar_restore_abort;
2132 	session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
2133 	session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0;
2134 	session->ns_data.dd_read_offset = 0;
2135 	session->ns_data.dd_read_length = 0;
2136 
2137 	if ((err = ndmp_restore_extract_params(session,
2138 	    params)) != NDMP_NO_ERR) {
2139 		NDMP_FREE(nlp->nlp_params);
2140 		return (err);
2141 	}
2142 
2143 	err = ndmpd_mover_connect(session, NDMP_MOVER_MODE_WRITE);
2144 	if (err != NDMP_NO_ERR) {
2145 		NDMP_FREE(nlp->nlp_params);
2146 		return (err);
2147 	}
2148 
2149 	session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
2150 	session->ns_data.dd_operation = NDMP_DATA_OP_RECOVER;
2151 	session->ns_data.dd_abort = FALSE;
2152 
2153 	reply.error = NDMP_NO_ERR;
2154 	if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
2155 	    &reply) < 0) {
2156 		NDMP_LOG(LOG_DEBUG, "Sending data_start_recover reply");
2157 		NDMP_FREE(nlp->nlp_params);
2158 		if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP) {
2159 			/*
2160 			 * ndmpcopy: we use the same socket for the mover,
2161 			 * so expect to close when mover is done!
2162 			 */
2163 			if (session->ns_data.dd_sock !=
2164 			    session->ns_mover.md_sock)
2165 				(void) close(session->ns_data.dd_sock);
2166 
2167 			session->ns_data.dd_sock = -1;
2168 		} else {
2169 			ndmpd_mover_error(session,
2170 			    NDMP_MOVER_HALT_CONNECT_CLOSED);
2171 		}
2172 		return (NDMP_NO_ERR);
2173 	}
2174 
2175 
2176 	/*
2177 	 * perform the restore
2178 	 *
2179 	 * Cannot wait for the thread to exit as we are replying the
2180 	 * client request here.
2181 	 */
2182 	(void) pthread_create(NULL, NULL,
2183 	    (funct_t)session->ns_data.dd_module.dm_start_func,
2184 	    params);
2185 
2186 	return (NDMP_NO_ERR);
2187 }
2188 
2189 
2190 /*
2191  * ndmpd_data_get_info
2192  *
2193  * Return the total number of bytes processed
2194  *
2195  * Parameters:
2196  *   session   (input) - session pointer.
2197  *
2198  * Returns:
2199  *   the number of bytes processed
2200  */
2201 static u_longlong_t
2202 ndmpd_data_get_info(ndmpd_session_t *session)
2203 {
2204 	ndmp_lbr_params_t *nlp;
2205 
2206 	nlp = ndmp_get_nlp(session);
2207 	if (nlp == NULL)
2208 		return ((u_longlong_t)0);
2209 
2210 	if (nlp->nlp_jstat == NULL)
2211 		return (nlp->nlp_bytes_total);
2212 
2213 	return ((u_longlong_t)nlp->nlp_jstat->js_bytes_total);
2214 }
2215