3 Copyright 1988, 1998 The Open Group
4 Copyright 2002 Sun Microsystems, Inc. All rights reserved.
5 Copyright 2002,2004 Oswald Buddenhagen <ossi@kde.org>
7 Permission to use, copy, modify, distribute, and sell this software and its
8 documentation for any purpose is hereby granted without fee, provided that
9 the above copyright notice appear in all copies and that both that
10 copyright notice and this permission notice appear in supporting
13 The above copyright notice and this permission notice shall be included
14 in all copies or substantial portions of the Software.
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 OTHER DEALINGS IN THE SOFTWARE.
24 Except as contained in this notice, the name of a copyright holder shall
25 not be used in advertising or otherwise to promote the sale, use or
26 other dealings in this Software without prior written authorization
27 from the copyright holder.
32 * xdm - display manager daemon
33 * Author: Keith Packard, MIT X Consortium
35 * socket.c - Support for BSD sockets
40 #if defined(XDMCP) && !defined(STREAMSCONN)
43 #include "dm_socket.h"
46 #include <arpa/inet.h>
48 static int currentRequestPort
;
51 createListeningSocket( struct sockaddr
*sock_addr
, int salen
)
54 #if defined(IPv6) && defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
57 const char *addrstring
= "unknown";
58 #if defined(IPv6) && defined(AF_INET6)
59 char addrbuf
[INET6_ADDRSTRLEN
];
65 if (debugLevel
& DEBUG_CORE
) {
66 #if defined(IPv6) && defined(AF_INET6)
68 if (sock_addr
->sa_family
== AF_INET6
)
69 ipaddr
= & ((struct sockaddr_in6
*)sock_addr
)->sin6_addr
;
71 ipaddr
= & ((struct sockaddr_in
*)sock_addr
)->sin_addr
;
73 inet_ntop( sock_addr
->sa_family
, ipaddr
, addrbuf
, sizeof(addrbuf
) );
76 addrstring
= inet_ntoa( ((struct sockaddr_in
*)sock_addr
)->sin_addr
);
79 debug( "creating socket to listen on port %d of address %s\n",
80 requestPort
, addrstring
);
83 if ((fd
= socket( sock_addr
->sa_family
, SOCK_DGRAM
, 0 )) == -1) {
84 logError( "XDMCP socket creation failed, errno %d\n", errno
);
87 #if defined(IPv6) && defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
88 setsockopt( fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
) );
91 if (bind( fd
, sock_addr
, salen
) == -1) {
92 logError( "error %d binding socket address %d\n", errno
, requestPort
);
97 registerCloseOnFork( fd
);
103 struct socklist
*next
;
104 struct socklist
*mcastgroups
;
105 struct sockaddr
*addr
;
109 int ref
; /* referenced bit - see updateListenSockets */
112 static struct socklist
*listensocks
;
115 destroyListeningSocket( struct socklist
*s
)
117 struct socklist
*g
, *n
;
120 closeNclearCloseOnFork( s
->fd
);
121 unregisterInput( s
->fd
);
128 for (g
= s
->mcastgroups
; g
; g
= n
) {
134 s
->mcastgroups
= NULL
;
137 static struct socklist
*
138 findInList( struct socklist
*list
, ARRAY8Ptr addr
)
142 for (s
= list
; s
; s
= s
->next
) {
143 if (s
->addrlen
== addr
->length
) {
146 switch (s
->addr
->sa_family
) {
149 &(((struct sockaddr_in
*)s
->addr
)->sin_addr
.s_addr
);
151 #if defined(IPv6) && defined(AF_INET6)
154 &(((struct sockaddr_in6
*)s
->addr
)->sin6_addr
.s6_addr
);
158 /* Unrecognized address family */
161 if (!memcmp( addrdata
, addr
->data
, addr
->length
))
168 static struct socklist
*
169 createSocklistEntry( ARRAY8Ptr addr
)
173 if (!(s
= Calloc( 1, sizeof(struct socklist
) )))
176 if (addr
->length
== 4) { /* IPv4 */
177 struct sockaddr_in
*sin4
;
178 sin4
= Calloc( 1, sizeof(struct sockaddr_in
) );
179 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
180 sin4
->sin_len
= sizeof(struct sockaddr_in
);
182 s
->addr
= (struct sockaddr
*)sin4
;
183 s
->salen
= sizeof(struct sockaddr_in
);
184 s
->addrlen
= sizeof(struct in_addr
);
185 sin4
->sin_family
= AF_INET
;
186 sin4
->sin_port
= htons( (short)requestPort
);
187 memcpy( &sin4
->sin_addr
, addr
->data
, addr
->length
);
189 #if defined(IPv6) && defined(AF_INET6)
190 else if (addr
->length
== 16) { /* IPv6 */
191 struct sockaddr_in6
*sin6
;
192 sin6
= Calloc( 1, sizeof(struct sockaddr_in6
) );
193 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
194 sin6
->sin6_len
= sizeof(struct sockaddr_in6
);
196 s
->addr
= (struct sockaddr
*)sin6
;
197 s
->salen
= sizeof(struct sockaddr_in6
);
198 s
->addrlen
= sizeof(struct in6_addr
);
199 sin6
->sin6_family
= AF_INET6
;
200 sin6
->sin6_port
= htons( (short)requestPort
);
201 memcpy( &sin6
->sin6_addr
, addr
->data
, addr
->length
);
205 /* Unknown address type */
213 updateListener( ARRAY8Ptr addr
, void **closure
)
222 #if defined(IPv6) && defined(AF_INET6)
223 struct in6_addr in6
= in6addr_any
;
224 tmpaddr
.length
= sizeof(in6
);
225 tmpaddr
.data
= (CARD8Ptr
) &in6
;
226 updateListener( &tmpaddr
, closure
);
230 in
.s_addr
= htonl( INADDR_ANY
);
231 tmpaddr
.length
= sizeof(in
);
232 tmpaddr
.data
= (CARD8Ptr
) &in
;
233 updateListener( &tmpaddr
, closure
);
237 if (currentRequestPort
== requestPort
&&
238 (s
= findInList( listensocks
, addr
)))
240 *closure
= (void *)s
;
245 if (!(s
= createSocklistEntry( addr
)))
248 if ((s
->fd
= createListeningSocket( s
->addr
, s
->salen
)) < 0) {
254 s
->next
= listensocks
;
256 *closure
= (void *)s
;
259 #define JOIN_MCAST_GROUP 0
260 #define LEAVE_MCAST_GROUP 1
263 changeMcastMembership( struct socklist
*s
, struct socklist
*g
, int op
)
267 switch (s
->addr
->sa_family
)
272 memcpy( &mreq
.imr_multiaddr
,
273 &((struct sockaddr_in
*)g
->addr
)->sin_addr
,
274 sizeof(struct in_addr
) );
275 memcpy( &mreq
.imr_interface
,
276 &((struct sockaddr_in
*)s
->addr
)->sin_addr
,
277 sizeof(struct in_addr
) );
278 if (op
== JOIN_MCAST_GROUP
)
279 sockopt
= IP_ADD_MEMBERSHIP
;
281 sockopt
= IP_DROP_MEMBERSHIP
;
282 if (setsockopt( s
->fd
, IPPROTO_IP
, sockopt
,
283 &mreq
, sizeof(mreq
) ) < 0) {
284 logError( "XDMCP socket multicast %s to %s failed, errno %d\n",
285 (op
== JOIN_MCAST_GROUP
) ? "join" : "drop",
286 inet_ntoa( ((struct sockaddr_in
*)g
->addr
)->sin_addr
),
288 } else if (debugLevel
& DEBUG_CORE
) {
289 debug( "XDMCP socket multicast %s to %s succeeded\n",
290 (op
== JOIN_MCAST_GROUP
) ? "join" : "drop",
291 inet_ntoa( ((struct sockaddr_in
*)g
->addr
)->sin_addr
) );
295 #if defined(IPv6) && defined(AF_INET6)
296 # ifndef IPV6_JOIN_GROUP
297 # define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
299 # ifndef IPV6_LEAVE_GROUP
300 # define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
304 struct ipv6_mreq mreq6
;
305 memcpy( &mreq6
.ipv6mr_multiaddr
,
306 &((struct sockaddr_in6
*)g
->addr
)->sin6_addr
,
307 sizeof(struct in6_addr
) );
308 mreq6
.ipv6mr_interface
= 0; /* TODO: fix this */
309 if (op
== JOIN_MCAST_GROUP
)
310 sockopt
= IPV6_JOIN_GROUP
;
312 sockopt
= IPV6_LEAVE_GROUP
;
313 if (setsockopt( s
->fd
, IPPROTO_IPV6
, sockopt
,
314 &mreq6
, sizeof(mreq6
) ) < 0)
317 char addrbuf
[INET6_ADDRSTRLEN
];
319 inet_ntop( s
->addr
->sa_family
,
320 &((struct sockaddr_in6
*)g
->addr
)->sin6_addr
,
321 addrbuf
, sizeof(addrbuf
) );
323 logError( "XDMCP socket multicast %s to %s failed, errno %d\n",
324 (op
== JOIN_MCAST_GROUP
) ? "join" : "drop", addrbuf
,
326 } else if (debugLevel
& DEBUG_CORE
) {
327 char addrbuf
[INET6_ADDRSTRLEN
];
329 inet_ntop( s
->addr
->sa_family
,
330 &((struct sockaddr_in6
*)g
->addr
)->sin6_addr
,
331 addrbuf
, sizeof(addrbuf
) );
333 debug( "XDMCP socket multicast %s to %s succeeded\n",
334 (op
== JOIN_MCAST_GROUP
) ? "join" : "drop", addrbuf
);
343 updateMcastGroup( ARRAY8Ptr addr
, void **closure
)
345 struct socklist
*s
= (struct socklist
*)*closure
;
351 /* Already in the group, mark & continue */
352 if ((g
= findInList( s
->mcastgroups
, addr
))) {
357 /* Need to join the group */
358 if (!(g
= createSocklistEntry( addr
)))
361 changeMcastMembership( s
, g
, JOIN_MCAST_GROUP
);
365 /* Open or close listening sockets to match the current settings read in
366 from the access database. */
368 updateListenSockets( void )
370 struct socklist
*s
, *g
, **ls
, **lg
;
373 /* Clear Ref bits - any not marked by UpdateCallback will be closed */
374 for (s
= listensocks
; s
; s
= s
->next
) {
376 for (g
= s
->mcastgroups
; g
; g
= g
->next
)
379 forEachListenAddr( updateListener
, updateMcastGroup
, &tmpPtr
);
380 currentRequestPort
= requestPort
;
381 for (ls
= &listensocks
; (s
= *ls
); )
383 destroyListeningSocket( s
);
388 for (lg
= &s
->mcastgroups
; (g
= *lg
); )
390 changeMcastMembership( s
, g
, LEAVE_MCAST_GROUP
);
399 anyListenSockets( void )
401 return listensocks
!= NULL
;
405 processListenSockets( fd_set
*reads
)
410 for (s
= listensocks
; s
; s
= s
->next
)
411 if (FD_ISSET( s
->fd
, reads
)) {
412 processRequestSocket( s
->fd
);
418 #endif /* !STREAMSCONN && XDMCP */