Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : * Samba internal messaging functions
4 : * Copyright (C) 2014 by Volker Lendecke
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 <talloc.h>
22 : #include "messages_dgm.h"
23 : #include "messages_dgm_ref.h"
24 : #include "lib/util/debug.h"
25 : #include "lib/util/dlinklist.h"
26 :
27 : struct msg_dgm_ref {
28 : struct msg_dgm_ref *prev, *next;
29 : struct messaging_dgm_fde *fde;
30 : void (*recv_cb)(struct tevent_context *ev,
31 : const uint8_t *msg, size_t msg_len,
32 : int *fds, size_t num_fds, void *private_data);
33 : void *recv_cb_private_data;
34 : };
35 :
36 : static pid_t dgm_pid = 0;
37 : static struct msg_dgm_ref *refs = NULL;
38 : static struct msg_dgm_ref *next_ref = NULL;
39 :
40 : static int msg_dgm_ref_destructor(struct msg_dgm_ref *r);
41 : static void msg_dgm_ref_recv(struct tevent_context *ev,
42 : const uint8_t *msg, size_t msg_len,
43 : int *fds, size_t num_fds, void *private_data);
44 :
45 508628 : void *messaging_dgm_ref(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
46 : uint64_t *unique,
47 : const char *socket_dir,
48 : const char *lockfile_dir,
49 : void (*recv_cb)(struct tevent_context *ev,
50 : const uint8_t *msg, size_t msg_len,
51 : int *fds, size_t num_fds,
52 : void *private_data),
53 : void *recv_cb_private_data,
54 : int *err)
55 : {
56 18190 : struct msg_dgm_ref *result, *tmp_refs;
57 :
58 508628 : result = talloc(mem_ctx, struct msg_dgm_ref);
59 508628 : if (result == NULL) {
60 0 : *err = ENOMEM;
61 0 : return NULL;
62 : }
63 508628 : result->fde = NULL;
64 :
65 508628 : tmp_refs = refs;
66 :
67 508628 : if ((refs != NULL) && (dgm_pid != tevent_cached_getpid())) {
68 : /*
69 : * Have to reinit after fork
70 : */
71 23212 : messaging_dgm_destroy();
72 23212 : refs = NULL;
73 : }
74 :
75 508628 : if (refs == NULL) {
76 1140 : int ret;
77 :
78 59909 : ret = messaging_dgm_init(ev, unique, socket_dir, lockfile_dir,
79 : msg_dgm_ref_recv, NULL);
80 59909 : DBG_DEBUG("messaging_dgm_init returned %s\n", strerror(ret));
81 59909 : if (ret != 0) {
82 13 : DEBUG(10, ("messaging_dgm_init failed: %s\n",
83 : strerror(ret)));
84 13 : TALLOC_FREE(result);
85 13 : *err = ret;
86 13 : return NULL;
87 : }
88 59896 : dgm_pid = tevent_cached_getpid();
89 : } else {
90 17050 : int ret;
91 448719 : ret = messaging_dgm_get_unique(tevent_cached_getpid(), unique);
92 448719 : DBG_DEBUG("messaging_dgm_get_unique returned %s\n",
93 : strerror(ret));
94 448719 : if (ret != 0) {
95 0 : TALLOC_FREE(result);
96 0 : *err = ret;
97 0 : return NULL;
98 : }
99 :
100 : }
101 :
102 508615 : result->fde = messaging_dgm_register_tevent_context(result, ev);
103 508615 : if (result->fde == NULL) {
104 0 : TALLOC_FREE(result);
105 0 : *err = ENOMEM;
106 0 : return NULL;
107 : }
108 :
109 508615 : DBG_DEBUG("unique = %"PRIu64"\n", *unique);
110 :
111 508615 : refs = tmp_refs;
112 :
113 508615 : result->recv_cb = recv_cb;
114 508615 : result->recv_cb_private_data = recv_cb_private_data;
115 508615 : DLIST_ADD(refs, result);
116 508615 : talloc_set_destructor(result, msg_dgm_ref_destructor);
117 :
118 508615 : return result;
119 : }
120 :
121 189896 : static void msg_dgm_ref_recv(struct tevent_context *ev,
122 : const uint8_t *msg, size_t msg_len,
123 : int *fds, size_t num_fds, void *private_data)
124 : {
125 66684 : struct msg_dgm_ref *r;
126 :
127 : /*
128 : * We have to broadcast incoming messages to all refs. The first ref
129 : * that grabs the fd's will get them.
130 : */
131 693332 : for (r = refs; r != NULL; r = next_ref) {
132 132931 : bool active;
133 :
134 503436 : next_ref = r->next;
135 :
136 503436 : active = messaging_dgm_fde_active(r->fde);
137 503436 : if (!active) {
138 : /*
139 : * r's tevent_context has died.
140 : */
141 38781 : continue;
142 : }
143 :
144 464655 : r->recv_cb(ev, msg, msg_len, fds, num_fds,
145 : r->recv_cb_private_data);
146 : }
147 189896 : }
148 :
149 583470 : static int msg_dgm_ref_destructor(struct msg_dgm_ref *r)
150 : {
151 583470 : if (refs == NULL) {
152 0 : abort();
153 : }
154 :
155 583470 : if (r == next_ref) {
156 65 : next_ref = r->next;
157 : }
158 :
159 583470 : DLIST_REMOVE(refs, r);
160 :
161 583470 : TALLOC_FREE(r->fde);
162 :
163 583470 : DBG_DEBUG("refs=%p\n", refs);
164 :
165 583470 : if (refs == NULL) {
166 76790 : messaging_dgm_destroy();
167 : }
168 583470 : return 0;
169 : }
|