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