2 * Copyright (c) 2013 Larisa Grigore. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 #include "sysvipc_hash.h"
40 #include "sysvipc_sockets.h"
44 #define MAX_CLIENTS 256
49 struct pollfd poll_fds[MAX_CLIENTS];
50 struct client *clients[MAX_CLIENTS];
53 struct hashtable *clientshash = NULL;
57 const char *pidfile = "/var/run/sysvpicd.pid";
63 * It is not necessary to check if the dir is empty and delete all files
64 * in it. Every time a client or the daemon exists all fds are closed
65 * and all resources are deleted (the daemon calls unlink after open a
66 * file for a sysv resource.
68 return (rmdir(DIRPATH));
75 return (mkdir(DIRPATH, 0600));
84 /* Create and init structures used for clients. */
85 clientshash = _hash_init(MAX_CLIENTS);
89 /* Create sysv resources directory. */
90 error = create_sysv_dir();
92 sysvd_print_err("You must first remove %s dir\n",
97 /* Open socket used to receive connections. */
98 unlink(LISTEN_SOCKET_FILE);
100 int fd_tmp = open(LISTEN_SOCKET_FILE, O_EXCL | O_CREAT, 0666);
102 sysvd_print_err("Could not open %s\n", LISTEN_SOCKET_FILE);
107 socket_fd = init_socket(LISTEN_SOCKET_FILE);
109 sysvd_print_err("Could not init %s socket\n", LISTEN_SOCKET_FILE);
113 poll_fds[SOCKET_FD_IDX].fd = socket_fd;
114 poll_fds[SOCKET_FD_IDX].events = POLLIN | POLLPRI;
115 poll_fds[SOCKET_FD_IDX].revents = 0;
127 daemon_add_client(void)
131 struct cmsgcred cred;
134 cl = malloc(sizeof(*cl));
136 sysvd_print_err("malloc");
142 /* Segments attached to a process. It is used
143 * when the process dies.
145 LIST_INIT(&cl->ids_attached);
147 /* Init communication channel between daemon and client. */
148 cl->sock = handle_new_connection(poll_fds[SOCKET_FD_IDX].fd);
150 poll_fds[nr_poll_fds].fd = cl->sock;
151 poll_fds[nr_poll_fds].events = POLLIN;
152 poll_fds[nr_poll_fds].revents = 0;
154 clients[nr_poll_fds] = cl;
157 if(nr_poll_fds == MAX_CLIENTS) {
158 sysvd_print_err("No room for another client; connection refused\n");
159 poll_fds[SOCKET_FD_IDX].events = 0;
162 /* Get the client pid. */
163 receive_msg_with_cred(cl->sock, &test, sizeof(test), &cred);
164 cl->pid = cred.cmcred_pid;
166 sysvd_print("total = %d...another one will be added\n", nr_poll_fds);
167 sysvd_print("pid = %d conected\n", cl->pid);
169 /* Verify if the client is already connected using the hashtable. */
170 if (_hash_lookup(clientshash, cl->pid)) {
172 sysvd_print_err("client already added");
177 /* Insert client in hashtable. */
178 _hash_insert(clientshash, cl->pid, cl);
184 daemon_remove_client(int i)
187 struct client *cl = clients[i];
188 sysvd_print("pid %d disconected\n", cl->pid);
189 sysvd_print("total = %d\n", nr_poll_fds);
191 /* Close communication channels. */
194 /* Put last client on i position. */
195 if (i != nr_poll_fds - 1) {
196 poll_fds[i] = poll_fds[nr_poll_fds - 1];
197 clients[i] = clients[nr_poll_fds - 1];
203 _hash_remove(clientshash, cl->pid);
208 if(nr_poll_fds == MAX_CLIENTS - 1) {
209 sysvd_print_err("Now another connexion can be handled\n");
210 poll_fds[SOCKET_FD_IDX].events = POLLIN | POLLPRI;
215 daemon_handle_msg(int i)
218 struct shmget_msg shmget_msg;
219 struct shmctl_msg shmctl_msg;
220 struct shmat_msg shmat_msg;
223 struct cmsgcred cred;
225 int fd_send, fd_recv;
226 fd_send = fd_recv = clients[i]->sock;
228 msg_type = receive_type_message(fd_recv);
229 sysvd_print("type = %d from %d\n", msg_type, clients[i]->pid);
232 case CONNEXION_CLOSED:
233 sysvd_print("connection closed\n");
239 receive_msg_with_cred(fd_recv, (char *)&shmget_msg,
240 sizeof(shmget_msg), &cred);
241 shmid = handle_shmget(clients[i]->pid,
244 /* Send the shmid. */
245 write(fd_send, (char *)&shmid,
247 sysvd_print("sent %d to client %d\n",
248 shmid, clients[i]->pid);
251 receive_msg_with_cred(fd_recv, (char *)&shmat_msg,
252 sizeof(shmat_msg), &cred);
253 error = handle_shmat(clients[i]->pid,
256 /* Send the error after few checks. */
257 write(fd_send, (char *)&error,
261 receive_msg_with_cred(fd_recv, (char *)&shmctl_msg,
262 sizeof(shmctl_msg), &cred);
263 error = handle_shmctl(&shmctl_msg, &cred);
265 /* Send the error after few checks. */
266 write(fd_send, (char *)&error,
268 if (error == 0 && shmctl_msg.cmd == IPC_STAT) {
270 write(fd_send, (char *)&shmctl_msg.buf,
271 sizeof(struct shmid_ds));
275 receive_msg_with_cred(fd_recv, (char *)&shmid,
276 sizeof(shmid), NULL);
277 shmid = handle_shmdt(clients[i]->pid, shmid);
282 sysvd_print("end\n");
296 ret = poll(poll_fds, nr_poll_fds, INFTIM);
298 sysvd_print_err("poll");
301 for (i=0; (i < nr_poll_fds) && ret; i++) {
302 if (poll_fds[i].revents == 0)
311 r = daemon_handle_msg(i);
313 daemon_remove_client(i);
332 main(int argc, char *argv[])
340 while ((c = getopt(argc,argv,"df:p")) !=-1) {
358 sysvd_print_err("SYSV_SEMS defined (used for sysv sems; a group of semaphores is protected)"
359 "by a rwlock and each semaphore is protected by a mutex\n");
361 sysvd_print_err("SYSV_SEMS not defined (used for sysv sems; a group of semaphores is protected)"
365 sysvd_print("daemon starting\n");
366 error = daemon_init();
370 if (sysvd_daemon == 1) {
376 /* It won't reach here. */
377 sysvd_print("daemon finished\n");