1 /* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
2
3 #include "lib.h"
4 #include "array.h"
5 #include "ipc-connection.h"
6 #include "ipc-group.h"
7
8 struct ipc_group_cmd {
9 ipc_cmd_callback_t *callback;
10 void *context;
11
12 int refcount;
13 char *first_error;
14 };
15
16 static ARRAY(struct ipc_group *) ipc_groups;
17
ipc_group_alloc(int listen_fd)18 struct ipc_group *ipc_group_alloc(int listen_fd)
19 {
20 struct ipc_group *group;
21
22 i_assert(ipc_group_lookup_listen_fd(listen_fd) == NULL);
23
24 group = i_new(struct ipc_group, 1);
25 group->listen_fd = listen_fd;
26 array_push_back(&ipc_groups, &group);
27 return group;
28 }
29
ipc_group_free(struct ipc_group ** _group)30 void ipc_group_free(struct ipc_group **_group)
31 {
32 struct ipc_group *const *groups, *group = *_group;
33 unsigned int i, count;
34
35 i_assert(group->connections == NULL);
36
37 *_group = NULL;
38 groups = array_get(&ipc_groups, &count);
39 for (i = 0; i < count; i++) {
40 if (groups[i] == group) {
41 array_delete(&ipc_groups, i, 1);
42 break;
43 }
44 }
45 i_free(group->name);
46 i_free(group);
47 }
48
ipc_group_lookup_listen_fd(int listen_fd)49 struct ipc_group *ipc_group_lookup_listen_fd(int listen_fd)
50 {
51 struct ipc_group *group;
52
53 array_foreach_elem(&ipc_groups, group) {
54 if (group->listen_fd == listen_fd)
55 return group;
56 }
57 return NULL;
58 }
59
ipc_group_lookup_name(const char * name)60 struct ipc_group *ipc_group_lookup_name(const char *name)
61 {
62 struct ipc_group *group;
63
64 array_foreach_elem(&ipc_groups, group) {
65 if (group->name != NULL &&
66 strcmp(group->name, name) == 0)
67 return group;
68 }
69 return NULL;
70 }
71
ipc_group_update_name(struct ipc_group * group,const char * name)72 int ipc_group_update_name(struct ipc_group *group, const char *name)
73 {
74 if (group->name == NULL)
75 group->name = i_strdup(name);
76 else if (strcmp(group->name, name) != 0)
77 return -1;
78 return 0;
79 }
80
ipc_group_cmd_callback(enum ipc_cmd_status status,const char * line,void * context)81 static void ipc_group_cmd_callback(enum ipc_cmd_status status,
82 const char *line, void *context)
83 {
84 struct ipc_group_cmd *group_cmd = context;
85
86 i_assert(group_cmd->refcount > 0);
87
88 switch (status) {
89 case IPC_CMD_STATUS_REPLY:
90 group_cmd->callback(IPC_CMD_STATUS_REPLY, line,
91 group_cmd->context);
92 break;
93 case IPC_CMD_STATUS_ERROR:
94 if (group_cmd->first_error == NULL)
95 group_cmd->first_error = i_strdup(line);
96 /* fall through */
97 case IPC_CMD_STATUS_OK:
98 if (--group_cmd->refcount > 0)
99 break;
100
101 if (group_cmd->first_error == NULL) {
102 group_cmd->callback(IPC_CMD_STATUS_OK, line,
103 group_cmd->context);
104 } else {
105 group_cmd->callback(IPC_CMD_STATUS_ERROR,
106 group_cmd->first_error,
107 group_cmd->context);
108 i_free(group_cmd->first_error);
109 }
110 i_free(group_cmd);
111 break;
112 }
113
114 }
115
ipc_group_cmd(struct ipc_group * group,const char * cmd,ipc_cmd_callback_t * callback,void * context)116 bool ipc_group_cmd(struct ipc_group *group, const char *cmd,
117 ipc_cmd_callback_t *callback, void *context)
118 {
119 struct ipc_connection *conn, *next;
120 struct ipc_group_cmd *group_cmd;
121
122 if (group->connections == NULL) {
123 callback(IPC_CMD_STATUS_OK, NULL, context);
124 return FALSE;
125 }
126
127 group_cmd = i_new(struct ipc_group_cmd, 1);
128 group_cmd->callback = callback;
129 group_cmd->context = context;
130
131 for (conn = group->connections; conn != NULL; conn = next) {
132 next = conn->next;
133
134 group_cmd->refcount++;
135 ipc_connection_cmd(conn, cmd,
136 ipc_group_cmd_callback, group_cmd);
137 }
138 return TRUE;
139 }
140
ipc_groups_init(void)141 void ipc_groups_init(void)
142 {
143 i_array_init(&ipc_groups, 16);
144 }
145
ipc_groups_disconnect_all(void)146 void ipc_groups_disconnect_all(void)
147 {
148 struct ipc_group *const *groupp, *group;
149
150 while (array_count(&ipc_groups) > 0) {
151 groupp = array_front(&ipc_groups);
152 group = *groupp;
153
154 while ((*groupp)->connections != NULL) {
155 struct ipc_connection *conn = (*groupp)->connections;
156 ipc_connection_destroy(&conn, FALSE, "Shutting down");
157 }
158 ipc_group_free(&group);
159 }
160 }
161
ipc_groups_deinit(void)162 void ipc_groups_deinit(void)
163 {
164 ipc_groups_disconnect_all();
165 array_free(&ipc_groups);
166 }
167