ctdb-common: Add wait_send/wait_recv to sock_daemon_funcs
[samba.git] / ctdb / common / sock_daemon.c
1 /*
2    A server based on unix domain socket
3
4    Copyright (C) Amitay Isaacs  2016
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "replace.h"
21 #include "system/filesys.h"
22 #include "system/network.h"
23 #include "system/wait.h"
24
25 #include <talloc.h>
26 #include <tevent.h>
27
28 #include "lib/async_req/async_sock.h"
29 #include "lib/util/debug.h"
30 #include "lib/util/blocking.h"
31 #include "lib/util/dlinklist.h"
32 #include "lib/util/tevent_unix.h"
33
34 #include "common/logging.h"
35 #include "common/reqid.h"
36 #include "common/comm.h"
37 #include "common/pidfile.h"
38 #include "common/sock_daemon.h"
39
40 struct sock_socket {
41         struct sock_socket *prev, *next;
42
43         const char *sockpath;
44         struct sock_socket_funcs *funcs;
45         void *private_data;
46
47         int fd;
48         struct tevent_req *req;
49 };
50
51 struct sock_client {
52         struct sock_client *prev, *next;
53
54         struct tevent_req *req;
55         struct sock_client_context *client_ctx;
56 };
57
58 struct sock_client_context {
59         struct tevent_context *ev;
60         struct sock_socket *sock;
61         int fd;
62         struct comm_context *comm;
63
64         struct sock_client *client;
65 };
66
67 struct sock_daemon_context {
68         struct sock_daemon_funcs *funcs;
69         void *private_data;
70
71         struct pidfile_context *pid_ctx;
72         struct sock_socket *socket_list;
73 };
74
75 /*
76  * Process a single client
77  */
78
79 static void sock_client_read_handler(uint8_t *buf, size_t buflen,
80                                      void *private_data);
81 static void sock_client_read_done(struct tevent_req *subreq);
82 static void sock_client_dead_handler(void *private_data);
83 static int sock_client_context_destructor(
84                                 struct sock_client_context *client_ctx);
85
86 static int sock_client_context_init(TALLOC_CTX *mem_ctx,
87                                     struct tevent_context *ev,
88                                     struct sock_socket *sock,
89                                     int client_fd,
90                                     struct sock_client *client,
91                                     struct sock_client_context **result)
92 {
93         struct sock_client_context *client_ctx;
94         int ret;
95
96         client_ctx = talloc_zero(mem_ctx, struct sock_client_context);
97         if (client_ctx == NULL) {
98                 return ENOMEM;
99         }
100
101         client_ctx->ev = ev;
102         client_ctx->sock = sock;
103         client_ctx->fd = client_fd;
104         client_ctx->client = client;
105
106         ret = comm_setup(client_ctx, ev, client_fd,
107                          sock_client_read_handler, client_ctx,
108                          sock_client_dead_handler, client_ctx,
109                          &client_ctx->comm);
110         if (ret != 0) {
111                 talloc_free(client_ctx);
112                 return ret;
113         }
114
115         if (sock->funcs->connect != NULL) {
116                 bool status;
117
118                 status = sock->funcs->connect(client_ctx, sock->private_data);
119                 if (! status) {
120                         talloc_free(client_ctx);
121                         close(client_fd);
122                         return 0;
123                 }
124         }
125
126         talloc_set_destructor(client_ctx, sock_client_context_destructor);
127
128         *result = client_ctx;
129         return 0;
130 }
131
132 static void sock_client_read_handler(uint8_t *buf, size_t buflen,
133                                      void *private_data)
134 {
135         struct sock_client_context *client_ctx = talloc_get_type_abort(
136                 private_data, struct sock_client_context);
137         struct sock_socket *sock = client_ctx->sock;
138         struct tevent_req *subreq;
139
140         subreq = sock->funcs->read_send(client_ctx, client_ctx->ev,
141                                         client_ctx, buf, buflen,
142                                         sock->private_data);
143         if (subreq == NULL) {
144                 talloc_free(client_ctx);
145                 return;
146         }
147         tevent_req_set_callback(subreq, sock_client_read_done, client_ctx);
148 }
149
150 static void sock_client_read_done(struct tevent_req *subreq)
151 {
152         struct sock_client_context *client_ctx = tevent_req_callback_data(
153                 subreq, struct sock_client_context);
154         struct sock_socket *sock = client_ctx->sock;
155         int ret;
156         bool status;
157
158         status = sock->funcs->read_recv(subreq, &ret);
159         if (! status) {
160                 D_ERR("client read failed with ret=%d\n", ret);
161                 talloc_free(client_ctx);
162         }
163 }
164
165 static void sock_client_dead_handler(void *private_data)
166 {
167         struct sock_client_context *client_ctx = talloc_get_type_abort(
168                 private_data, struct sock_client_context);
169         struct sock_socket *sock = client_ctx->sock;
170
171         if (sock->funcs->disconnect != NULL) {
172                 sock->funcs->disconnect(client_ctx, sock->private_data);
173         }
174
175         talloc_free(client_ctx);
176 }
177
178 static int sock_client_context_destructor(
179                                 struct sock_client_context *client_ctx)
180 {
181         TALLOC_FREE(client_ctx->client);
182         TALLOC_FREE(client_ctx->comm);
183         if (client_ctx->fd != -1) {
184                 close(client_ctx->fd);
185                 client_ctx->fd = -1;
186         }
187
188         return 0;
189 }
190
191 /*
192  * Process a single listening socket
193  */
194
195 static int socket_setup(const char *sockpath, bool remove_before_use)
196 {
197         struct sockaddr_un addr;
198         size_t len;
199         int ret, fd;
200
201         memset(&addr, 0, sizeof(addr));
202         addr.sun_family = AF_UNIX;
203
204         len = strlcpy(addr.sun_path, sockpath, sizeof(addr.sun_path));
205         if (len >= sizeof(addr.sun_path)) {
206                 D_ERR("socket path too long: %s\n", sockpath);
207                 return -1;
208         }
209
210         fd = socket(AF_UNIX, SOCK_STREAM, 0);
211         if (fd == -1) {
212                 D_ERR("socket create failed - %s\n", sockpath);
213                 return -1;
214         }
215
216         ret = set_blocking(fd, false);
217         if (ret != 0) {
218                 D_ERR("socket set nonblocking failed - %s\n", sockpath);
219                 close(fd);
220                 return -1;
221         }
222
223         if (remove_before_use) {
224                 unlink(sockpath);
225         }
226
227         ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
228         if (ret != 0) {
229                 D_ERR("socket bind failed - %s\n", sockpath);
230                 close(fd);
231                 return -1;
232         }
233
234         ret = listen(fd, 10);
235         if (ret != 0) {
236                 D_ERR("socket listen failed - %s\n", sockpath);
237                 close(fd);
238                 return -1;
239         }
240
241         return fd;
242 }
243
244 static int sock_socket_destructor(struct sock_socket *sock);
245
246 static int sock_socket_init(TALLOC_CTX *mem_ctx, const char *sockpath,
247                             struct sock_socket_funcs *funcs,
248                             void *private_data,
249                             bool remove_before_use,
250                             struct sock_socket **result)
251 {
252         struct sock_socket *sock;
253
254         if (funcs == NULL) {
255                 return EINVAL;
256         }
257         if (funcs->read_send == NULL || funcs->read_recv == NULL) {
258                 return EINVAL;
259         }
260
261         sock = talloc_zero(mem_ctx, struct sock_socket);
262         if (sock == NULL) {
263                 return ENOMEM;
264         }
265
266         sock->sockpath = sockpath;
267         sock->funcs = funcs;
268         sock->private_data = private_data;
269
270         sock->fd = socket_setup(sockpath, remove_before_use);
271         if (sock->fd == -1) {
272                 talloc_free(sock);
273                 return EIO;
274         }
275
276         talloc_set_destructor(sock, sock_socket_destructor);
277
278         *result = sock;
279         return 0;
280 }
281
282 static int sock_socket_destructor(struct sock_socket *sock)
283 {
284         if (sock->fd != -1) {
285                 close(sock->fd);
286                 sock->fd = -1;
287         }
288
289         unlink(sock->sockpath);
290         return 0;
291 }
292
293
294 struct sock_socket_start_state {
295         struct tevent_context *ev;
296         struct sock_socket *sock;
297
298         struct sock_client *client_list;
299 };
300
301 static int sock_socket_start_state_destructor(
302                                 struct sock_socket_start_state *state);
303 static void sock_socket_start_new_client(struct tevent_req *subreq);
304 static int sock_socket_start_client_destructor(struct sock_client *client);
305
306 static struct tevent_req *sock_socket_start_send(TALLOC_CTX *mem_ctx,
307                                                  struct tevent_context *ev,
308                                                  struct sock_socket *sock)
309 {
310         struct tevent_req *req, *subreq;
311         struct sock_socket_start_state *state;
312
313         req = tevent_req_create(mem_ctx, &state,
314                                 struct sock_socket_start_state);
315         if (req == NULL) {
316                 return NULL;
317         }
318
319         state->ev = ev;
320         state->sock = sock;
321
322         talloc_set_destructor(state, sock_socket_start_state_destructor);
323
324         subreq = accept_send(state, ev, sock->fd);
325         if (tevent_req_nomem(subreq, req)) {
326                 return tevent_req_post(req, ev);
327         }
328         tevent_req_set_callback(subreq, sock_socket_start_new_client, req);
329
330         return req;
331 }
332
333 static int sock_socket_start_state_destructor(
334                                 struct sock_socket_start_state *state)
335 {
336         struct sock_client *client;
337
338         while ((client = state->client_list) != NULL) {
339                 talloc_free(client);
340         }
341
342         return 0;
343 }
344
345 static void sock_socket_start_new_client(struct tevent_req *subreq)
346 {
347         struct tevent_req *req = tevent_req_callback_data(
348                 subreq, struct tevent_req);
349         struct sock_socket_start_state *state = tevent_req_data(
350                 req, struct sock_socket_start_state);
351         struct sock_client *client;
352         int client_fd, ret;
353
354         client_fd = accept_recv(subreq, NULL, NULL, &ret);
355         TALLOC_FREE(subreq);
356         if (client_fd == -1) {
357                 D_ERR("failed to accept new connection\n");
358         }
359
360         subreq = accept_send(state, state->ev, state->sock->fd);
361         if (tevent_req_nomem(subreq, req)) {
362                 return;
363         }
364         tevent_req_set_callback(subreq, sock_socket_start_new_client, req);
365
366         if (client_fd == -1) {
367                 return;
368         }
369
370         client = talloc_zero(state, struct sock_client);
371         if (tevent_req_nomem(client, req)) {
372                 close(client_fd);
373                 return;
374         }
375
376         client->req = req;
377
378         ret = sock_client_context_init(client, state->ev, state->sock,
379                                        client_fd, client, &client->client_ctx);
380         if (ret != 0) {
381                 talloc_free(client);
382                 return;
383         }
384
385         talloc_set_destructor(client, sock_socket_start_client_destructor);
386         DLIST_ADD(state->client_list, client);
387 }
388
389 static int sock_socket_start_client_destructor(struct sock_client *client)
390 {
391         struct sock_socket_start_state *state = tevent_req_data(
392                 client->req, struct sock_socket_start_state);
393
394         DLIST_REMOVE(state->client_list, client);
395         TALLOC_FREE(client->client_ctx);
396
397         return 0;
398 }
399
400 static bool sock_socket_start_recv(struct tevent_req *req, int *perr)
401 {
402         struct sock_socket_start_state *state = tevent_req_data(
403                 req, struct sock_socket_start_state);
404         int ret;
405
406         state->sock->req = NULL;
407
408         if (tevent_req_is_unix_error(req, &ret)) {
409                 if (perr != NULL) {
410                         *perr = ret;
411                 }
412                 return false;
413         }
414
415         return true;
416 }
417
418 /*
419  * Send message to a client
420  */
421
422 struct tevent_req *sock_socket_write_send(TALLOC_CTX *mem_ctx,
423                                          struct tevent_context *ev,
424                                          struct sock_client_context *client_ctx,
425                                          uint8_t *buf, size_t buflen)
426 {
427         struct tevent_req *req;
428
429         req = comm_write_send(mem_ctx, ev, client_ctx->comm, buf, buflen);
430
431         return req;
432 }
433
434 bool sock_socket_write_recv(struct tevent_req *req, int *perr)
435 {
436         int ret;
437         bool status;
438
439         status = comm_write_recv(req, &ret);
440         if (! status) {
441                 if (perr != NULL) {
442                         *perr = ret;
443                 }
444         }
445
446         return status;
447 }
448
449 /*
450  * Socket daemon
451  */
452
453 int sock_daemon_setup(TALLOC_CTX *mem_ctx, const char *daemon_name,
454                       const char *logging, const char *debug_level,
455                       const char *pidfile,
456                       struct sock_daemon_funcs *funcs,
457                       void *private_data,
458                       struct sock_daemon_context **out)
459 {
460         struct sock_daemon_context *sockd;
461         int ret;
462
463         sockd = talloc_zero(mem_ctx, struct sock_daemon_context);
464         if (sockd == NULL) {
465                 return ENOMEM;
466         }
467
468         sockd->funcs = funcs;
469         sockd->private_data = private_data;
470
471         ret = logging_init(sockd, logging, debug_level, daemon_name);
472         if (ret != 0) {
473                 fprintf(stderr,
474                         "Failed to initialize logging, logging=%s, debug=%s\n",
475                         logging, debug_level);
476                 return ret;
477         }
478
479         if (pidfile != NULL) {
480                 ret = pidfile_create(sockd, pidfile, &sockd->pid_ctx);
481                 if (ret != 0) {
482                         talloc_free(sockd);
483                         return EEXIST;
484                 }
485         }
486
487         *out = sockd;
488         return 0;
489 }
490
491 int sock_daemon_add_unix(struct sock_daemon_context *sockd,
492                          const char *sockpath,
493                          struct sock_socket_funcs *funcs,
494                          void *private_data)
495 {
496         struct sock_socket *sock;
497         int ret;
498         bool remove_before_use = false;
499
500         remove_before_use = (sockd->pid_ctx != NULL) ? true : false;
501
502         ret = sock_socket_init(sockd, sockpath, funcs, private_data,
503                                remove_before_use, &sock);
504         if (ret != 0) {
505                 return ret;
506         }
507
508         D_NOTICE("listening on %s\n", sockpath);
509
510         DLIST_ADD(sockd->socket_list, sock);
511         return 0;
512 }
513
514 /*
515  * Run socket daemon
516  */
517
518 struct sock_daemon_run_state {
519         struct tevent_context *ev;
520         struct sock_daemon_context *sockd;
521         pid_t pid_watch;
522
523         int fd;
524 };
525
526 static void sock_daemon_run_started(struct tevent_req *subreq);
527 static void sock_daemon_run_signal_handler(struct tevent_context *ev,
528                                            struct tevent_signal *se,
529                                            int signum, int count, void *siginfo,
530                                            void *private_data);
531 static void sock_daemon_run_reconfigure(struct tevent_req *req);
532 static void sock_daemon_run_shutdown(struct tevent_req *req);
533 static void sock_daemon_run_socket_fail(struct tevent_req *subreq);
534 static void sock_daemon_run_watch_pid(struct tevent_req *subreq);
535 static void sock_daemon_run_wait_done(struct tevent_req *subreq);
536
537 struct tevent_req *sock_daemon_run_send(TALLOC_CTX *mem_ctx,
538                                         struct tevent_context *ev,
539                                         struct sock_daemon_context *sockd,
540                                         pid_t pid_watch)
541 {
542         struct tevent_req *req, *subreq;
543         struct sock_daemon_run_state *state;
544         struct tevent_signal *se;
545         struct sock_socket *sock;
546
547         req = tevent_req_create(mem_ctx, &state,
548                                 struct sock_daemon_run_state);
549         if (req == NULL) {
550                 return NULL;
551         }
552
553         state->ev = ev;
554         state->sockd = sockd;
555         state->pid_watch = pid_watch;
556         state->fd  = -1;
557
558         subreq = tevent_wakeup_send(state, ev,
559                                     tevent_timeval_current_ofs(0, 0));
560         if (tevent_req_nomem(subreq, req)) {
561                 return tevent_req_post(req, ev);
562         }
563         tevent_req_set_callback(subreq, sock_daemon_run_started, req);
564
565         se = tevent_add_signal(ev, state, SIGHUP, 0,
566                                sock_daemon_run_signal_handler, req);
567         if (tevent_req_nomem(se, req)) {
568                 return tevent_req_post(req, ev);
569         }
570
571         se = tevent_add_signal(ev, state, SIGUSR1, 0,
572                                sock_daemon_run_signal_handler, req);
573         if (tevent_req_nomem(se, req)) {
574                 return tevent_req_post(req, ev);
575         }
576
577         se = tevent_add_signal(ev, state, SIGINT, 0,
578                                sock_daemon_run_signal_handler, req);
579         if (tevent_req_nomem(se, req)) {
580                 return tevent_req_post(req, ev);
581         }
582
583         se = tevent_add_signal(ev, state, SIGTERM, 0,
584                                sock_daemon_run_signal_handler, req);
585         if (tevent_req_nomem(se, req)) {
586                 return tevent_req_post(req, ev);
587         }
588
589         for (sock = sockd->socket_list; sock != NULL; sock = sock->next) {
590                 subreq = sock_socket_start_send(state, ev, sock);
591                 if (tevent_req_nomem(subreq, req)) {
592                         return tevent_req_post(req, ev);
593                 }
594                 tevent_req_set_callback(subreq, sock_daemon_run_socket_fail,
595                                         req);
596
597                 sock->req = subreq;
598         }
599
600         if (pid_watch > 1) {
601                 subreq = tevent_wakeup_send(state, ev,
602                                             tevent_timeval_current_ofs(1,0));
603                 if (tevent_req_nomem(subreq, req)) {
604                         return tevent_req_post(req, ev);
605                 }
606                 tevent_req_set_callback(subreq, sock_daemon_run_watch_pid,
607                                         req);
608         }
609
610         if (sockd->funcs != NULL && sockd->funcs->wait_send != NULL &&
611             sockd->funcs->wait_recv != NULL) {
612                 subreq = sockd->funcs->wait_send(state, ev,
613                                                  sockd->private_data);
614                 if (tevent_req_nomem(subreq, req)) {
615                         return tevent_req_post(req, ev);
616                 }
617                 tevent_req_set_callback(subreq, sock_daemon_run_wait_done,
618                                         req);
619         }
620
621         return req;
622 }
623
624 static void sock_daemon_run_started(struct tevent_req *subreq)
625 {
626         struct tevent_req *req = tevent_req_callback_data(
627                 subreq, struct tevent_req);
628         struct sock_daemon_run_state *state = tevent_req_data(
629                 req, struct sock_daemon_run_state);
630         struct sock_daemon_context *sockd = state->sockd;
631
632         D_NOTICE("daemon started, pid=%u\n", getpid());
633
634         if (sockd->funcs != NULL && sockd->funcs->startup != NULL) {
635                 sockd->funcs->startup(sockd->private_data);
636         }
637 }
638
639 static void sock_daemon_run_signal_handler(struct tevent_context *ev,
640                                            struct tevent_signal *se,
641                                            int signum, int count, void *siginfo,
642                                            void *private_data)
643 {
644         struct tevent_req *req = talloc_get_type_abort(
645                 private_data, struct tevent_req);
646
647         D_NOTICE("Received signal %d\n", signum);
648
649         if (signum == SIGHUP || signum == SIGUSR1) {
650                 sock_daemon_run_reconfigure(req);
651                 return;
652         }
653
654         if (signum == SIGINT || signum == SIGTERM) {
655                 sock_daemon_run_shutdown(req);
656                 tevent_req_error(req, EINTR);
657         }
658 }
659
660 static void sock_daemon_run_reconfigure(struct tevent_req *req)
661 {
662         struct sock_daemon_run_state *state = tevent_req_data(
663                 req, struct sock_daemon_run_state);
664         struct sock_daemon_context *sockd = state->sockd;
665
666         if (sockd->funcs != NULL && sockd->funcs->reconfigure != NULL) {
667                 sockd->funcs->reconfigure(sockd->private_data);
668         }
669 }
670
671 static void sock_daemon_run_shutdown(struct tevent_req *req)
672 {
673         struct sock_daemon_run_state *state = tevent_req_data(
674                 req, struct sock_daemon_run_state);
675         struct sock_daemon_context *sockd = state->sockd;
676         struct sock_socket *sock;
677
678         D_NOTICE("Shutting down\n");
679
680         while ((sock = sockd->socket_list) != NULL) {
681                 DLIST_REMOVE(sockd->socket_list, sock);
682                 TALLOC_FREE(sock->req);
683                 TALLOC_FREE(sock);
684         }
685
686         if (sockd->funcs != NULL && sockd->funcs->shutdown != NULL) {
687                 sockd->funcs->shutdown(sockd->private_data);
688         }
689
690         TALLOC_FREE(sockd->pid_ctx);
691 }
692
693 static void sock_daemon_run_socket_fail(struct tevent_req *subreq)
694 {
695         struct tevent_req *req = tevent_req_callback_data(
696                 subreq, struct tevent_req);
697         int ret = 0;
698         bool status;
699
700         status = sock_socket_start_recv(subreq, &ret);
701         TALLOC_FREE(subreq);
702         sock_daemon_run_shutdown(req);
703         if (! status) {
704                 tevent_req_error(req, ret);
705         } else {
706                 tevent_req_done(req);
707         }
708 }
709
710 static void sock_daemon_run_watch_pid(struct tevent_req *subreq)
711 {
712         struct tevent_req *req = tevent_req_callback_data(
713                 subreq, struct tevent_req);
714         struct sock_daemon_run_state *state = tevent_req_data(
715                 req, struct sock_daemon_run_state);
716         int ret;
717         bool status;
718
719         status = tevent_wakeup_recv(subreq);
720         TALLOC_FREE(subreq);
721         if (! status) {
722                 tevent_req_error(req, EIO);
723                 return;
724         }
725
726         ret = kill(state->pid_watch, 0);
727         if (ret == -1) {
728                 if (errno == ESRCH) {
729                         D_ERR("PID %d gone away, exiting\n", state->pid_watch);
730                         sock_daemon_run_shutdown(req);
731                         tevent_req_error(req, ESRCH);
732                         return;
733                 } else {
734                         D_ERR("Failed to check PID status %d, ret=%d\n",
735                               state->pid_watch, errno);
736                 }
737         }
738
739         subreq = tevent_wakeup_send(state, state->ev,
740                                     tevent_timeval_current_ofs(5,0));
741         if (tevent_req_nomem(subreq, req)) {
742                 return;
743         }
744         tevent_req_set_callback(subreq, sock_daemon_run_watch_pid, req);
745 }
746
747 static void sock_daemon_run_wait_done(struct tevent_req *subreq)
748 {
749         struct tevent_req *req = tevent_req_callback_data(
750                 subreq, struct tevent_req);
751         struct sock_daemon_run_state *state = tevent_req_data(
752                 req, struct sock_daemon_run_state);
753         struct sock_daemon_context *sockd = state->sockd;
754         int ret;
755         bool status;
756
757         status = sockd->funcs->wait_recv(subreq, &ret);
758         TALLOC_FREE(subreq);
759         sock_daemon_run_shutdown(req);
760         if (! status) {
761                 tevent_req_error(req, ret);
762         } else {
763                 tevent_req_done(req);
764         }
765 }
766
767 bool sock_daemon_run_recv(struct tevent_req *req, int *perr)
768 {
769         int ret;
770
771         if (tevent_req_is_unix_error(req, &ret)) {
772                 if (perr != NULL) {
773                         *perr = ret;
774                 }
775                 return false;
776         }
777
778         return true;
779 }
780
781 int sock_daemon_run(struct tevent_context *ev,
782                     struct sock_daemon_context *sockd,
783                     pid_t pid_watch)
784 {
785         struct tevent_req *req;
786         int ret;
787         bool status;
788
789         req = sock_daemon_run_send(ev, ev, sockd, pid_watch);
790         if (req == NULL) {
791                 return ENOMEM;
792         }
793
794         tevent_req_poll(req, ev);
795
796         status = sock_daemon_run_recv(req, &ret);
797         TALLOC_FREE(req);
798         if (! status) {
799                 return ret;
800         }
801
802         return 0;
803 }