1 /* the Music Player Daemon (MPD)
2 * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
3 * This project's homepage is: http://www.musicpd.org
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include "interface.h"
27 #include <sys/socket.h>
29 #include <sys/param.h>
30 #include <netinet/in.h>
37 #define MAXHOSTNAME 1024
41 #define DEFAULT_PORT 6600
43 #define BINDERROR() do { \
44 FATAL("unable to bind port %u: %s\n" \
45 "maybe MPD is still running?\n", \
46 port, strerror(errno)); \
49 static int *listenSockets
;
50 static int numberOfListenSockets
;
53 static int establishListen(unsigned int port
,
54 struct sockaddr
*addrp
, socklen_t addrlen
)
58 int allowReuse
= ALLOW_REUSE
;
60 switch (addrp
->sa_family
) {
73 FATAL("unknown address family: %i\n", addrp
->sa_family
);
76 if ((sock
= socket(pf
, SOCK_STREAM
, 0)) < 0)
77 FATAL("socket < 0\n");
79 if (fcntl(sock
, F_SETFL
, fcntl(sock
, F_GETFL
) | O_NONBLOCK
) < 0) {
80 FATAL("problems setting nonblocking on listen socket: %s\n",
84 if (setsockopt(sock
, SOL_SOCKET
, SO_REUSEADDR
, (char *)&allowReuse
,
85 sizeof(allowReuse
)) < 0) {
86 FATAL("problems setsockopt'ing: %s\n", strerror(errno
));
89 if (bind(sock
, addrp
, addrlen
) < 0) {
94 if (listen(sock
, 5) < 0)
95 FATAL("problems listen'ing: %s\n", strerror(errno
));
97 numberOfListenSockets
++;
99 xrealloc(listenSockets
, sizeof(int) * numberOfListenSockets
);
101 listenSockets
[numberOfListenSockets
- 1] = sock
;
106 static void parseListenConfigParam(unsigned int port
, ConfigParam
* param
)
108 struct sockaddr
*addrp
= NULL
;
109 socklen_t addrlen
= 0;
110 struct sockaddr_in sin
;
112 struct sockaddr_in6 sin6
;
113 int useIpv6
= ipv6Supported();
115 memset(&sin6
, 0, sizeof(struct sockaddr_in6
));
116 sin6
.sin6_port
= htons(port
);
117 sin6
.sin6_family
= AF_INET6
;
119 memset(&sin
, 0, sizeof(struct sockaddr_in
));
120 sin
.sin_port
= htons(port
);
121 sin
.sin_family
= AF_INET
;
123 if (!param
|| 0 == strcmp(param
->value
, "any")) {
124 DEBUG("binding to any address\n");
127 sin6
.sin6_addr
= in6addr_any
;
128 addrp
= (struct sockaddr
*)&sin6
;
129 addrlen
= sizeof(struct sockaddr_in6
);
130 if (establishListen(port
, addrp
, addrlen
) < 0)
134 sin
.sin_addr
.s_addr
= INADDR_ANY
;
135 addrp
= (struct sockaddr
*)&sin
;
136 addrlen
= sizeof(struct sockaddr_in
);
138 if ((establishListen(port
, addrp
, addrlen
) < 0) && !useIpv6
) {
140 if (establishListen(port
, addrp
, addrlen
) < 0) {
146 DEBUG("binding to address for %s\n", param
->value
);
147 if (!(he
= gethostbyname(param
->value
))) {
148 FATAL("can't lookup host \"%s\" at line %i\n",
149 param
->value
, param
->line
);
151 switch (he
->h_addrtype
) {
155 FATAL("no IPv6 support, but a IPv6 address "
156 "found for \"%s\" at line %i\n",
157 param
->value
, param
->line
);
159 memcpy((char *)&sin6
.sin6_addr
.s6_addr
,
160 (char *)he
->h_addr
, he
->h_length
);
161 addrp
= (struct sockaddr
*)&sin6
;
162 addrlen
= sizeof(struct sockaddr_in6
);
166 memcpy((char *)&sin
.sin_addr
.s_addr
,
167 (char *)he
->h_addr
, he
->h_length
);
168 addrp
= (struct sockaddr
*)&sin
;
169 addrlen
= sizeof(struct sockaddr_in
);
172 FATAL("address type for \"%s\" is not IPv4 or IPv6 "
173 "at line %i\n", param
->value
, param
->line
);
176 if (establishListen(port
, addrp
, addrlen
) < 0)
181 void listenOnPort(void)
183 int port
= DEFAULT_PORT
;
184 ConfigParam
*param
= getNextConfigParam(CONF_BIND_TO_ADDRESS
, NULL
);
185 ConfigParam
*portParam
= getConfigParam(CONF_PORT
);
189 port
= strtol(portParam
->value
, &test
, 10);
190 if (port
<= 0 || *test
!= '\0') {
191 FATAL("%s \"%s\" specified at line %i is not a "
192 "positive integer", CONF_PORT
,
193 portParam
->value
, portParam
->line
);
200 parseListenConfigParam(port
, param
);
201 } while ((param
= getNextConfigParam(CONF_BIND_TO_ADDRESS
, param
)));
204 void addListenSocketsToFdSet(fd_set
* fds
, int *fdmax
)
208 for (i
= 0; i
< numberOfListenSockets
; i
++) {
209 FD_SET(listenSockets
[i
], fds
);
210 if (listenSockets
[i
] > *fdmax
)
211 *fdmax
= listenSockets
[i
];
215 void closeAllListenSockets(void)
219 DEBUG("closeAllListenSockets called\n");
221 for (i
= 0; i
< numberOfListenSockets
; i
++) {
222 DEBUG("closing listen socket %i\n", i
);
223 while (close(listenSockets
[i
]) < 0 && errno
== EINTR
) ;
225 freeAllListenSockets();
228 void freeAllListenSockets(void)
230 numberOfListenSockets
= 0;
232 listenSockets
= NULL
;
235 void getConnections(fd_set
* fds
)
239 struct sockaddr sockAddr
;
240 socklen_t socklen
= sizeof(sockAddr
);
242 for (i
= 0; i
< numberOfListenSockets
; i
++) {
243 if (FD_ISSET(listenSockets
[i
], fds
)) {
244 if ((fd
= accept(listenSockets
[i
], &sockAddr
, &socklen
))
246 openAInterface(fd
, &sockAddr
);
248 && (errno
!= EAGAIN
&& errno
!= EINTR
)) {
249 ERROR("Problems accept()'ing\n");