2 * $Id: comm.c,v 1.2 2005-04-28 20:49:47 bfernhomberg Exp $
4 * Copyright (C) Joerg Lenneis 2003
5 * All Rights Reserved. See COPYING.
21 #include <sys/param.h>
23 #include <sys/socket.h>
25 #ifdef HAVE_SYS_TYPES_H
26 #include <sys/types.h>
29 #ifdef HAVE_SYS_TIME_H
37 #ifdef HAVE_SYS_SOCKET_H
38 #include <sys/socket.h>
45 #include <atalk/logger.h>
46 #include <atalk/cnid_dbd_private.h>
52 /* Length of the space taken up by a padded control message of length len */
54 #define CMSG_SPACE(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + __CMSG_ALIGN(len))
59 time_t tm; /* When respawned last */
63 static int control_fd;
65 static struct connection *fd_table;
66 static int fd_table_size;
67 static int fds_in_use = 0;
70 static void invalidate_fd(int fd)
76 for (i = 0; i != fds_in_use; i++)
77 if (fd_table[i].fd == fd)
80 assert(i < fds_in_use);
83 fd_table[i] = fd_table[fds_in_use];
84 fd_table[fds_in_use].fd = -1;
89 static int recv_cred(int fd)
94 struct cmsghdr *cmsgp = NULL;
95 char buf[CMSG_SPACE(sizeof(int))];
98 memset(&msgh,0,sizeof(msgh));
99 memset(buf,0,sizeof(buf));
101 msgh.msg_name = NULL;
102 msgh.msg_namelen = 0;
107 iov[0].iov_base = dbuf;
108 iov[0].iov_len = sizeof(dbuf);
110 msgh.msg_control = buf;
111 msgh.msg_controllen = sizeof(buf);
114 ret = recvmsg(fd ,&msgh,0);
115 } while ( ret == -1 && errno == EINTR );
121 for ( cmsgp = CMSG_FIRSTHDR(&msgh); cmsgp != NULL; cmsgp = CMSG_NXTHDR(&msgh,cmsgp) ) {
122 if ( cmsgp->cmsg_level == SOL_SOCKET && cmsgp->cmsg_type == SCM_RIGHTS ) {
123 return *(int *) CMSG_DATA(cmsgp);
127 if ( ret == sizeof (int) )
128 errno = *(int *)dbuf; /* Rcvd errno */
130 errno = ENOENT; /* Default errno */
136 * Check for client requests. We keep up to fd_table_size open descriptors in
137 * fd_table. If the table is full and we get a new descriptor via
138 * control_fd, we close a random decriptor in the table to make space. The
139 * affected client will automatically reconnect. For an EOF (descriptor is
140 * closed by the client, so a read here returns 0) comm_rcv will take care of
141 * things and clean up fd_table. The same happens for any read/write errors.
144 static int check_fd()
151 int maxfd = control_fd;
155 FD_SET(control_fd, &readfds);
157 for (i = 0; i != fds_in_use; i++) {
158 FD_SET(fd_table[i].fd, &readfds);
159 if (maxfd < fd_table[i].fd)
160 maxfd = fd_table[i].fd;
165 if ((ret = select(maxfd + 1, &readfds, NULL, NULL, &tv)) < 0) {
168 LOG(log_error, logtype_cnid, "error in select: %s",strerror(errno));
177 if (FD_ISSET(control_fd, &readfds)) {
180 fd = recv_cred(control_fd);
184 if (fds_in_use < fd_table_size) {
185 fd_table[fds_in_use].fd = fd;
186 fd_table[fds_in_use].tm = t;
191 for (i = 0; i != fds_in_use; i++) {
192 if (older <= fd_table[i].tm) {
193 older = fd_table[i].tm;
197 close(fd_table[l].fd);
204 for (i = 0; i != fds_in_use; i++) {
205 if (FD_ISSET(fd_table[i].fd, &readfds)) {
207 return fd_table[i].fd;
210 /* We should never get here */
214 int comm_init(struct db_param *dbp, int ctrlfd, int clntfd)
219 fd_table_size = dbp->fd_table_size;
221 if ((fd_table = malloc(fd_table_size * sizeof(struct connection))) == NULL) {
222 LOG(log_error, logtype_cnid, "Out of memory");
225 for (i = 0; i != fd_table_size; i++)
231 /* this one dump core in recvmsg, great */
232 if ( setsockopt(control_fd, SOL_SOCKET, SO_PASSCRED, &b, sizeof (b)) < 0) {
233 LOG(log_error, logtype_cnid, "setsockopt SO_PASSCRED %s", strerror(errno));
237 /* push the first client fd */
238 fd_table[fds_in_use].fd = clntfd;
253 int comm_rcv(struct cnid_dbd_rqst *rqst)
258 if ((cur_fd = check_fd()) < 0)
263 nametmp = rqst->name;
264 if ((b = read(cur_fd, rqst, sizeof(struct cnid_dbd_rqst))) != sizeof(struct cnid_dbd_rqst)) {
266 LOG(log_error, logtype_cnid, "error reading message header: %s", strerror(errno));
267 invalidate_fd(cur_fd);
268 rqst->name = nametmp;
271 rqst->name = nametmp;
272 if (rqst->namelen && read(cur_fd, rqst->name, rqst->namelen) != rqst->namelen) {
273 LOG(log_error, logtype_cnid, "error reading message name: %s", strerror(errno));
274 invalidate_fd(cur_fd);
277 /* We set this to make life easier for logging. None of the other stuff
278 needs zero terminated strings. */
279 rqst->name[rqst->namelen] = '\0';
286 int comm_snd(struct cnid_dbd_rply *rply)
293 if (!rply->namelen) {
294 if (write(cur_fd, rply, sizeof(struct cnid_dbd_rply)) != sizeof(struct cnid_dbd_rply)) {
295 LOG(log_error, logtype_cnid, "error writing message header: %s", strerror(errno));
296 invalidate_fd(cur_fd);
303 iov[0].iov_base = rply;
304 iov[0].iov_len = sizeof(struct cnid_dbd_rply);
305 iov[1].iov_base = rply->name;
306 iov[1].iov_len = rply->namelen;
307 towrite = sizeof(struct cnid_dbd_rply) +rply->namelen;
309 if (writev(cur_fd, iov, 2) != towrite) {
310 LOG(log_error, logtype_cnid, "error writing message : %s", strerror(errno));
311 invalidate_fd(cur_fd);
315 if (write(cur_fd, rply, sizeof(struct cnid_dbd_rply)) != sizeof(struct cnid_dbd_rply)) {
316 LOG(log_error, logtype_cnid, "error writing message header: %s", strerror(errno));
317 invalidate_fd(cur_fd);
320 if (write(cur_fd, rply->name, rply->namelen) != rply->namelen) {
321 LOG(log_error, logtype_cnid, "error writing message name: %s", strerror(errno));
322 invalidate_fd(cur_fd);