2 * Copyright (C) Joerg Lenneis 2003
3 * Copyright (C) Frank Lahm 2010
5 * All Rights Reserved. See COPYING.
12 #if !defined(__FreeBSD__) && !defined(__NetBSD__)
14 # define _XOPEN_SOURCE 600
16 #ifndef __EXTENSIONS__
17 # define __EXTENSIONS__
29 #include <sys/param.h>
30 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <sys/select.h>
38 #include <atalk/logger.h>
39 #include <atalk/util.h>
40 #include <atalk/cnid_dbd_private.h>
46 /* Length of the space taken up by a padded control message of length len */
48 #define CMSG_SPACE(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + __CMSG_ALIGN(len))
53 time_t tm; /* When respawned last */
57 static int control_fd;
59 static struct connection *fd_table;
60 static int fd_table_size;
61 static int fds_in_use = 0;
64 static void invalidate_fd(int fd)
70 for (i = 0; i != fds_in_use; i++)
71 if (fd_table[i].fd == fd)
74 assert(i < fds_in_use);
77 fd_table[i] = fd_table[fds_in_use];
78 fd_table[fds_in_use].fd = -1;
85 * Check for client requests. We keep up to fd_table_size open descriptors in
86 * fd_table. If the table is full and we get a new descriptor via
87 * control_fd, we close a random decriptor in the table to make space. The
88 * affected client will automatically reconnect. For an EOF (descriptor is
89 * closed by the client, so a read here returns 0) comm_rcv will take care of
90 * things and clean up fd_table. The same happens for any read/write errors.
93 static int check_fd(time_t timeout, const sigset_t *sigmask, time_t *now)
100 int maxfd = control_fd;
104 FD_SET(control_fd, &readfds);
106 for (i = 0; i != fds_in_use; i++) {
107 FD_SET(fd_table[i].fd, &readfds);
108 if (maxfd < fd_table[i].fd)
109 maxfd = fd_table[i].fd;
114 if ((ret = pselect(maxfd + 1, &readfds, NULL, NULL, &tv, sigmask)) < 0) {
117 LOG(log_error, logtype_cnid, "error in select: %s",strerror(errno));
129 if (FD_ISSET(control_fd, &readfds)) {
132 fd = recv_fd(control_fd, 0);
136 if (fds_in_use < fd_table_size) {
137 fd_table[fds_in_use].fd = fd;
138 fd_table[fds_in_use].tm = t;
143 for (i = 0; i != fds_in_use; i++) {
144 if (older <= fd_table[i].tm) {
145 older = fd_table[i].tm;
149 close(fd_table[l].fd);
156 for (i = 0; i != fds_in_use; i++) {
157 if (FD_ISSET(fd_table[i].fd, &readfds)) {
159 return fd_table[i].fd;
162 /* We should never get here */
166 int comm_init(struct db_param *dbp, int ctrlfd, int clntfd)
171 fd_table_size = dbp->fd_table_size;
173 if ((fd_table = malloc(fd_table_size * sizeof(struct connection))) == NULL) {
174 LOG(log_error, logtype_cnid, "Out of memory");
177 for (i = 0; i != fd_table_size; i++)
183 /* this one dump core in recvmsg, great */
184 if ( setsockopt(control_fd, SOL_SOCKET, SO_PASSCRED, &b, sizeof (b)) < 0) {
185 LOG(log_error, logtype_cnid, "setsockopt SO_PASSCRED %s", strerror(errno));
189 /* push the first client fd */
190 fd_table[fds_in_use].fd = clntfd;
205 int comm_rcv(struct cnid_dbd_rqst *rqst, time_t timeout, const sigset_t *sigmask, time_t *now)
210 if ((cur_fd = check_fd(timeout, sigmask, now)) < 0)
216 LOG(log_maxdebug, logtype_cnid, "comm_rcv: got data on fd %u", cur_fd);
218 if (setnonblock(cur_fd, 1) != 0) {
219 LOG(log_error, logtype_cnid, "comm_rcv: setnonblock: %s", strerror(errno));
223 nametmp = (char *)rqst->name;
224 if ((b = readt(cur_fd, rqst, sizeof(struct cnid_dbd_rqst), 1, CNID_DBD_TIMEOUT))
225 != sizeof(struct cnid_dbd_rqst)) {
227 LOG(log_error, logtype_cnid, "error reading message header: %s", strerror(errno));
228 invalidate_fd(cur_fd);
229 rqst->name = nametmp;
232 rqst->name = nametmp;
233 if (rqst->namelen && readt(cur_fd, (char *)rqst->name, rqst->namelen, 1, CNID_DBD_TIMEOUT)
235 LOG(log_error, logtype_cnid, "error reading message name: %s", strerror(errno));
236 invalidate_fd(cur_fd);
239 /* We set this to make life easier for logging. None of the other stuff
240 needs zero terminated strings. */
241 ((char *)(rqst->name))[rqst->namelen] = '\0';
243 LOG(log_maxdebug, logtype_cnid, "comm_rcv: got %u bytes", b + rqst->namelen);
250 int comm_snd(struct cnid_dbd_rply *rply)
257 if (!rply->namelen) {
258 if (write(cur_fd, rply, sizeof(struct cnid_dbd_rply)) != sizeof(struct cnid_dbd_rply)) {
259 LOG(log_error, logtype_cnid, "error writing message header: %s", strerror(errno));
260 invalidate_fd(cur_fd);
267 iov[0].iov_base = rply;
268 iov[0].iov_len = sizeof(struct cnid_dbd_rply);
269 iov[1].iov_base = rply->name;
270 iov[1].iov_len = rply->namelen;
271 towrite = sizeof(struct cnid_dbd_rply) +rply->namelen;
273 if (writev(cur_fd, iov, 2) != towrite) {
274 LOG(log_error, logtype_cnid, "error writing message : %s", strerror(errno));
275 invalidate_fd(cur_fd);
279 if (write(cur_fd, rply, sizeof(struct cnid_dbd_rply)) != sizeof(struct cnid_dbd_rply)) {
280 LOG(log_error, logtype_cnid, "error writing message header: %s", strerror(errno));
281 invalidate_fd(cur_fd);
284 if (write(cur_fd, rply->name, rply->namelen) != rply->namelen) {
285 LOG(log_error, logtype_cnid, "error writing message name: %s", strerror(errno));
286 invalidate_fd(cur_fd);