From 3b55506bca05496bf066afc396cd40a38856c4ae Mon Sep 17 00:00:00 2001 From: Erich Hoover Date: Tue, 11 Oct 2011 08:20:08 -0600 Subject: server: Add mechanism for storing an interface ID with a socket. --- include/wine/server_protocol.h | 36 ++++++++++- server/Makefile.in | 6 +- server/protocol.def | 15 ++++ server/request.h | 11 +++ server/sock.c | 142 +++++++++++++++++++++++++++++++++++++++- server/trace.c | 22 ++++++ 6 files changed, 227 insertions(+), 5 deletions(-) diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index e0b0ac8..755ad12 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -1428,6 +1428,34 @@ struct get_socket_event_reply +struct set_socket_iface_request +{ + struct request_header __header; + obj_handle_t handle; + int iface; + char __pad_20[4]; +}; +struct set_socket_iface_reply +{ + struct reply_header __header; +}; + + + +struct get_socket_iface_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_socket_iface_reply +{ + struct reply_header __header; + int iface; + char __pad_12[4]; +}; + + + struct enable_socket_event_request { struct request_header __header; @@ -4929,6 +4957,8 @@ enum request REQ_accept_into_socket, REQ_set_socket_event, REQ_get_socket_event, + REQ_set_socket_iface, + REQ_get_socket_iface, REQ_enable_socket_event, REQ_set_socket_deferred, REQ_alloc_console, @@ -5183,6 +5213,8 @@ union generic_request struct accept_into_socket_request accept_into_socket_request; struct set_socket_event_request set_socket_event_request; struct get_socket_event_request get_socket_event_request; + struct set_socket_iface_request set_socket_iface_request; + struct get_socket_iface_request get_socket_iface_request; struct enable_socket_event_request enable_socket_event_request; struct set_socket_deferred_request set_socket_deferred_request; struct alloc_console_request alloc_console_request; @@ -5435,6 +5467,8 @@ union generic_reply struct accept_into_socket_reply accept_into_socket_reply; struct set_socket_event_reply set_socket_event_reply; struct get_socket_event_reply get_socket_event_reply; + struct set_socket_iface_reply set_socket_iface_reply; + struct get_socket_iface_reply get_socket_iface_reply; struct enable_socket_event_reply enable_socket_event_reply; struct set_socket_deferred_reply set_socket_deferred_reply; struct alloc_console_reply alloc_console_reply; @@ -5637,6 +5671,6 @@ union generic_reply struct set_suspend_context_reply set_suspend_context_reply; }; -#define SERVER_PROTOCOL_VERSION 427 +#define SERVER_PROTOCOL_VERSION 428 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/Makefile.in b/server/Makefile.in index a2f1a52..6f89c27 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -1,5 +1,5 @@ DEFS = -D__WINESRC__ -EXTRALIBS = @LIBPOLL@ +EXTRALIBS = @LIBPTHREAD@ C_SRCS = \ async.c \ @@ -62,10 +62,10 @@ all: $(PROGRAMS) @MAKE_RULES@ wineserver: $(OBJS) - $(CC) -o $@ $(OBJS) $(LIBWINE) $(LIBPORT) $(LDFLAGS) $(LIBS) $(LDRPATH_LOCAL) + $(CC) -o $@ $(OBJS) $(LIBWINE) $(LIBPORT) $(LDFLAGS) $(LIBS) $(EXTRALIBS) $(LDRPATH_LOCAL) wineserver-installed: $(OBJS) - $(CC) -o $@ $(OBJS) $(LIBWINE) $(LIBPORT) $(LDFLAGS) $(LIBS) $(LDRPATH_INSTALL) + $(CC) -o $@ $(OBJS) $(LIBWINE) $(LIBPORT) $(LDFLAGS) $(LIBS) $(EXTRALIBS) $(LDRPATH_INSTALL) install install-lib:: wineserver-installed $(DESTDIR)$(bindir) install-man-pages $(INSTALL_PROGRAM) wineserver-installed $(DESTDIR)$(bindir)/wineserver diff --git a/server/protocol.def b/server/protocol.def index bec2e3c..a071ad2 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1154,6 +1154,21 @@ enum server_fd_type @END +/* Set socket interface ID */ +@REQ(set_socket_iface) + obj_handle_t handle; /* handle to the socket */ + int iface; /* interface ID */ +@END + + +/* Get socket interface ID */ +@REQ(get_socket_iface) + obj_handle_t handle; /* handle to the socket */ +@REPLY + int iface; /* interface ID */ +@END + + /* Reenable pending socket events */ @REQ(enable_socket_event) obj_handle_t handle; /* handle to the socket */ diff --git a/server/request.h b/server/request.h index b875e30..f697c4f 100644 --- a/server/request.h +++ b/server/request.h @@ -158,6 +158,8 @@ DECL_HANDLER(accept_socket); DECL_HANDLER(accept_into_socket); DECL_HANDLER(set_socket_event); DECL_HANDLER(get_socket_event); +DECL_HANDLER(set_socket_iface); +DECL_HANDLER(get_socket_iface); DECL_HANDLER(enable_socket_event); DECL_HANDLER(set_socket_deferred); DECL_HANDLER(alloc_console); @@ -411,6 +413,8 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_accept_into_socket, (req_handler)req_set_socket_event, (req_handler)req_get_socket_event, + (req_handler)req_set_socket_iface, + (req_handler)req_get_socket_iface, (req_handler)req_enable_socket_event, (req_handler)req_set_socket_deferred, (req_handler)req_alloc_console, @@ -952,6 +956,13 @@ C_ASSERT( FIELD_OFFSET(struct get_socket_event_reply, mask) == 8 ); C_ASSERT( FIELD_OFFSET(struct get_socket_event_reply, pmask) == 12 ); C_ASSERT( FIELD_OFFSET(struct get_socket_event_reply, state) == 16 ); C_ASSERT( sizeof(struct get_socket_event_reply) == 24 ); +C_ASSERT( FIELD_OFFSET(struct set_socket_iface_request, handle) == 12 ); +C_ASSERT( FIELD_OFFSET(struct set_socket_iface_request, iface) == 16 ); +C_ASSERT( sizeof(struct set_socket_iface_request) == 24 ); +C_ASSERT( FIELD_OFFSET(struct get_socket_iface_request, handle) == 12 ); +C_ASSERT( sizeof(struct get_socket_iface_request) == 16 ); +C_ASSERT( FIELD_OFFSET(struct get_socket_iface_reply, iface) == 8 ); +C_ASSERT( sizeof(struct get_socket_iface_reply) == 16 ); C_ASSERT( FIELD_OFFSET(struct enable_socket_event_request, handle) == 12 ); C_ASSERT( FIELD_OFFSET(struct enable_socket_event_request, mask) == 16 ); C_ASSERT( FIELD_OFFSET(struct enable_socket_event_request, sstate) == 20 ); diff --git a/server/sock.c b/server/sock.c index 9f62da2..a7522eb 100644 --- a/server/sock.c +++ b/server/sock.c @@ -38,14 +38,19 @@ #ifdef HAVE_SYS_SOCKET_H # include #endif +#ifdef HAVE_NETINET_IN_H +# include +#endif #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_SYS_FILIO_H # include #endif +#include #include #include +#include #include "ntstatus.h" #define WIN32_NO_STATUS @@ -89,6 +94,12 @@ /* Constants for WSAIoctl() */ #define WSA_FLAG_OVERLAPPED 0x01 +#if !defined(HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS) +# if defined(IP_PKTINFO) +# define IP_IFACEFILTER IP_PKTINFO +# endif +#endif + struct sock { struct object obj; /* object header */ @@ -109,6 +120,8 @@ struct sock struct sock *deferred; /* socket that waits for a deferred accept */ struct async_queue *read_q; /* queue for asynchronous reads */ struct async_queue *write_q; /* queue for asynchronous writes */ + int iface_index; /* interface ID for interface-specific sockets */ + sem_t *iface_lock; /* semaphore lock for interface-specific sockets */ }; static void sock_dump( struct object *obj, int verbose ); @@ -372,6 +385,71 @@ end: sock_wake_up( sock ); } +/* Test for UDP interface filtered packets that have triggered a server-side + * poll(). If the packet does not match for this socket's interface + * then throw it away. + */ +static int accept_read_poll( struct fd *fd ) +{ +#ifdef IP_IFACEFILTER + struct sock *sock = get_fd_user( fd ); + unsigned int check_iface, optlen; + int handle = get_unix_fd ( fd ); + struct msghdr hdr; + char pktbuf[512]; + int ret = TRUE; + + memset(&hdr, 0, sizeof(struct msghdr)); + hdr.msg_control = pktbuf; + hdr.msg_controllen = sizeof(pktbuf); + hdr.msg_flags = 0; + + check_iface = 0; + optlen = sizeof(check_iface); + getsockopt(handle, IPPROTO_IP, IP_IFACEFILTER, (void *) &check_iface, &optlen); + check_iface &= (sock->iface_index != -1); + if (check_iface) + { + sem_wait(sock->iface_lock); + /* Peek at the packet to check its interface */ + if ( recvmsg(handle, &hdr, MSG_PEEK|MSG_DONTWAIT) != -1 ) + { + int iface_index = sock->iface_index, packet_index = -1; + struct cmsghdr *cmsg; + + for (cmsg = CMSG_FIRSTHDR(&hdr); cmsg != NULL; + cmsg = CMSG_NXTHDR(&hdr, cmsg)) + { +#if defined(IP_PKTINFO) + if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) + { + struct in_pktinfo *pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg); + + if (pktinfo) + packet_index = pktinfo->ipi_ifindex; + } +#else +#error "IP_IFACEFILTER is defined incorrectly." +#endif + } + if (packet_index != -1 && packet_index != iface_index) + { + if ( recvmsg(handle, &hdr, MSG_DONTWAIT) != -1 ) + ret = FALSE; + else + fprintf(stderr, "Failed to throw away packet with interface mismatch! %m\n"); + } + } + else + fprintf(stderr, "Failed to peek at message header! %m\n"); + sem_post(sock->iface_lock); + } + return ret; +#else + return TRUE; +#endif /* IP_IFACEFILTER */ +} + static void sock_poll_event( struct fd *fd, int event ) { struct sock *sock = get_fd_user( fd ); @@ -438,6 +516,12 @@ static void sock_poll_event( struct fd *fd, int event ) } } } + else if (event & POLLIN) /* POLLIN for non-stream socket */ + { + /* Check to see if the packet is not destined for the given interface */ + if (!accept_read_poll(fd)) + event &= ~POLLIN; + } if ( (hangup_seen || event & (POLLHUP|POLLERR)) && (sock->state & (FD_READ|FD_WRITE)) ) { @@ -597,8 +681,23 @@ static void sock_destroy( struct object *obj ) if (sock->event) release_object( sock->event ); if (sock->fd) { + int sockfd = get_unix_fd(sock->fd); + + if (sock->iface_lock) + { + char lockname[100]; + struct stat fdinfo; + + if (fstat(sockfd, &fdinfo) == 0) + { + snprintf( lockname, sizeof(lockname), "/wine-ifacelock-%d.%d-%ld", + major(fdinfo.st_dev), minor(fdinfo.st_dev), (long)fdinfo.st_ino ); + sem_close( sock->iface_lock ); + sem_unlink( lockname ); + } + } /* shut the socket down to force pending poll() calls in the client to return */ - shutdown( get_unix_fd(sock->fd), SHUT_RDWR ); + shutdown( sockfd, SHUT_RDWR ); release_object( sock->fd ); } } @@ -620,6 +719,8 @@ static void init_sock(struct sock *sock) sock->deferred = NULL; sock->read_q = NULL; sock->write_q = NULL; + sock->iface_index = -1; + sock->iface_lock = NULL; memset( sock->errors, 0, sizeof(sock->errors) ); } @@ -963,6 +1064,45 @@ DECL_HANDLER(accept_into_socket) release_object( sock ); } +/* set socket interface */ +DECL_HANDLER(set_socket_iface) +{ + struct sock *sock; + char lockname[100]; + struct stat fdinfo; + int sockfd; + + if (!(sock = (struct sock *)get_handle_obj( current->process, req->handle, + FILE_WRITE_ATTRIBUTES, &sock_ops))) return; + sock->iface_index = req->iface; + sockfd = get_unix_fd(sock->fd); + if (fstat(sockfd, &fdinfo) == 0) + { + snprintf( lockname, sizeof(lockname), "/wine-ifacelock-%d.%d-%ld", + major(fdinfo.st_dev), minor(fdinfo.st_dev), (long)fdinfo.st_ino ); + sock->iface_lock = sem_open( lockname, O_CREAT, S_IRUSR | S_IWUSR, 1 ); + } + else + fprintf(stderr, "failed to create socket semaphore\n"); + release_object( &sock->obj ); +} + +/* get socket interface */ +DECL_HANDLER(get_socket_iface) +{ + struct sock *sock; + + sock = (struct sock *)get_handle_obj( current->process, req->handle, FILE_READ_ATTRIBUTES, &sock_ops ); + if (!sock) + { + reply->iface = 0; + set_error( WSAENOTSOCK ); + return; + } + reply->iface = sock->iface_index; + release_object( &sock->obj ); +} + /* set socket event parameters */ DECL_HANDLER(set_socket_event) { diff --git a/server/trace.c b/server/trace.c index 188eee4..289e78d 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1590,6 +1590,22 @@ static void dump_get_socket_event_reply( const struct get_socket_event_reply *re dump_varargs_ints( ", errors=", cur_size ); } +static void dump_set_socket_iface_request( const struct set_socket_iface_request *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); + fprintf( stderr, ", iface=%d", req->iface ); +} + +static void dump_get_socket_iface_request( const struct get_socket_iface_request *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); +} + +static void dump_get_socket_iface_reply( const struct get_socket_iface_reply *req ) +{ + fprintf( stderr, " iface=%d", req->iface ); +} + static void dump_enable_socket_event_request( const struct enable_socket_event_request *req ) { fprintf( stderr, " handle=%04x", req->handle ); @@ -3953,6 +3969,8 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_accept_into_socket_request, (dump_func)dump_set_socket_event_request, (dump_func)dump_get_socket_event_request, + (dump_func)dump_set_socket_iface_request, + (dump_func)dump_get_socket_iface_request, (dump_func)dump_enable_socket_event_request, (dump_func)dump_set_socket_deferred_request, (dump_func)dump_alloc_console_request, @@ -4204,6 +4222,8 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { NULL, (dump_func)dump_get_socket_event_reply, NULL, + (dump_func)dump_get_socket_iface_reply, + NULL, NULL, (dump_func)dump_alloc_console_reply, NULL, @@ -4453,6 +4473,8 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "accept_into_socket", "set_socket_event", "get_socket_event", + "set_socket_iface", + "get_socket_iface", "enable_socket_event", "set_socket_deferred", "alloc_console", -- 1.7.1