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 500256 : 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 18106 : struct msg_dgm_ref *result, *tmp_refs;
57 :
58 500256 : result = talloc(mem_ctx, struct msg_dgm_ref);
59 500256 : if (result == NULL) {
60 0 : *err = ENOMEM;
61 0 : return NULL;
62 : }
63 500256 : result->fde = NULL;
64 :
65 500256 : tmp_refs = refs;
66 :
67 500256 : if ((refs != NULL) && (dgm_pid != tevent_cached_getpid())) {
68 : /*
69 : * Have to reinit after fork
70 : */
71 23060 : messaging_dgm_destroy();
72 23060 : refs = NULL;
73 : }
74 :
75 500256 : if (refs == NULL) {
76 1140 : int ret;
77 :
78 59069 : ret = messaging_dgm_init(ev, unique, socket_dir, lockfile_dir,
79 : msg_dgm_ref_recv, NULL);
80 59069 : DBG_DEBUG("messaging_dgm_init returned %s\n", strerror(ret));
81 59069 : 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 59056 : dgm_pid = tevent_cached_getpid();
89 : } else {
90 16966 : int ret;
91 441187 : ret = messaging_dgm_get_unique(tevent_cached_getpid(), unique);
92 441187 : DBG_DEBUG("messaging_dgm_get_unique returned %s\n",
93 : strerror(ret));
94 441187 : if (ret != 0) {
95 0 : TALLOC_FREE(result);
96 0 : *err = ret;
97 0 : return NULL;
98 : }
99 :
100 : }
101 :
102 500243 : result->fde = messaging_dgm_register_tevent_context(result, ev);
103 500243 : if (result->fde == NULL) {
104 0 : TALLOC_FREE(result);
105 0 : *err = ENOMEM;
106 0 : return NULL;
107 : }
108 :
109 500243 : DBG_DEBUG("unique = %"PRIu64"\n", *unique);
110 :
111 500243 : refs = tmp_refs;
112 :
113 500243 : result->recv_cb = recv_cb;
114 500243 : result->recv_cb_private_data = recv_cb_private_data;
115 500243 : DLIST_ADD(refs, result);
116 500243 : talloc_set_destructor(result, msg_dgm_ref_destructor);
117 :
118 500243 : return result;
119 : }
120 :
121 167787 : 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 44802 : 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 629579 : for (r = refs; r != NULL; r = next_ref) {
132 89043 : bool active;
133 :
134 461792 : next_ref = r->next;
135 :
136 461792 : active = messaging_dgm_fde_active(r->fde);
137 461792 : if (!active) {
138 : /*
139 : * r's tevent_context has died.
140 : */
141 38559 : continue;
142 : }
143 :
144 423233 : r->recv_cb(ev, msg, msg_len, fds, num_fds,
145 : r->recv_cb_private_data);
146 : }
147 167787 : }
148 :
149 574396 : static int msg_dgm_ref_destructor(struct msg_dgm_ref *r)
150 : {
151 574396 : if (refs == NULL) {
152 0 : abort();
153 : }
154 :
155 574396 : if (r == next_ref) {
156 66 : next_ref = r->next;
157 : }
158 :
159 574396 : DLIST_REMOVE(refs, r);
160 :
161 574396 : TALLOC_FREE(r->fde);
162 :
163 574396 : DBG_DEBUG("refs=%p\n", refs);
164 :
165 574396 : if (refs == NULL) {
166 75598 : messaging_dgm_destroy();
167 : }
168 574396 : return 0;
169 : }
|