]> arthur.barton.de Git - netatalk.git/blob - etc/cnid_dbd/comm.c
Try to fix compile errors reported with redhat 7
[netatalk.git] / etc / cnid_dbd / comm.c
1 /*
2  * $Id: comm.c,v 1.1.4.2 2003-09-20 02:47:21 bfernhomberg Exp $
3  *
4  * Copyright (C) Joerg Lenneis 2003
5  * All Rights Reserved.  See COPYRIGHT.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <errno.h>
16 #ifdef HAVE_UNISTD_H
17 #include <unistd.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
25 #include <sys/time.h>
26 #endif /* HAVE_SYS_TIME_H */
27 #ifdef HAVE_SYS_UIO_H
28 #include <sys/uio.h>
29 #endif /* HAVE_SYS_UIO_H */
30
31
32 #include <assert.h>
33 #include <time.h>
34
35 #include <atalk/logger.h>
36 #include <atalk/cnid_dbd_private.h>
37
38 #include "db_param.h"
39 #include "usockfd.h"
40 #include "comm.h"
41
42 struct connection {
43     time_t tm;                    /* When respawned last */
44     int    fd;
45 };
46
47 static int   usock_fd;
48 static int   cur_fd;
49 static struct connection *fd_table;
50 static int  fd_table_size;
51 static int  fds_in_use = 0;
52
53
54 static void invalidate_fd(int fd)
55 {
56     int i;
57
58     if (fd == usock_fd)
59         return;
60     for (i = 0; i != fds_in_use; i++) 
61         if (fd_table[i].fd == fd)
62             break;
63     
64     assert(i < fds_in_use);
65
66     fds_in_use--;
67     fd_table[i] = fd_table[fds_in_use];
68     fd_table[fds_in_use].fd = -1;
69     close(fd);    
70     return;
71 }
72
73 static int recv_cred(int fd)
74 {
75 int ret;
76 struct msghdr msgh; 
77 struct iovec iov[1];
78 struct cmsghdr *cmsgp = NULL;
79 char buf[CMSG_SPACE(sizeof(int))];
80 char dbuf[80];
81
82     memset(&msgh,0,sizeof(msgh));
83     memset(buf,0,sizeof(buf));
84
85     msgh.msg_name = NULL;
86     msgh.msg_namelen = 0;
87
88     msgh.msg_iov = iov;
89     msgh.msg_iovlen = 1;
90
91     iov[0].iov_base = dbuf;
92     iov[0].iov_len = sizeof(dbuf);
93
94     msgh.msg_control = buf;
95     msgh.msg_controllen = sizeof(buf);
96
97     do  {
98           ret = recvmsg(fd ,&msgh,0);
99     } while ( ret == -1 && errno == EINTR );
100
101     if ( ret == -1 ) {
102         return -1;
103     }
104       
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);
108         }
109     }
110
111     if ( ret == sizeof (int) )
112        errno = *(int *)dbuf; /* Rcvd errno */
113     else
114        errno = ENOENT;    /* Default errno */
115    
116     return -1;
117 }
118
119 /*
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.
126  */
127
128 static int check_fd()
129 {
130     int fd;
131     fd_set readfds;
132     struct timeval tv;
133     int ret;
134     int i;
135     int maxfd = usock_fd;
136     time_t t;
137     
138     FD_ZERO(&readfds);
139     FD_SET(usock_fd, &readfds);
140     
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;
145     }
146
147     tv.tv_usec = 0;
148     tv.tv_sec  = 1;
149     if ((ret = select(maxfd + 1, &readfds, NULL, NULL, &tv)) < 0) {
150         if (errno == EINTR)
151             return 0;
152         LOG(log_error, logtype_cnid, "error in select: %s",strerror(errno));
153         return -1;
154     }
155
156     if (!ret)
157         return 0;
158
159     time(&t);
160
161     if (FD_ISSET(usock_fd, &readfds)) {
162         int    l = 0;
163         
164         fd = recv_cred(usock_fd);
165         if (fd < 0) {
166             return -1;
167         }
168         if (fds_in_use < fd_table_size) {
169             fd_table[fds_in_use].fd = fd;
170             fd_table[fds_in_use].tm = t;
171             fds_in_use++;
172         } else {
173             time_t older = t;
174              
175             for (i = 0; i != fds_in_use; i++) {
176                 if (older <= fd_table[i].tm) {
177                     older = fd_table[i].tm;
178                     l = i;
179                 }
180             }
181             close(fd_table[l].fd);
182             fd_table[l].fd = fd;
183             fd_table[l].tm = t;
184         }
185         return 0;
186     }
187
188     for (i = 0; i != fds_in_use; i++) {
189         if (FD_ISSET(fd_table[i].fd, &readfds)) {
190             fd_table[i].tm = t;
191             return fd_table[i].fd;
192         }
193     }       
194     /* We should never get here */
195     return 0;
196 }
197
198 int comm_init(struct db_param *dbp)
199 {
200     int i;
201
202     fds_in_use = 0;
203     fd_table_size = dbp->fd_table_size;
204     
205     if ((fd_table = malloc(fd_table_size * sizeof(struct connection))) == NULL) {
206         LOG(log_error, logtype_cnid, "Out of memory");
207         return -1;
208     }
209     for (i = 0; i != fd_table_size; i++)
210         fd_table[i].fd = -1;
211     /* from dup2 */
212     usock_fd = 0;
213 #if 0
214     int b = 1;
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));
218         return -1;
219     }
220 #endif
221     /* push the first from dup2 */
222     fd_table[fds_in_use].fd = 1;
223     fds_in_use++;
224     
225     return 0;
226 }
227
228 /* ------------ 
229    nbe of clients
230 */
231 int comm_nbe(void)
232 {
233     return fds_in_use;
234 }
235
236 /* ------------ */
237 int comm_rcv(struct cnid_dbd_rqst *rqst)
238 {
239     char *nametmp;
240     int b;
241
242     if ((cur_fd = check_fd()) < 0)
243         return -1;
244
245     if (!cur_fd)
246         return 0;
247     nametmp = rqst->name;
248     if ((b = read(cur_fd, rqst, sizeof(struct cnid_dbd_rqst))) != sizeof(struct cnid_dbd_rqst)) {
249         if (b)
250             LOG(log_error, logtype_cnid, "error reading message header: %s", strerror(errno));
251         invalidate_fd(cur_fd);
252         rqst->name = nametmp;
253         return 0;
254     }
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);
259         return 0;
260     }
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';
264         
265     return 1;
266 }
267
268
269 int comm_snd(struct cnid_dbd_rply *rply)
270 {
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);
274         return 0;
275     }
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);
279         return 0;
280     }
281     return 1;
282 }
283
284