]> arthur.barton.de Git - netatalk.git/blob - etc/cnid_dbd/usockfd.c
IPv6 support for afpd and cnid_metad
[netatalk.git] / etc / cnid_dbd / usockfd.c
1 /*
2  * $Id: usockfd.c,v 1.6 2009-11-05 14:38:07 franklahm Exp $
3  *
4  * Copyright (C) Joerg Lenneis 2003
5  * All Rights Reserved.  See COPYING.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H */
11
12
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/un.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #include <netdb.h>
24
25 #ifdef HAVE_SYS_TYPES_H
26 #include <sys/types.h>
27 #endif /* HAVE_SYS_TYPES_H */
28 #ifdef HAVE_SYS_TIME_H
29 #include <sys/time.h>
30 #endif /* HAVE_SYS_TIME_H */
31
32
33 #include <atalk/logger.h>
34 #include "usockfd.h"
35
36 #include <sys/select.h>
37
38 int usockfd_create(char *usock_fn, mode_t mode, int backlog)
39 {
40     int sockfd;
41     struct sockaddr_un addr;
42
43
44     if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
45         LOG(log_error, logtype_cnid, "error in socket call: %s",
46             strerror(errno));
47         return -1;
48     }
49      
50     if (unlink(usock_fn) < 0 && errno != ENOENT) {
51         LOG(log_error, logtype_cnid, "error unlinking unix socket file %s: %s",
52             usock_fn, strerror(errno));
53         return -1;
54     }
55     memset((char *) &addr, 0, sizeof(struct sockaddr_un));
56     addr.sun_family = AF_UNIX;
57     strncpy(addr.sun_path, usock_fn, sizeof(addr.sun_path) - 1);
58     if (bind(sockfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)) < 0) {
59         LOG(log_error, logtype_cnid, "error binding to socket for %s: %s",
60             usock_fn, strerror(errno));
61         return -1;
62     }
63
64     if (listen(sockfd, backlog) < 0) {
65         LOG(log_error, logtype_cnid, "error in listen for %s: %s",
66             usock_fn, strerror(errno));
67         return -1;
68     }
69
70     if (chmod(usock_fn, mode) < 0) {
71         LOG(log_error, logtype_cnid, "error changing permissions for %s: %s",
72             usock_fn, strerror(errno));
73         close(sockfd);
74         return -1;
75     }
76
77     return sockfd;
78 }
79
80 /* ---------------
81  * create a tcp socket
82  */
83 int tsockfd_create(char *host, char *port, int backlog)
84 {
85     int sockfd, flag, ret;
86     struct addrinfo hints, *servinfo, *p;
87
88     /* Prepare hint for getaddrinfo */
89     memset(&hints, 0, sizeof hints);
90     hints.ai_family = AF_UNSPEC;
91     hints.ai_socktype = SOCK_STREAM;
92
93     if ((ret = getaddrinfo(host, port, &hints, &servinfo)) != 0) {
94         LOG(log_error, logtype_default, "tsockfd_create: getaddrinfo: %s\n", gai_strerror(ret));
95         return 0;
96     }
97
98     /* create a socket */
99     /* loop through all the results and bind to the first we can */
100     for (p = servinfo; p != NULL; p = p->ai_next) {
101         if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
102             LOG(log_info, logtype_default, "tsockfd_create: socket: %s", strerror(errno));
103             continue;
104         }
105
106         /*
107          * Set some socket options:
108          * SO_REUSEADDR deals w/ quick close/opens
109          * TCP_NODELAY diables Nagle
110          */
111 #ifdef SO_REUSEADDR
112         flag = 1;
113         setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
114 #endif
115
116 #ifdef USE_TCP_NODELAY
117 #ifndef SOL_TCP
118 #define SOL_TCP IPPROTO_TCP
119 #endif
120         flag = 1;
121         setsockopt(sockfd, SOL_TCP, TCP_NODELAY, &flag, sizeof(flag));
122 #endif /* USE_TCP_NODELAY */
123             
124         if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
125             close(sockfd);
126             LOG(log_info, logtype_default, "tsockfd_create: bind: %s\n", strerror(errno));
127             continue;
128         }
129
130         if (listen(sockfd, backlog) < 0) {
131             close(sockfd);
132             LOG(log_info, logtype_default, "tsockfd_create: listen: %s\n", strerror(errno));
133             continue;
134         }
135
136         /* We got a socket */
137         break;
138     }
139
140     if (p == NULL)  {
141         LOG(log_error, logtype_default, "tsockfd_create: no suitable network config %s:%s", host, port);
142         freeaddrinfo(servinfo);
143         return -1;
144     }
145
146     freeaddrinfo(servinfo);
147     return sockfd;
148 }
149
150 /* --------------------- */
151 int usockfd_check(int sockfd, const sigset_t *sigset)
152 {
153     int fd;
154     socklen_t size;
155     fd_set readfds;
156     int ret;
157     struct timeval tv;
158      
159     FD_ZERO(&readfds);
160     FD_SET(sockfd, &readfds);
161
162     if ((ret = pselect(sockfd + 1, &readfds, NULL, NULL, NULL, sigset)) < 0) {
163         if (errno == EINTR)
164             return 0;
165         LOG(log_error, logtype_cnid, "error in select: %s",
166             strerror(errno));
167         return -1;
168     }
169
170     if (ret) {
171         size = 0;
172         if ((fd = accept(sockfd, NULL, &size)) < 0) {
173             if (errno == EINTR)
174                 return 0;
175             LOG(log_error, logtype_cnid, "error in accept: %s", 
176                 strerror(errno));
177             return -1;
178         }
179         tv.tv_sec = 5;
180         tv.tv_usec = 0;
181         if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
182             LOG(log_error, logtype_cnid, "set SO_RCVTIMEO: %s", strerror(errno));
183             close(fd);
184             return -1;
185         }
186         return fd;
187     } else
188         return 0;
189 }