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