Imported Upstream version 3.2.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_debug("will exit on EOF from stdin");
193             g_thread_init(NULL);
194             g_thread_create(exit_on_stdin_eof_thread, NULL, FALSE, NULL);
195         }
196
197         for (;;) {
198                 len = sizeof sa;
199                 conn_sock = accept (listen_sock, &sa, &len);
200                 if (conn_sock < 0) {
201                         perror ("accept");
202                         return 4;
203                 }
204
205                 rc = fork();
206                 if (rc < 0) {
207                         perror ("fork");
208                         return 5;
209                 }
210
211                 if (rc == 0) {
212                         close (listen_sock);
213                         ndma_server_session (sess, conn_sock);
214                         exit (0);
215                 }
216                 close (conn_sock);
217         }
218
219         return 0;
220 }
221
222 #endif /* !NDMOS_EFFECT_NO_SERVER_AGENTS */
223
224
225 int
226 ndma_session_distribute_quantum (struct ndm_session *sess)
227 {
228         int             total_did_something = 0;
229         int             did_something;
230
231         do {
232                 did_something = 0;
233
234                 did_something |= ndmis_quantum (sess);
235
236 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
237                 if (sess->tape_acb.mover_state.state != NDMP9_MOVER_STATE_IDLE)
238                         did_something |= ndmta_quantum (sess);
239 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
240
241 #ifndef NDMOS_OPTION_NO_DATA_AGENT
242                 if (sess->data_acb.data_state.state != NDMP9_DATA_STATE_IDLE)
243                         did_something |= ndmda_quantum (sess);
244 #endif /* !NDMOS_OPTION_NO_DATA_AGENT */
245
246                 total_did_something |= did_something;
247
248         } while (did_something);
249
250         return total_did_something;
251 }
252
253
254 int
255 ndma_session_quantum (struct ndm_session *sess, int max_delay_secs)
256 {
257         struct ndm_image_stream *is = &sess->plumb.image_stream;
258         struct ndmconn *        conn;
259         struct ndmconn *        conntab[5];
260         int                     n_conntab;
261         struct ndmchan *        chtab[16];
262         int                     n_chtab;
263         int                     i;
264         int                     max_delay_usec = max_delay_secs * 1000;
265
266         /*
267          * Gather distinct connections
268          */
269         n_conntab = 0;
270         if ((conn = sess->plumb.control))
271                 conntab[n_conntab++] = conn;
272         if ( (conn = sess->plumb.data)
273          && conn != sess->plumb.control)
274                 conntab[n_conntab++] = conn;
275         if ( (conn = sess->plumb.tape)
276          && conn != sess->plumb.data
277          && conn != sess->plumb.control)
278                 conntab[n_conntab++] = conn;
279         if ( (conn = sess->plumb.robot)
280          && conn != sess->plumb.tape
281          && conn != sess->plumb.data
282          && conn != sess->plumb.control)
283                 conntab[n_conntab++] = conn;
284
285         /*
286          * Add connections to channel table
287          */
288         n_chtab = 0;
289         for (i = 0; i < n_conntab; i++) {
290                 conn = conntab[i];
291                 chtab[n_chtab++] = &conn->chan;
292         }
293
294 #ifndef NDMOS_OPTION_NO_DATA_AGENT
295         /*
296          * Add DATA AGENT channels to table if active (!IDLE)
297          */
298         if (sess->data_acb.data_state.state != NDMP9_DATA_STATE_IDLE) {
299                 chtab[n_chtab++] = &sess->data_acb.formatter_image;
300                 chtab[n_chtab++] = &sess->data_acb.formatter_error;
301                 chtab[n_chtab++] = &sess->data_acb.formatter_wrap;
302         }
303 #endif /* !NDMOS_OPTION_NO_DATA_AGENT */
304
305         /*
306          * Add image stream to channel table
307          */
308         if (is->remote.connect_status == NDMIS_CONN_LISTEN)
309                 chtab[n_chtab++] = &is->remote.listen_chan;
310
311         chtab[n_chtab++] = &is->chan;
312
313         /*
314          * Let TAPE and DATA AGENTS get a bit of work done.
315          * This fills channel buffers as much as possible prior to blocking.
316          */
317         if (ndma_session_distribute_quantum (sess))
318                 max_delay_usec = 0;
319
320 #if 0
321 #ifndef NDMOS_OPTION_NO_DATA_AGENT
322         /* bogus */
323         if (sess->data_acb.data_state.state == NDMP9_DATA_STATE_ACTIVE
324          && sess->data_acb.data_state.data_connection_addr.addr_type
325                                                 == NDMP9_ADDR_LOCAL) {
326                 /*
327                  * There is no remote connection to cue forward
328                  * progress between local DATA/MOVER.
329                  * So, sniff all the connections, and immediately
330                  * attempt the next tape record.
331                  */
332                  max_delay_usec = 0;
333         }
334 #endif /* !NDMOS_OPTION_NO_DATA_AGENT */
335 #endif
336
337         /*
338          * Block awaiting ready I/O. Many channel buffers
339          * will have actual I/O (read/write) performed.
340          */
341         ndmchan_quantum (chtab, n_chtab, max_delay_usec);
342
343         /*
344          * Tattle for debug
345          */
346         if (sess->param.log_level > 7) {
347                 for (i = 0; i < n_chtab; i++) {
348                         struct ndmchan *        ch = chtab[i];
349                         char                    buf[80];
350
351                         ndmchan_pp (ch, buf);
352                         ndmalogf (sess, 0, 7, "ch %s", buf);
353                 }
354         }
355
356         /*
357          * Let TAPE and DATA AGENTS get a bit more work done.
358          * This will mostly digest whatever data just arrived.
359          */
360         ndma_session_distribute_quantum (sess);
361
362         /*
363          * Dispatch any pending activity on the control connections
364          */
365         for (i = 0; i < n_conntab; i++) {
366                 conn = conntab[i];
367                 if (conn->chan.ready) {
368                         conn->chan.ready = 0;
369                         ndma_dispatch_conn (sess, conn);
370                 }
371         }
372
373         return 0;
374 }
375
376
377
378
379 int
380 ndma_session_initialize (struct ndm_session *sess)
381 {
382         ndmis_initialize (sess);
383
384 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
385         /* ndmca_initialize (sess); */
386 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
387
388 #ifndef NDMOS_OPTION_NO_DATA_AGENT
389         ndmda_initialize (sess);
390 #endif /* !NDMOS_OPTION_NO_DATA_AGENT */
391
392 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
393         ndmta_initialize (sess);
394 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
395
396 #ifndef NDMOS_OPTION_NO_ROBOT_AGENT
397         ndmra_initialize (sess);
398 #endif /* !NDMOS_OPTION_NO_ROBOT_AGENT */
399
400         return 0;
401 }
402
403 int
404 ndma_session_commission (struct ndm_session *sess)
405 {
406         ndmis_commission (sess);
407
408 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
409         /* ndmca_commission (sess); */
410 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
411
412 #ifndef NDMOS_OPTION_NO_DATA_AGENT
413         ndmda_commission (sess);
414 #endif /* !NDMOS_OPTION_NO_DATA_AGENT */
415
416 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
417         ndmta_commission (sess);
418 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
419
420 #ifndef NDMOS_OPTION_NO_ROBOT_AGENT
421         ndmra_commission (sess);
422 #endif /* !NDMOS_OPTION_NO_ROBOT_AGENT */
423
424         return 0;
425 }
426
427 int
428 ndma_session_decommission (struct ndm_session *sess)
429 {
430         ndmis_decommission (sess);
431
432 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
433         /* ndmca_decommission (sess); */
434 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
435
436 #ifndef NDMOS_OPTION_NO_DATA_AGENT
437         ndmda_decommission (sess);
438 #endif /* !NDMOS_OPTION_NO_DATA_AGENT */
439
440 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
441         ndmta_decommission (sess);
442 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
443
444 #ifndef NDMOS_OPTION_NO_ROBOT_AGENT
445         ndmra_decommission (sess);
446 #endif /* !NDMOS_OPTION_NO_ROBOT_AGENT */
447
448         return 0;
449 }
450