2 * $Id: comm.c,v 1.1.4.2 2003-09-20 02:47:21 bfernhomberg Exp $
4 * Copyright (C) Joerg Lenneis 2003
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
18 #endif /* HAVE_UNISTD_H */
19 #include <sys/param.h>
20 #include <sys/socket.h>
21 #ifdef HAVE_SYS_TYPES_H
22 #include <sys/types.h>
23 #endif /* HAVE_SYS_TYPES_H */
24 #ifdef HAVE_SYS_TIME_H
26 #endif /* HAVE_SYS_TIME_H */
29 #endif /* HAVE_SYS_UIO_H */
35 #include <atalk/logger.h>
36 #include <atalk/cnid_dbd_private.h>
43 time_t tm; /* When respawned last */
49 static struct connection *fd_table;
50 static int fd_table_size;
51 static int fds_in_use = 0;
54 static void invalidate_fd(int fd)
60 for (i = 0; i != fds_in_use; i++)
61 if (fd_table[i].fd == fd)
64 assert(i < fds_in_use);
67 fd_table[i] = fd_table[fds_in_use];
68 fd_table[fds_in_use].fd = -1;
73 static int recv_cred(int fd)
78 struct cmsghdr *cmsgp = NULL;
79 char buf[CMSG_SPACE(sizeof(int))];
82 memset(&msgh,0,sizeof(msgh));
83 memset(buf,0,sizeof(buf));
91 iov[0].iov_base = dbuf;
92 iov[0].iov_len = sizeof(dbuf);
94 msgh.msg_control = buf;
95 msgh.msg_controllen = sizeof(buf);
98 ret = recvmsg(fd ,&msgh,0);
99 } while ( ret == -1 && errno == EINTR );
105 for ( cmsgp = CMSG_FIRSTHDR(&msgh); cmsgp != NULL; cmsgp = CMSG_NXTHDR(&msgh,cmsgp) ) {
106 if ( cmsgp->cmsg_level == SOL_SOCKET && cmsgp->cmsg_type == SCM_RIGHTS ) {
107 return *(int *) CMSG_DATA(cmsgp);
111 if ( ret == sizeof (int) )
112 errno = *(int *)dbuf; /* Rcvd errno */
114 errno = ENOENT; /* Default errno */
120 * Check for client requests. We keep up to fd_table_size open descriptors in
121 * fd_table. If the table is full and we get a request for a new descriptor via
122 * usock_fd, we close a random decriptor in the table to make space. The
123 * affected client will automatically reconnect. For an EOF (descriptor is
124 * closed by the client, so a read here returns 0) comm_rcv will take care of
125 * things and clean up fd_table. The same happens for any read/write errors.
128 static int check_fd()
135 int maxfd = usock_fd;
139 FD_SET(usock_fd, &readfds);
141 for (i = 0; i != fds_in_use; i++) {
142 FD_SET(fd_table[i].fd, &readfds);
143 if (maxfd < fd_table[i].fd)
144 maxfd = fd_table[i].fd;
149 if ((ret = select(maxfd + 1, &readfds, NULL, NULL, &tv)) < 0) {
152 LOG(log_error, logtype_cnid, "error in select: %s",strerror(errno));
161 if (FD_ISSET(usock_fd, &readfds)) {
164 fd = recv_cred(usock_fd);
168 if (fds_in_use < fd_table_size) {
169 fd_table[fds_in_use].fd = fd;
170 fd_table[fds_in_use].tm = t;
175 for (i = 0; i != fds_in_use; i++) {
176 if (older <= fd_table[i].tm) {
177 older = fd_table[i].tm;
181 close(fd_table[l].fd);
188 for (i = 0; i != fds_in_use; i++) {
189 if (FD_ISSET(fd_table[i].fd, &readfds)) {
191 return fd_table[i].fd;
194 /* We should never get here */
198 int comm_init(struct db_param *dbp)
203 fd_table_size = dbp->fd_table_size;
205 if ((fd_table = malloc(fd_table_size * sizeof(struct connection))) == NULL) {
206 LOG(log_error, logtype_cnid, "Out of memory");
209 for (i = 0; i != fd_table_size; i++)
215 /* this one dump core in recvmsg, great */
216 if ( setsockopt(usock_fd, SOL_SOCKET, SO_PASSCRED, &b, sizeof (b)) < 0) {
217 LOG(log_error, logtype_cnid, "setsockopt SO_PASSCRED %s", strerror(errno));
221 /* push the first from dup2 */
222 fd_table[fds_in_use].fd = 1;
237 int comm_rcv(struct cnid_dbd_rqst *rqst)
242 if ((cur_fd = check_fd()) < 0)
247 nametmp = rqst->name;
248 if ((b = read(cur_fd, rqst, sizeof(struct cnid_dbd_rqst))) != sizeof(struct cnid_dbd_rqst)) {
250 LOG(log_error, logtype_cnid, "error reading message header: %s", strerror(errno));
251 invalidate_fd(cur_fd);
252 rqst->name = nametmp;
255 rqst->name = nametmp;
256 if (rqst->namelen && read(cur_fd, rqst->name, rqst->namelen) != rqst->namelen) {
257 LOG(log_error, logtype_cnid, "error reading message name: %s", strerror(errno));
258 invalidate_fd(cur_fd);
261 /* We set this to make life easier for logging. None of the other stuff
262 needs zero terminated strings. */
263 rqst->name[rqst->namelen] = '\0';
269 int comm_snd(struct cnid_dbd_rply *rply)
271 if (write(cur_fd, rply, sizeof(struct cnid_dbd_rply)) != sizeof(struct cnid_dbd_rply)) {
272 LOG(log_error, logtype_cnid, "error writing message header: %s", strerror(errno));
273 invalidate_fd(cur_fd);
276 if (rply->namelen && write(cur_fd, rply->name, rply->namelen) != rply->namelen) {
277 LOG(log_error, logtype_cnid, "error writing message name: %s", strerror(errno));
278 invalidate_fd(cur_fd);