Imported Upstream version 3.1.0
[debian/amanda] / ndmp-src / ndma_comm_session.c
1 /*
2  * Copyright (c) 1998,1999,2000
3  *      Traakan, Inc., Los Altos, CA
4  *      All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice unmodified, this list of conditions, and the following
11  *    disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 /*
30  * Project:  NDMJOB
31  * Ident:    $Id: $
32  *
33  * Description:
34  *
35  */
36
37
38 #include "ndmagents.h"
39
40
41
42
43 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
44
45 int
46 ndma_client_session (struct ndm_session *sess)
47 {
48         struct ndm_job_param *  job = &sess->control_acb.job;
49         int                     rc;
50
51         rc = ndma_job_audit (job, 0, 0);
52         if (rc)
53                 return -1;
54
55         rc = ndma_session_initialize (sess);
56         if (rc) return rc;
57
58         rc = ndma_session_commission (sess);
59         if (rc) return rc;
60
61         rc = ndmca_connect_control_agent (sess);
62         if (rc) return rc;      /* already tattled */
63
64         sess->conn_open = 1;
65         sess->conn_authorized = 1;
66
67         rc = ndmca_control_agent (sess);
68
69         ndma_session_decommission (sess);
70
71         return rc;
72 }
73
74 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
75
76
77 #ifndef NDMOS_EFFECT_NO_SERVER_AGENTS
78
79 int
80 ndma_server_session (struct ndm_session *sess, int control_sock)
81 {
82         struct ndmconn *        conn;
83         int                     rc;
84         struct sockaddr         sa;
85         socklen_t               len;
86
87         rc = ndma_session_initialize (sess);
88         if (rc) return rc;
89
90         rc = ndma_session_commission (sess);
91         if (rc) return rc;
92
93         len = sizeof sa;
94         rc = getpeername (control_sock, &sa, &len);
95         if (rc < 0) {
96                 perror ("getpeername");
97         } else {
98                 ndmalogf (sess, 0, 2, "Connection accepted from %s",
99                         inet_ntoa ( ((struct sockaddr_in *)&sa)->sin_addr));
100         }
101
102         len = sizeof sa;
103         rc = getsockname (control_sock, &sa, &len);
104         if (rc < 0) {
105                 perror ("getsockname");
106         } else {
107                 ndmalogf (sess, 0, 2, "Connection accepted to %s",
108                         inet_ntoa ( ((struct sockaddr_in *)&sa)->sin_addr));
109         }
110
111         conn = ndmconn_initialize (0, "#C");
112         if (!conn) {
113                 ndmalogf (sess, 0, 0, "can't init connection");
114                 close (control_sock);
115                 return -1;
116         }
117
118         ndmos_condition_control_socket (sess, control_sock);
119
120         ndmconn_set_snoop (conn, &sess->param.log, sess->param.log_level);
121         ndmconn_accept (conn, control_sock);
122
123         conn->call = ndma_call;
124         conn->context = sess;
125
126         sess->plumb.control = conn;
127
128         while (!conn->chan.eof) {
129                 ndma_session_quantum (sess, 1000);
130         }
131
132 #if 0
133         ndmalogf (sess, 0, 2, "Connection close %s",
134                 inet_ntoa ( ((struct sockaddr_in *)sa)->sin_addr));
135 #endif
136
137         ndmconn_destruct (conn);
138
139         ndma_session_decommission (sess);
140
141         return 0;
142 }
143
144 gpointer
145 exit_on_stdin_eof_thread(gpointer data G_GNUC_UNUSED)
146 {
147     char buf[32];
148
149     for (;;) {
150         if (read(0, buf, sizeof(buf)) <= 0) {
151             printf("DONE\n");
152             fflush(stdout);
153             exit(0);
154         }
155     }
156 }
157
158 int
159 ndma_daemon_session (struct ndm_session *sess, int port, int is_test_daemon)
160 {
161         int                     listen_sock;
162         int                     conn_sock, rc;
163         socklen_t               len;
164         struct sockaddr         sa;
165
166         listen_sock = socket (AF_INET, SOCK_STREAM, 0);
167         if (listen_sock < 0) {
168                 perror ("socket");
169                 return 1;
170         }
171
172         ndmos_condition_listen_socket (sess, listen_sock);
173
174         NDMOS_MACRO_SET_SOCKADDR(&sa, 0, port);
175
176         if (bind (listen_sock, &sa, sizeof sa) < 0) {
177                 perror ("bind");
178                 return 2;
179         }
180
181         if (listen (listen_sock, 1) < 0) {
182                 perror ("listen");
183                 return 3;
184         }
185
186         if (is_test_daemon) {
187             /* the listen socket is running, so tell our invoker */
188             printf("READY\n");
189             fflush(stdout);
190
191             /* and exit when our stdin goes away */
192             g_thread_init(NULL);
193             g_thread_create(exit_on_stdin_eof_thread, NULL, FALSE, NULL);
194         }
195
196         for (;;) {
197                 len = sizeof sa;
198                 conn_sock = accept (listen_sock, &sa, &len);
199                 if (conn_sock < 0) {
200                         perror ("accept");
201                         return 4;
202                 }
203
204                 rc = fork();
205                 if (rc < 0) {
206                         perror ("fork");
207                         return 5;
208                 }
209
210                 if (rc == 0) {
211                         close (listen_sock);
212                         ndma_server_session (sess, conn_sock);
213                         exit (0);
214                 }
215                 close (conn_sock);
216         }
217
218         return 0;
219 }
220
221 #endif /* !NDMOS_EFFECT_NO_SERVER_AGENTS */
222
223
224 int
225 ndma_session_distribute_quantum (struct ndm_session *sess)
226 {
227         int             total_did_something = 0;
228         int             did_something;
229
230         do {
231                 did_something = 0;
232
233                 did_something |= ndmis_quantum (sess);
234
235 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
236                 if (sess->tape_acb.mover_state.state != NDMP9_MOVER_STATE_IDLE)
237                         did_something |= ndmta_quantum (sess);
238 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
239
240 #ifndef NDMOS_OPTION_NO_DATA_AGENT
241                 if (sess->data_acb.data_state.state != NDMP9_DATA_STATE_IDLE)
242                         did_something |= ndmda_quantum (sess);
243 #endif /* !NDMOS_OPTION_NO_DATA_AGENT */
244
245                 total_did_something |= did_something;
246
247         } while (did_something);
248
249         return total_did_something;
250 }
251
252
253 int
254 ndma_session_quantum (struct ndm_session *sess, int max_delay_secs)
255 {
256         struct ndm_image_stream *is = &sess->plumb.image_stream;
257         struct ndmconn *        conn;
258         struct ndmconn *        conntab[5];
259         int                     n_conntab;
260         struct ndmchan *        chtab[16];
261         int                     n_chtab;
262         int                     i;
263         int                     max_delay_usec = max_delay_secs * 1000;
264
265         /*
266          * Gather distinct connections
267          */
268         n_conntab = 0;
269         if ((conn = sess->plumb.control))
270                 conntab[n_conntab++] = conn;
271         if ( (conn = sess->plumb.data)
272          && conn != sess->plumb.control)
273                 conntab[n_conntab++] = conn;
274         if ( (conn = sess->plumb.tape)
275          && conn != sess->plumb.data
276          && conn != sess->plumb.control)
277                 conntab[n_conntab++] = conn;
278         if ( (conn = sess->plumb.robot)
279          && conn != sess->plumb.tape
280          && conn != sess->plumb.data
281          && conn != sess->plumb.control)
282                 conntab[n_conntab++] = conn;
283
284         /*
285          * Add connections to channel table
286          */
287         n_chtab = 0;
288         for (i = 0; i < n_conntab; i++) {
289                 conn = conntab[i];
290                 chtab[n_chtab++] = &conn->chan;
291         }
292
293 #ifndef NDMOS_OPTION_NO_DATA_AGENT
294         /*
295          * Add DATA AGENT channels to table if active (!IDLE)
296          */
297         if (sess->data_acb.data_state.state != NDMP9_DATA_STATE_IDLE) {
298                 chtab[n_chtab++] = &sess->data_acb.formatter_image;
299                 chtab[n_chtab++] = &sess->data_acb.formatter_error;
300                 chtab[n_chtab++] = &sess->data_acb.formatter_wrap;
301         }
302 #endif /* !NDMOS_OPTION_NO_DATA_AGENT */
303
304         /*
305          * Add image stream to channel table
306          */
307         if (is->remote.connect_status == NDMIS_CONN_LISTEN)
308                 chtab[n_chtab++] = &is->remote.listen_chan;
309
310         chtab[n_chtab++] = &is->chan;
311
312         /*
313          * Let TAPE and DATA AGENTS get a bit of work done.
314          * This fills channel buffers as much as possible prior to blocking.
315          */
316         if (ndma_session_distribute_quantum (sess))
317                 max_delay_usec = 0;
318
319 #if 0
320 #ifndef NDMOS_OPTION_NO_DATA_AGENT
321         /* bogus */
322         if (sess->data_acb.data_state.state == NDMP9_DATA_STATE_ACTIVE
323          && sess->data_acb.data_state.data_connection_addr.addr_type
324                                                 == NDMP9_ADDR_LOCAL) {
325                 /*
326                  * There is no remote connection to cue forward
327                  * progress between local DATA/MOVER.
328                  * So, sniff all the connections, and immediately
329                  * attempt the next tape record.
330                  */
331                  max_delay_usec = 0;
332         }
333 #endif /* !NDMOS_OPTION_NO_DATA_AGENT */
334 #endif
335
336         /*
337          * Block awaiting ready I/O. Many channel buffers
338          * will have actual I/O (read/write) performed.
339          */
340         ndmchan_quantum (chtab, n_chtab, max_delay_usec);
341
342         /*
343          * Tattle for debug
344          */
345         if (sess->param.log_level > 7) {
346                 for (i = 0; i < n_chtab; i++) {
347                         struct ndmchan *        ch = chtab[i];
348                         char                    buf[80];
349
350                         ndmchan_pp (ch, buf);
351                         ndmalogf (sess, 0, 7, "ch %s", buf);
352                 }
353         }
354
355         /*
356          * Let TAPE and DATA AGENTS get a bit more work done.
357          * This will mostly digest whatever data just arrived.
358          */
359         ndma_session_distribute_quantum (sess);
360
361         /*
362          * Dispatch any pending activity on the control connections
363          */
364         for (i = 0; i < n_conntab; i++) {
365                 conn = conntab[i];
366                 if (conn->chan.ready) {
367                         conn->chan.ready = 0;
368                         ndma_dispatch_conn (sess, conn);
369                 }
370         }
371
372         return 0;
373 }
374
375
376
377
378 int
379 ndma_session_initialize (struct ndm_session *sess)
380 {
381         ndmis_initialize (sess);
382
383 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
384         /* ndmca_initialize (sess); */
385 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
386
387 #ifndef NDMOS_OPTION_NO_DATA_AGENT
388         ndmda_initialize (sess);
389 #endif /* !NDMOS_OPTION_NO_DATA_AGENT */
390
391 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
392         ndmta_initialize (sess);
393 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
394
395 #ifndef NDMOS_OPTION_NO_ROBOT_AGENT
396         ndmra_initialize (sess);
397 #endif /* !NDMOS_OPTION_NO_ROBOT_AGENT */
398
399         return 0;
400 }
401
402 int
403 ndma_session_commission (struct ndm_session *sess)
404 {
405         ndmis_commission (sess);
406
407 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
408         /* ndmca_commission (sess); */
409 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
410
411 #ifndef NDMOS_OPTION_NO_DATA_AGENT
412         ndmda_commission (sess);
413 #endif /* !NDMOS_OPTION_NO_DATA_AGENT */
414
415 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
416         ndmta_commission (sess);
417 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
418
419 #ifndef NDMOS_OPTION_NO_ROBOT_AGENT
420         ndmra_commission (sess);
421 #endif /* !NDMOS_OPTION_NO_ROBOT_AGENT */
422
423         return 0;
424 }
425
426 int
427 ndma_session_decommission (struct ndm_session *sess)
428 {
429         ndmis_decommission (sess);
430
431 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
432         /* ndmca_decommission (sess); */
433 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
434
435 #ifndef NDMOS_OPTION_NO_DATA_AGENT
436         ndmda_decommission (sess);
437 #endif /* !NDMOS_OPTION_NO_DATA_AGENT */
438
439 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
440         ndmta_decommission (sess);
441 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
442
443 #ifndef NDMOS_OPTION_NO_ROBOT_AGENT
444         ndmra_decommission (sess);
445 #endif /* !NDMOS_OPTION_NO_ROBOT_AGENT */
446
447         return 0;
448 }
449