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.
41 #include "sysvipc_hash.h"
42 #include "sysvipc_sockets.h"
46 #define MAX_CLIENTS 256
51 struct pollfd poll_fds
[MAX_CLIENTS
];
52 struct client
*clients
[MAX_CLIENTS
];
55 struct hashtable
*clientshash
= NULL
;
64 * It is not necessary to check if the dir is empty and delete all files
65 * in it. Every time a client or the daemon exists all fds are closed
66 * and all resources are deleted (the daemon calls unlink after open a
67 * file for a sysv resource.
69 return (rmdir(DIRPATH
));
76 return (mkdir(DIRPATH
, 0600));
85 /* Create and init structures used for clients. */
86 clientshash
= _hash_init(MAX_CLIENTS
);
90 /* Create sysv resources directory. */
91 error
= create_sysv_dir();
93 sysvd_print_err("You must first remove %s dir\n",
98 /* Open socket used to receive connections. */
99 unlink(LISTEN_SOCKET_FILE
);
101 int fd_tmp
= open(LISTEN_SOCKET_FILE
, O_EXCL
| O_CREAT
, 0666);
103 sysvd_print_err("Could not open %s\n", LISTEN_SOCKET_FILE
);
108 socket_fd
= init_socket(LISTEN_SOCKET_FILE
);
110 sysvd_print_err("Could not init %s socket\n", LISTEN_SOCKET_FILE
);
114 poll_fds
[SOCKET_FD_IDX
].fd
= socket_fd
;
115 poll_fds
[SOCKET_FD_IDX
].events
= POLLIN
| POLLPRI
;
116 poll_fds
[SOCKET_FD_IDX
].revents
= 0;
128 daemon_add_client(void)
132 struct cmsgcred cred
;
135 cl
= malloc(sizeof(*cl
));
137 sysvd_print_err("malloc");
143 /* Segments attached to a process. It is used
144 * when the process dies.
146 LIST_INIT(&cl
->ids_attached
);
148 /* Init communication channel between daemon and client. */
149 cl
->sock
= handle_new_connection(poll_fds
[SOCKET_FD_IDX
].fd
);
151 poll_fds
[nr_poll_fds
].fd
= cl
->sock
;
152 poll_fds
[nr_poll_fds
].events
= POLLIN
;
153 poll_fds
[nr_poll_fds
].revents
= 0;
155 clients
[nr_poll_fds
] = cl
;
158 if(nr_poll_fds
== MAX_CLIENTS
) {
159 sysvd_print_err("No room for another client; connection refused\n");
160 poll_fds
[SOCKET_FD_IDX
].events
= 0;
163 /* Get the client pid. */
164 receive_msg_with_cred(cl
->sock
, &test
, sizeof(test
), &cred
);
165 cl
->pid
= cred
.cmcred_pid
;
167 sysvd_print("total = %d...another one will be added\n", nr_poll_fds
);
168 sysvd_print("pid = %d connected\n", cl
->pid
);
170 /* Verify if the client is already connected using the hashtable. */
171 if (_hash_lookup(clientshash
, cl
->pid
)) {
173 sysvd_print_err("client already added");
178 /* Insert client in hashtable. */
179 _hash_insert(clientshash
, cl
->pid
, cl
);
185 daemon_remove_client(int i
)
188 struct client
*cl
= clients
[i
];
189 sysvd_print("pid %d disconected\n", cl
->pid
);
190 sysvd_print("total = %d\n", nr_poll_fds
);
192 /* Close communication channels. */
195 /* Put last client on i position. */
196 if (i
!= nr_poll_fds
- 1) {
197 poll_fds
[i
] = poll_fds
[nr_poll_fds
- 1];
198 clients
[i
] = clients
[nr_poll_fds
- 1];
204 _hash_remove(clientshash
, cl
->pid
);
209 if(nr_poll_fds
== MAX_CLIENTS
- 1) {
210 sysvd_print_err("Now another connexion can be handled\n");
211 poll_fds
[SOCKET_FD_IDX
].events
= POLLIN
| POLLPRI
;
216 daemon_handle_msg(int i
)
219 struct shmget_msg shmget_msg
;
220 struct shmctl_msg shmctl_msg
;
221 struct shmat_msg shmat_msg
;
224 struct cmsgcred cred
;
226 int fd_send
, fd_recv
;
227 fd_send
= fd_recv
= clients
[i
]->sock
;
229 msg_type
= receive_type_message(fd_recv
);
230 sysvd_print("type = %d from %d\n", msg_type
, clients
[i
]->pid
);
233 case CONNEXION_CLOSED
:
234 sysvd_print("connection closed\n");
240 receive_msg_with_cred(fd_recv
, (char *)&shmget_msg
,
241 sizeof(shmget_msg
), &cred
);
242 shmid
= handle_shmget(clients
[i
]->pid
,
245 /* Send the shmid. */
246 write(fd_send
, (char *)&shmid
,
248 sysvd_print("sent %d to client %d\n",
249 shmid
, clients
[i
]->pid
);
252 receive_msg_with_cred(fd_recv
, (char *)&shmat_msg
,
253 sizeof(shmat_msg
), &cred
);
254 error
= handle_shmat(clients
[i
]->pid
,
257 /* Send the error after few checks. */
258 write(fd_send
, (char *)&error
,
262 receive_msg_with_cred(fd_recv
, (char *)&shmctl_msg
,
263 sizeof(shmctl_msg
), &cred
);
264 error
= handle_shmctl(&shmctl_msg
, &cred
);
266 /* Send the error after few checks. */
267 write(fd_send
, (char *)&error
,
269 if (error
== 0 && shmctl_msg
.cmd
== IPC_STAT
) {
271 write(fd_send
, (char *)&shmctl_msg
.buf
,
272 sizeof(struct shmid_ds
));
276 receive_msg_with_cred(fd_recv
, (char *)&shmid
,
277 sizeof(shmid
), NULL
);
278 shmid
= handle_shmdt(clients
[i
]->pid
, shmid
);
283 sysvd_print("end\n");
297 ret
= poll(poll_fds
, nr_poll_fds
, INFTIM
);
299 sysvd_print_err("poll");
302 for (i
=0; (i
< nr_poll_fds
) && ret
; i
++) {
303 if (poll_fds
[i
].revents
== 0)
312 r
= daemon_handle_msg(i
);
314 daemon_remove_client(i
);
329 fprintf(stderr
, "sysvipcd [-df] [-p pidfile]\n");
334 main(int argc
, char *argv
[])
338 char *pidfilename
= NULL
;
339 struct pidfh
*pfh
= NULL
;
344 while ((c
= getopt(argc
,argv
,"dfp:")) !=-1) {
354 pidfilename
= optarg
;
363 sysvd_print("SYSV_SEMS defined (used for sysv sems); "
364 "a group of semaphores is protected)\n"
365 "by a rwlock and each semaphore is protected by a mutex\n");
367 sysvd_print("SYSV_SEMS not defined (used for sysv sems); "
368 "a group of semaphores is protected)\n"
372 sysvd_print("daemon starting\n");
373 error
= daemon_init();
377 if (sysvd_daemon
== 1) {
378 pfh
= pidfile_open(pidfilename
, 600, NULL
);
385 /* It won't reach here. */
386 sysvd_print("daemon finished\n");