2 * Copyright (c) 2009-2012 Zmanda, Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * Contact information: Zmanda Inc., 465 N Mathlida Ave, Suite 300
19 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
24 #include "sockaddr-util.h"
25 #include "ndmpconnobj.h"
28 * NDMPConnection class implementation
31 /* level at which to snoop when VERBOSE is set; 8 = everything but hexdumps,
32 * and 5 = packets without details */
35 static GObjectClass *parent_class = NULL;
37 /* and equipment to ensure we only talk to ndmlib in one thread at a time, even
38 * using multiple connections. The ndmlib code is not necessarily reentrant,
39 * so this is better safe than sorry. */
40 static GStaticMutex ndmlib_mutex = G_STATIC_MUTEX_INIT;
42 /* macros like those in ndmlib.h, but designed for use in this class */
43 /* (copied from ndmp-src/ndmlib.h; see that file for copyright and license) */
45 #define NDMP_TRANS(SELF, TYPE) \
47 struct ndmp_xa_buf * xa = &(SELF)->conn->call_xa_buf; \
48 TYPE##_request * request; \
49 TYPE##_reply * reply; \
50 request = &xa->request.body.TYPE##_request_body; \
51 reply = &xa->reply.body.TYPE##_reply_body; \
52 NDMOS_MACRO_ZEROFILL (xa); \
53 xa->request.protocol_version = NDMP4VER; \
54 xa->request.header.message = (ndmp0_message) MT_##TYPE; \
55 g_static_mutex_lock(&ndmlib_mutex); \
58 #define NDMP_TRANS_NO_REQUEST(SELF, TYPE) \
60 struct ndmp_xa_buf * xa = &(SELF)->conn->call_xa_buf; \
61 TYPE##_reply * reply; \
62 reply = &xa->reply.body.TYPE##_reply_body; \
63 NDMOS_MACRO_ZEROFILL (xa); \
64 xa->request.protocol_version = NDMP4VER; \
65 xa->request.header.message = (ndmp0_message) MT_##TYPE; \
66 g_static_mutex_lock(&ndmlib_mutex); \
69 #define NDMP_CALL(SELF) \
71 (SELF)->last_rc = (*(SELF)->conn->call)((SELF)->conn, xa); \
72 if ((SELF)->last_rc) { \
74 g_static_mutex_unlock(&ndmlib_mutex); \
79 #define NDMP_FREE() ndmconn_free_nmb(NULL, &xa->reply)
82 g_static_mutex_unlock(&ndmlib_mutex); \
90 finalize_impl(GObject *goself)
92 NDMPConnection *self = NDMP_CONNECTION(goself);
95 G_OBJECT_CLASS(parent_class)->finalize(goself);
97 g_debug("closing conn#%d", self->connid);
99 /* close this connection if necessary */
101 ndmconn_destruct(self->conn);
105 if (self->log_state) {
106 g_free(self->log_state);
107 self->log_state = NULL;
116 ndmp_connection_err_code(
117 NDMPConnection *self)
119 if (self->startup_err) {
121 } else if (self->last_rc == NDMCONN_CALL_STATUS_REPLY_ERROR) {
122 return self->conn->last_reply_error;
129 ndmp_connection_err_msg(
130 NDMPConnection *self)
132 if (self->startup_err) {
133 return g_strdup(self->startup_err);
134 } else if (self->last_rc == NDMCONN_CALL_STATUS_REPLY_ERROR) {
135 return g_strdup_printf("Error from NDMP server: %s",
136 ndmp9_error_to_str(self->conn->last_reply_error));
137 } else if (self->last_rc) {
138 return g_strdup_printf("ndmconn error %d: %s",
139 self->last_rc, ndmconn_get_err_msg(self->conn));
141 return g_strdup_printf("No error");
146 ndmp_connection_ndmlog_deliver(
149 int lev G_GNUC_UNUSED,
152 NDMPConnection *self = NDMP_CONNECTION(log->cookie);
153 g_debug("conn#%d: %s: %s", self->connid, tag, msg);
157 ndmp_connection_set_verbose(
158 NDMPConnection *self,
161 struct ndmlog *device_ndmlog;
162 g_assert(!self->startup_err);
164 device_ndmlog = g_new0(struct ndmlog, 1);
166 self->log_state = (gpointer)device_ndmlog;
167 device_ndmlog->deliver = ndmp_connection_ndmlog_deliver;
168 device_ndmlog->cookie = self;
171 ndmconn_set_snoop(self->conn,
175 ndmconn_clear_snoop(self->conn);
184 ndmp_connection_scsi_open(
185 NDMPConnection *self,
188 g_assert(!self->startup_err);
190 NDMP_TRANS(self, ndmp4_scsi_open)
191 request->device = device;
199 ndmp_connection_scsi_close(
200 NDMPConnection *self)
202 g_assert(!self->startup_err);
204 NDMP_TRANS_NO_REQUEST(self, ndmp4_scsi_close)
212 ndmp_connection_scsi_execute_cdb(
213 NDMPConnection *self,
214 guint32 flags, /* NDMP4_SCSI_DATA_{IN,OUT}; OUT = to device */
215 guint32 timeout, /* in ms */
220 gsize *actual_dataout_len, /* output */
221 gpointer datain, /* output */
222 gsize datain_max_len, /* output buffer size */
223 gsize *actual_datain_len, /* output */
224 guint8 *status, /* output */
225 gpointer ext_sense, /* output */
226 gsize ext_sense_max_len, /* output buffer size */
227 gsize *actual_ext_sense_len /* output */
230 g_assert(!self->startup_err);
234 if (actual_dataout_len)
235 *actual_dataout_len = 0;
236 if (actual_datain_len)
237 *actual_datain_len = 0;
238 if (actual_ext_sense_len)
239 *actual_ext_sense_len = 0;
241 NDMP_TRANS(self, ndmp4_scsi_execute_cdb)
242 request->flags = flags;
243 request->timeout = timeout;
244 request->datain_len = datain_max_len;
245 request->cdb.cdb_len = cdb_len;
246 request->cdb.cdb_val = cdb;
247 request->dataout.dataout_len = dataout_len;
248 request->dataout.dataout_val = dataout;
253 *status = reply->status;
254 if (actual_dataout_len)
255 *actual_dataout_len = reply->dataout_len;
257 reply->datain.datain_len = MIN(datain_max_len, reply->datain.datain_len);
258 if (actual_datain_len)
259 *actual_datain_len = reply->datain.datain_len;
260 if (datain_max_len && datain)
261 g_memmove(datain, reply->datain.datain_val, reply->datain.datain_len);
263 reply->ext_sense.ext_sense_len = MIN(ext_sense_max_len, reply->ext_sense.ext_sense_len);
264 if (actual_ext_sense_len)
265 *actual_ext_sense_len = reply->ext_sense.ext_sense_len;
266 if (ext_sense_max_len && ext_sense)
267 g_memmove(ext_sense, reply->ext_sense.ext_sense_val, reply->ext_sense.ext_sense_len);
275 ndmp_connection_tape_open(
276 NDMPConnection *self,
278 ndmp9_tape_open_mode mode)
280 g_assert(!self->startup_err);
282 NDMP_TRANS(self, ndmp4_tape_open)
283 request->device = device;
284 request->mode = mode;
292 ndmp_connection_tape_close(
293 NDMPConnection *self)
295 g_assert(!self->startup_err);
297 NDMP_TRANS_NO_REQUEST(self, ndmp4_tape_close)
305 ndmp_connection_tape_mtio(
306 NDMPConnection *self,
307 ndmp9_tape_mtio_op tape_op,
311 g_assert(!self->startup_err);
313 NDMP_TRANS(self, ndmp4_tape_mtio)
314 request->tape_op = tape_op;
315 request->count = count;
317 *resid_count = reply->resid_count;
324 ndmp_connection_tape_write(
325 NDMPConnection *self,
330 g_assert(!self->startup_err);
334 NDMP_TRANS(self, ndmp4_tape_write)
335 request->data_out.data_out_val = buf;
336 request->data_out.data_out_len = len;
338 *count = reply->count;
345 ndmp_connection_tape_read(
346 NDMPConnection *self,
351 g_assert(!self->startup_err);
355 NDMP_TRANS(self, ndmp4_tape_read)
356 request->count = count;
358 *out_count = reply->data_in.data_in_len;
359 g_memmove(buf, reply->data_in.data_in_val, *out_count);
366 ndmp_connection_tape_get_state(
367 NDMPConnection *self,
372 g_assert(!self->startup_err);
374 NDMP_TRANS_NO_REQUEST(self, ndmp4_tape_get_state)
377 if (reply->unsupported & NDMP4_TAPE_STATE_BLOCK_SIZE_UNS)
380 *blocksize = reply->block_size;
382 if (reply->unsupported & NDMP4_TAPE_STATE_FILE_NUM_UNS)
383 *file_num = G_MAXUINT64;
385 *file_num = reply->file_num;
387 if (reply->unsupported & NDMP4_TAPE_STATE_BLOCKNO_UNS)
388 *blockno = G_MAXUINT64;
390 *blockno = reply->blockno;
398 ndmp_connection_mover_set_record_size(
399 NDMPConnection *self,
402 g_assert(!self->startup_err);
404 NDMP_TRANS(self, ndmp4_mover_set_record_size)
405 /* this field is "len" in ndmp4, but "record_size" in ndmp9 */
406 request->len = record_size;
414 ndmp_connection_mover_set_window(
415 NDMPConnection *self,
419 g_assert(!self->startup_err);
421 NDMP_TRANS(self, ndmp4_mover_set_window)
422 request->offset = offset;
423 request->length = length;
431 ndmp_connection_mover_read(
432 NDMPConnection *self,
436 g_assert(!self->startup_err);
438 NDMP_TRANS(self, ndmp4_mover_read)
439 request->offset = offset;
440 request->length = length;
448 ndmp_connection_mover_continue(
449 NDMPConnection *self)
451 g_assert(!self->startup_err);
453 NDMP_TRANS_NO_REQUEST(self, ndmp4_mover_continue)
461 ndmp_connection_mover_listen(
462 NDMPConnection *self,
463 ndmp9_mover_mode mode,
464 ndmp9_addr_type addr_type,
465 DirectTCPAddr **addrs)
467 unsigned int naddrs, i;
470 g_assert(!self->startup_err);
472 NDMP_TRANS(self, ndmp4_mover_listen)
473 request->mode = mode;
474 request->addr_type = addr_type;
477 if (request->addr_type != reply->connect_addr.addr_type) {
478 g_warning("MOVER_LISTEN addr_type mismatch; got %d", reply->connect_addr.addr_type);
481 if (reply->connect_addr.addr_type == NDMP4_ADDR_TCP) {
482 naddrs = reply->connect_addr.ndmp4_addr_u.tcp_addr.tcp_addr_len;
483 *addrs = g_new0(DirectTCPAddr, naddrs+1);
484 for (i = 0; i < naddrs; i++) {
485 ndmp4_tcp_addr *na = &reply->connect_addr.ndmp4_addr_u.tcp_addr.tcp_addr_val[i];
486 (*addrs)[i].sin.sin_family = AF_INET;
487 (*addrs)[i].sin.sin_addr.s_addr = htonl(na->ip_addr);
488 SU_SET_PORT(addrs[i], na->port);
496 ndmp_connection_mover_connect(
497 NDMPConnection *self,
498 ndmp9_mover_mode mode,
499 DirectTCPAddr *addrs)
501 unsigned int naddrs, i;
504 g_assert(!self->startup_err);
508 for (naddrs = 0; SU_GET_FAMILY(&addrs[naddrs]) != 0; naddrs++) ;
510 /* convert addrs to an ndmp4_tcp_addr */
511 na = g_new0(ndmp4_tcp_addr, naddrs);
512 for (i = 0; i < naddrs; i++) {
513 na[i].ip_addr = ntohl(addrs[i].sin.sin_addr.s_addr);
514 na[i].port = SU_GET_PORT(&addrs[i]);
518 NDMP_TRANS(self, ndmp4_mover_connect)
519 request->mode = mode;
520 request->addr.addr_type = NDMP4_ADDR_TCP;
521 request->addr.ndmp4_addr_u.tcp_addr.tcp_addr_len = naddrs;
522 request->addr.ndmp4_addr_u.tcp_addr.tcp_addr_val = na;
530 ndmp_connection_mover_abort(
531 NDMPConnection *self)
533 g_assert(!self->startup_err);
535 NDMP_TRANS_NO_REQUEST(self, ndmp4_mover_abort)
543 ndmp_connection_mover_stop(
544 NDMPConnection *self)
546 g_assert(!self->startup_err);
548 NDMP_TRANS_NO_REQUEST(self, ndmp4_mover_stop)
556 ndmp_connection_mover_close(
557 NDMPConnection *self)
559 g_assert(!self->startup_err);
561 NDMP_TRANS_NO_REQUEST(self, ndmp4_mover_close)
568 gboolean ndmp_connection_mover_get_state(
569 NDMPConnection *self,
570 ndmp9_mover_state *state,
571 guint64 *bytes_moved,
572 guint64 *window_offset,
573 guint64 *window_length)
575 g_assert(!self->startup_err);
577 NDMP_TRANS_NO_REQUEST(self, ndmp4_mover_get_state)
579 if (state) *state = reply->state;
580 if (bytes_moved) *bytes_moved = reply->bytes_moved;
581 if (window_offset) *window_offset = reply->window_offset;
582 if (window_length) *window_length = reply->window_length;
589 ndmconn_handle_notify(
590 NDMPConnection *self,
591 struct ndmp_msg_buf *nmb)
593 g_assert(!self->startup_err);
595 if (nmb->header.message_type == NDMP0_MESSAGE_REQUEST) {
596 switch (nmb->header.message) {
597 case NDMP4_NOTIFY_DATA_HALTED: {
598 ndmp4_notify_data_halted_post *post =
599 &nmb->body.ndmp4_notify_data_halted_post_body;
600 self->data_halt_reason = post->reason;
604 case NDMP4_NOTIFY_MOVER_HALTED: {
605 ndmp4_notify_mover_halted_post *post =
606 &nmb->body.ndmp4_notify_mover_halted_post_body;
607 self->mover_halt_reason = post->reason;
611 case NDMP4_NOTIFY_MOVER_PAUSED: {
612 ndmp4_notify_mover_paused_post *post =
613 &nmb->body.ndmp4_notify_mover_paused_post_body;
614 self->mover_pause_reason = post->reason;
615 self->mover_pause_seek_position = post->seek_position;
620 case NDMP4_LOG_MESSAGE:
621 case NDMP4_LOG_NORMAL:
622 case NDMP4_LOG_DEBUG:
623 case NDMP4_LOG_ERROR:
624 case NDMP4_LOG_WARNING: {
625 ndmp4_log_message_post *post =
626 &nmb->body.ndmp4_log_message_post_body;
627 g_debug("%s", post->entry);
632 self->last_rc = NDMCONN_CALL_STATUS_REPLY_ERROR;
633 self->conn->last_reply_error = NDMP4_ILLEGAL_STATE_ERR;
637 self->last_rc = NDMCONN_CALL_STATUS_REPLY_ERROR;
638 self->conn->last_reply_error = NDMP4_ILLEGAL_STATE_ERR;
645 /* handler for "unexpected" messages. This handles notifications which happen
646 * to arrive while the connection is reading the socket looking for a reply. */
648 ndmconn_unexpected_impl (struct ndmconn *conn, struct ndmp_msg_buf *nmb)
650 NDMPConnection *self = NDMP_CONNECTION(conn->context);
652 if (!ndmconn_handle_notify(self, nmb)) {
653 g_warning("ignoring unrecognized, unexpected packet");
656 ndmconn_free_nmb(NULL, nmb);
660 ndmp_connection_wait_for_notify(
661 NDMPConnection *self,
662 ndmp9_data_halt_reason *data_halt_reason,
663 ndmp9_mover_halt_reason *mover_halt_reason,
664 ndmp9_mover_pause_reason *mover_pause_reason,
665 guint64 *mover_pause_seek_position)
667 struct ndmp_msg_buf nmb;
669 g_assert(!self->startup_err);
671 /* initialize output parameters */
672 if (data_halt_reason)
673 *data_halt_reason = NDMP4_DATA_HALT_NA;
674 if (mover_halt_reason)
675 *mover_halt_reason = NDMP4_MOVER_HALT_NA;
676 if (mover_pause_reason)
677 *mover_pause_reason = NDMP4_MOVER_PAUSE_NA;
678 if (mover_pause_seek_position)
679 *mover_pause_seek_position = 0;
682 gboolean found = FALSE;
684 SELECT_ARG_TYPE readset;
687 /* if any desired notifications have been received, then we're
689 if (data_halt_reason && self->data_halt_reason) {
691 *data_halt_reason = self->data_halt_reason;
692 self->data_halt_reason = NDMP4_DATA_HALT_NA;
695 if (mover_halt_reason && self->mover_halt_reason) {
697 *mover_halt_reason = self->mover_halt_reason;
698 self->mover_halt_reason = NDMP4_MOVER_HALT_NA;
701 if (mover_pause_reason && self->mover_pause_reason) {
703 *mover_pause_reason = self->mover_pause_reason;
704 if (mover_pause_seek_position)
705 *mover_pause_seek_position = self->mover_pause_seek_position;
706 self->mover_pause_reason = NDMP4_MOVER_PAUSE_NA;
707 self->mover_pause_seek_position = 0;
713 /* otherwise, wait for an incoming packet and handle it, then try
714 * again. There's some select trickery here to avoid hogging the
715 * ndmlib_mutex - basically, we want to block as long as possible
716 * outside of the ndmlib_mutex critical section. This will also be
717 * useful to allow the wait to be aborted. */
718 fd = self->conn->chan.fd;
720 FD_SET(fd, &readset);
721 nfound = select(fd+1, &readset, NULL, NULL, NULL);
723 /* fall on through, blind to any errors - presumably the same error
724 * condition will be caught by ndmconn_recv_nmb. */
726 g_static_mutex_lock(&ndmlib_mutex);
727 NDMOS_MACRO_ZEROFILL(&nmb);
728 nmb.protocol_version = NDMP4VER;
729 self->last_rc = ndmconn_recv_nmb(self->conn, &nmb);
730 g_static_mutex_unlock(&ndmlib_mutex);
733 /* (nothing to free) */
737 ndmconn_handle_notify(self, &nmb);
741 typedef struct notify_data_s {
742 NDMPConnection *self;
743 ndmp9_data_halt_reason *data_halt_reason;
744 ndmp9_mover_halt_reason *mover_halt_reason;
745 ndmp9_mover_pause_reason *mover_pause_reason;
746 guint64 *mover_pause_seek_position;
751 event_handle_t *read_event;
754 static void handle_notify(void *cookie);
756 static GStaticMutex notify_mutex = G_STATIC_MUTEX_INIT;
757 static notify_data_t **notify_data = NULL;
758 static int nb_notify_data = 0;
760 ndmp_connection_wait_for_notify_with_cond(
761 NDMPConnection *self,
762 ndmp9_data_halt_reason *data_halt_reason,
763 ndmp9_mover_halt_reason *mover_halt_reason,
764 ndmp9_mover_pause_reason *mover_pause_reason,
765 guint64 *mover_pause_seek_position,
770 struct ndmp_msg_buf nmb;
771 notify_data_t *ndata;
772 gboolean found = FALSE;
776 g_static_mutex_lock(¬ify_mutex);
777 if (notify_data == NULL) {
780 notify_data = g_new0(notify_data_t *, nb_notify_data);
781 for (i=0;i<nb_notify_data;i++) {
782 notify_data[i] = g_new0(notify_data_t, 1);
785 /* find a not used notify_data */
786 ndata = *notify_data;
788 while (i< nb_notify_data && notify_data[i]->in_use > 0) {
791 if (i == nb_notify_data) {
792 int new_nb_notify_data = nb_notify_data * 2;
794 notify_data = g_realloc(notify_data,
795 sizeof(notify_data_t *) * new_nb_notify_data);
796 for (j=nb_notify_data; j<new_nb_notify_data; j++) {
797 notify_data[j] = g_new0(notify_data_t, 1);
799 nb_notify_data = new_nb_notify_data;
800 ndata = notify_data[i];
802 ndata = notify_data[i];
804 ndata->data_halt_reason= data_halt_reason;
805 ndata->mover_halt_reason= mover_halt_reason;
806 ndata->mover_pause_reason= mover_pause_reason;
807 ndata->mover_pause_seek_position = mover_pause_seek_position;
808 ndata->abort_mutex = abort_mutex;
809 ndata->abort_cond = abort_cond;
812 g_static_mutex_unlock(¬ify_mutex);
814 g_assert(!self->startup_err);
816 /* initialize output parameters */
817 if (data_halt_reason)
818 *data_halt_reason = NDMP4_DATA_HALT_NA;
819 if (mover_halt_reason)
820 *mover_halt_reason = NDMP4_MOVER_HALT_NA;
821 if (mover_pause_reason)
822 *mover_pause_reason = NDMP4_MOVER_PAUSE_NA;
823 if (mover_pause_seek_position)
824 *mover_pause_seek_position = 0;
826 /* if any desired notifications have been received, then we're
828 if (data_halt_reason && self->data_halt_reason) {
830 *data_halt_reason = self->data_halt_reason;
831 self->data_halt_reason = NDMP4_DATA_HALT_NA;
834 if (mover_halt_reason && self->mover_halt_reason) {
836 *mover_halt_reason = self->mover_halt_reason;
837 self->mover_halt_reason = NDMP4_MOVER_HALT_NA;
840 if (mover_pause_reason && self->mover_pause_reason) {
842 *mover_pause_reason = self->mover_pause_reason;
843 if (mover_pause_seek_position)
844 *mover_pause_seek_position = self->mover_pause_seek_position;
845 self->mover_pause_reason = NDMP4_MOVER_PAUSE_NA;
846 self->mover_pause_seek_position = 0;
852 /* otherwise, wait for an incoming packet and handle it, then try
853 * again. There's some select trickery here to avoid hogging the
854 * ndmlib_mutex - basically, we want to block as long as possible
855 * outside of the ndmlib_mutex critical section. This will also be
856 * useful to allow the wait to be aborted. */
858 /* handle_notify can be executed before the register exit */
859 ndata->read_event = event_create(self->conn->chan.fd,
860 EV_READFD, handle_notify, ndata);
861 event_activate(ndata->read_event);
863 while (!*cancelled && ndata->status == 2) {
864 g_cond_wait(abort_cond, abort_mutex);
866 g_static_mutex_lock(¬ify_mutex);
868 if (ndata->read_event) {
869 event_release(ndata->read_event);
870 ndata->read_event = NULL;
872 if (ndata->status == 2) {
873 ndmp_connection_mover_abort(self);
874 ndmp_connection_mover_stop(self);
876 status = ndata->status;
878 if (ndata->in_use == 3)
880 g_static_mutex_unlock(¬ify_mutex);
886 handle_notify(void *cookie)
888 notify_data_t *ndata = cookie;
889 struct ndmp_msg_buf nmb;
890 gboolean found = FALSE;
891 GCond *abort_cond = ndata->abort_cond;
892 GMutex *abort_mutex = ndata->abort_mutex;
894 g_mutex_lock(abort_mutex);
896 g_static_mutex_lock(&ndmlib_mutex);
897 NDMOS_MACRO_ZEROFILL(&nmb);
898 nmb.protocol_version = NDMP4VER;
899 ndata->self->last_rc = ndmconn_recv_nmb(ndata->self->conn, &nmb);
900 g_static_mutex_unlock(&ndmlib_mutex);
902 if (ndata->self->last_rc) {
903 /* (nothing to free) */
908 ndmconn_handle_notify(ndata->self, &nmb);
911 /* if any desired notifications have been received, then we're
913 if (ndata->data_halt_reason && ndata->self->data_halt_reason) {
915 *ndata->data_halt_reason = ndata->self->data_halt_reason;
916 ndata->self->data_halt_reason = NDMP4_DATA_HALT_NA;
919 if (ndata->mover_halt_reason && ndata->self->mover_halt_reason) {
921 *ndata->mover_halt_reason = ndata->self->mover_halt_reason;
922 ndata->self->mover_halt_reason = NDMP4_MOVER_HALT_NA;
925 if (ndata->mover_pause_reason && ndata->self->mover_pause_reason) {
927 *ndata->mover_pause_reason = ndata->self->mover_pause_reason;
928 if (ndata->mover_pause_seek_position)
929 *ndata->mover_pause_seek_position = ndata->self->mover_pause_seek_position;
930 ndata->self->mover_pause_reason = NDMP4_MOVER_PAUSE_NA;
931 ndata->self->mover_pause_seek_position = 0;
935 g_static_mutex_lock(¬ify_mutex);
936 if (ndata->in_use == 2) {
937 goto notify_done_locked;
939 g_static_mutex_unlock(¬ify_mutex);
941 g_mutex_unlock(abort_mutex);
947 g_static_mutex_lock(¬ify_mutex);
949 if (ndata->read_event) {
950 event_release(ndata->read_event);
951 ndata->read_event = NULL;
954 if (ndata->in_use == 3)
956 g_static_mutex_unlock(¬ify_mutex);
958 g_cond_broadcast(abort_cond);
959 g_mutex_unlock(abort_mutex);
966 ndmp_connection_class_init(
967 NDMPConnectionClass * c)
969 GObjectClass *goc = (GObjectClass *)c;
971 goc->finalize = finalize_impl;
973 parent_class = g_type_class_peek_parent(c);
977 ndmp_connection_get_type(void)
979 static GType type = 0;
980 if G_UNLIKELY(type == 0) {
981 static const GTypeInfo info = {
982 sizeof (NDMPConnectionClass),
983 (GBaseInitFunc) NULL,
984 (GBaseFinalizeFunc) NULL,
985 (GClassInitFunc) ndmp_connection_class_init,
986 (GClassFinalizeFunc) NULL,
987 NULL /* class_data */,
988 sizeof (NDMPConnection),
990 (GInstanceInitFunc) NULL,
994 type = g_type_register_static (G_TYPE_OBJECT, "NDMPConnection", &info,
1007 ndmp_connection_new(
1014 NDMPConnection *self = NULL;
1016 gchar *errmsg = NULL;
1017 struct ndmconn *conn = NULL;
1019 static int next_connid = 1;
1020 static GStaticMutex next_connid_mutex = G_STATIC_MUTEX_INIT;
1022 conn = ndmconn_initialize(NULL, "amanda-server");
1024 errmsg = "could not initialize ndmconn";
1028 /* set up a handler for unexpected messages, which should generally
1029 * be notifications */
1030 conn->unexpected = ndmconn_unexpected_impl;
1032 if (ndmconn_connect_host_port(conn, hostname, port, 0) != 0) {
1033 errmsg = ndmconn_get_err_msg(conn);
1034 ndmconn_destruct(conn);
1038 if (0 == g_ascii_strcasecmp(auth, "void")) {
1039 rc = 0; /* don't authenticate */
1040 } else if (0 == g_ascii_strcasecmp(auth, "none")) {
1041 rc = ndmconn_auth_none(conn);
1042 } else if (0 == g_ascii_strcasecmp(auth, "md5")) {
1043 rc = ndmconn_auth_md5(conn, username, password);
1044 } else if (0 == g_ascii_strcasecmp(auth, "text")) {
1045 rc = ndmconn_auth_text(conn, username, password);
1047 errmsg = "invalid auth type";
1052 errmsg = ndmconn_get_err_msg(conn);
1053 ndmconn_destruct(conn);
1057 if (conn->protocol_version != NDMP4VER) {
1058 errmsg = g_strdup_printf("Only NDMPv4 is supported; got NDMPv%d",
1059 conn->protocol_version);
1060 ndmconn_destruct(conn);
1064 self = NDMP_CONNECTION(g_object_new(TYPE_NDMP_CONNECTION, NULL));
1066 g_static_mutex_lock(&next_connid_mutex);
1067 self->connid = next_connid++;
1068 g_static_mutex_unlock(&next_connid_mutex);
1069 conn->context = (void *)self;
1070 g_debug("opening new NDMPConnection #%d: to %s:%d", self->connid, hostname, port);
1073 /* make a "fake" error connection if we have an error message. Note that
1074 * this object is not added to the instances hash */
1076 self = NDMP_CONNECTION(g_object_new(TYPE_NDMP_CONNECTION, NULL));
1077 self->startup_err = errmsg;