Compare commits

...

27 Commits

Author SHA1 Message Date
Erich E. Hoover
9fcd7e7113 Fix date in changelog. 2014-04-04 17:28:07 -06:00
Erich E. Hoover
903a8e54d4 Update changelog for release 1.7.16. 2014-04-04 17:25:15 -06:00
Sebastian Lackner
3de6b17d8a Update dynamic unwind patches and add test. 2014-04-05 01:24:13 +02:00
Sebastian Lackner
74bd451363 11-Dynamic_Unwind: Explicitly declare unwind table callback as CDECL. 2014-04-04 19:56:20 +02:00
Sebastian Lackner
22a1e1ff59 Add proper implementation for dynamic unwind functions, removed stub implementation. 2014-04-04 19:47:11 +02:00
Sebastian Lackner
c781d177e1 Removed first set of DXVA2 patches (accepted upstream). 2014-04-04 19:44:11 +02:00
Erich E. Hoover
f13c0f3cd8 Further split out the SIO_ADDRESS_LIST_CHANGE patches. 2014-04-04 11:34:29 -06:00
Michael MĂĽller
9ebbbcfc9f Add stub for RtlInstallFunctionTableCallback 2014-04-04 07:15:16 +02:00
Sebastian Lackner
d886426f50 Updated DXVA2 stub and header patches. 2014-04-04 07:06:47 +02:00
Erich E. Hoover
d30bfe1a41 Add patch to silence repeated resource_check_usage FIXME. 2014-04-03 21:39:17 -06:00
Erich E. Hoover
30825c59a9 SetWaitableTimerEx FIXME patch accepted upstream. 2014-04-03 21:37:49 -06:00
Sebastian Lackner
7d03df647f Fix lcms dependency (wine requires lcms2 instead of lcms1), add build dependency to libsane-dev. 2014-04-03 19:50:14 +02:00
Sebastian Lackner
a046f03792 Add patch to silence SetWaitableTimerEx fixme message (heavily used by Adobe Flash). 2014-04-03 05:31:09 +02:00
Erich E. Hoover
b744f3d37b Use 'Multi-Arch: foreign' flag for wine-compholio package. 2014-04-02 20:28:54 -06:00
Michael MĂĽller
c52df465c1 Merge branch 'wine64' 2014-04-02 23:59:54 +02:00
Sebastian Lackner
09bfdcb009 Update DXVA2 patches, remove last work-in-progress part. 2014-03-29 06:53:54 +01:00
Erich E. Hoover
2f449562d1 First SIO_ADDRESS_LIST_CHANGE patch accepted upstream. 2014-03-28 15:58:51 -06:00
Sebastian Lackner
3c6c730333 Remove previous dxva2 patch (accepted upstream), added additional dxva2 implementation patches. 2014-03-26 22:28:10 +01:00
Michael MĂĽller
809ee539f3 Fix version number in Replaces/Breaks. 2014-03-25 17:08:07 +01:00
Michael MĂĽller
339892ffe6 Try to fix upgrading from old versions. 2014-03-25 15:58:12 +01:00
Michael MĂĽller
2e7f83fbf8 Add changelog entry. 2014-03-25 06:09:09 +01:00
Michael MĂĽller
9043eadbcb Fix search path for dh_shlibdeps. 2014-03-25 04:50:06 +01:00
Michael MĂĽller
5386c7843d Update dependencies and make them 64 bit ready. 2014-03-25 02:04:35 +01:00
Michael MĂĽller
0675620019 Pass CONFFLAGS to ./configure. 2014-03-25 01:02:13 +01:00
Michael MĂĽller
552b6acf97 Initial work to make wine-compholio 64 bit ready. 2014-03-25 00:52:10 +01:00
Sebastian Lackner
86c9842e64 Fix bug in generate-patchlist.sh. 2014-03-24 18:48:08 +01:00
Michael MĂĽller
d0e9447fb6 dxva2: Added stub dll 2014-03-24 00:17:29 +01:00
24 changed files with 1420 additions and 737 deletions

14
debian/changelog vendored
View File

@@ -1,3 +1,17 @@
wine-compholio (1.7.16) unstable; urgency=low
* Add stub for RtlInstallFunctionTableCallback.
* Further split out the SIO_ADDRESS_LIST_CHANGE patches.
* Add proper implementation for dynamic unwind functions, removed stub implementation.
* Fix lcms dependency (Wine requires lcms2 instead of lcms1), add build dependency to libsane-dev.
-- Erich E. Hoover <erich.e.hoover@gmail.com> Fri, 04 Apr 2014 17:27:52 -0600
wine-compholio (1.7.15-1) unstable; urgency=low
* Build 64 bit version of Wine.
* First SIO_ADDRESS_LIST_CHANGE patch accepted upstream.
* Added stub dll for DirectX Video Acceleration (dxva2.dll).
* Update DXVA2 patches (additional implementation details, parts accepted upstream).
-- Erich E. Hoover <erich.e.hoover@gmail.com> Tue, 25 Mar 2014 06:08:01 +0100
wine-compholio (1.7.15) unstable; urgency=low
* Fixed build dependencies for Debian Sid.
* Fixed free() of a const variable (Bug #1).

172
debian/control vendored
View File

@@ -5,7 +5,6 @@ Maintainer: Erich E. Hoover <ehoover@mines.edu>
XSBC-Original-Maintainer: Scott Ritchie <scottritchie@ubuntu.com>
Build-Depends: autotools-dev,
autoconf,
bind9-host,
bison,
bsdmainutils,
coreutils,
@@ -17,19 +16,10 @@ Build-Depends: autotools-dev,
fontforge,
gawk,
gcc-4.5 | gcc-4.7 | ubuntu-desktop (<< 1.207),
gcc-4.5-multilib [amd64] | ubuntu-desktop (<< 1.207) [amd64],
gcc-multilib [amd64],
gettext,
gzip,
ia32-libs [amd64],
ia32-libs-dev [amd64] | ubuntu-desktop (<< 1.267) [amd64],
ia32-libs-multiarch [amd64] | ubuntu-desktop (<< 1.267) [amd64],
lib32asound2-dev [amd64],
lib32ncurses5-dev [amd64],
lib32z1-dev [amd64],
libacl1-dev,
libasound2-dev [i386 lpia],
libc6-dev-i386 [amd64],
libasound2-dev,
libcapi20-dev,
libcups2-dev,
libdbus-1-dev,
@@ -42,23 +32,23 @@ Build-Depends: autotools-dev,
libglu1-mesa-dev | libglu-dev,
libgnutls-dev,
libgphoto2-dev | libgphoto2-6-dev | libgphoto2-2-dev (>= 2.4.6),
libgphoto2port-dev | ubuntu-desktop (>= 1.245) | debian-edu-config,
libgsm1-dev,
libgstreamer-plugins-base0.10-dev,
libgstreamer0.10-dev,
libice-dev,
libjpeg-dev,
liblcms1-dev, liblcms-dev,
liblcms2-dev,
libldap2-dev, libldap-dev,
libmpg123-dev,
libncurses5-dev [i386] | libncurses-dev [i386],
libncurses5-dev | libncurses-dev,
libopenal-dev (>= 1:1.12) | ubuntu-desktop (<< 1.207),
libpng12-dev,
libpulse-dev,
libsane-dev,
libssl-dev,
libstdc++6-4.5-dev | libstdc++-dev,
libtiff4-dev,
libv4l-dev [i386],
libtiff5-dev | libtiff4-dev | libtiff-dev,
libv4l-dev,
libx11-dev,
libxcomposite-dev,
libxcursor-dev,
@@ -73,14 +63,14 @@ Build-Depends: autotools-dev,
libxxf86vm-dev,
linux-kernel-headers,
linux-libc-dev,
prelink [i386 amd64],
prelink,
quilt (>= 0.46-7~),
sharutils,
unixodbc-dev,
x11proto-xinerama-dev
Standards-Version: 3.9.2
Package: wine-compholio
Package: wine-compholio-i386
Architecture: i386
Multi-Arch: foreign
Pre-Depends: dpkg (>= 1.14.12ubuntu3), ${misc:Pre-Depends}
@@ -104,7 +94,7 @@ Recommends: gettext,
libpulse0,
libsane,
libssl1.0.0,
libtiff4,
libtiff5 | libtiff4,
libv4l-0,
libxcomposite1,
libxcursor1,
@@ -116,7 +106,95 @@ Recommends: gettext,
libxt6,
libxxf86vm1,
unixodbc
Provides: wine-compholio
Section: otherosfs
Priority: optional
Replaces: wine-compholio (<< 1.7.15-1~)
Breaks: wine-compholio (<< 1.7.15-1~)
Description: The Compholio Edition is a special build of the popular Wine software
with patches representing my current staging tree for Wine.
Currently these patches fix:
* Netflix on Firefox hangs with loading bar at 100% (Bug 31993).
* Netflix on Firefox fails with Internet Connection Problem when loading bar is
at 99% (Bug 31858).
.
Microsoft Windows Compatibility Layer (Binary Emulator and Library)
Wine is a compatibility layer for running Windows applications on Linux.
Applications are run at full speed without the need of cpu emulation. Wine
does not require Microsoft Windows, however it can use native system dll
files in place of its own if they are available.
.
This package provides support for loading 32-bit x86 Windows applications
.
This package is based on a recent Wine beta. While many more applications will
work, there may be some loss of functionality compared with the stable release
provided by the regular wine package.
Package: wine-compholio-amd64
Architecture: amd64
Multi-Arch: foreign
Pre-Depends: dpkg (>= 1.14.12ubuntu3), ${misc:Pre-Depends}
Depends: ${shlibs:Depends},
libasound2-plugins,
libncurses5
Recommends: gettext,
libcapi20-3,
libcups2,
libdbus-1-3,
libfontconfig1 | libfontconfig,
libfreetype6,
libgif4,
libgnutls26,
libgphoto2-6 | libgphoto2-2 (>= 2.4.6),
libgphoto2-port10 | libgphoto2-port0 (>= 2.4.6),
libjpeg8,
libopenal1 (>= 1:1.12),
libosmesa6,
libpng12-0,
libpulse0,
libsane,
libssl1.0.0,
libtiff5 | libtiff4,
libv4l-0,
libxcomposite1,
libxcursor1,
libxi6,
libxinerama1,
libxrandr2,
libxrender1,
libxslt1.1,
libxt6,
libxxf86vm1,
unixodbc
Section: otherosfs
Priority: optional
Replaces: wine-compholio (<< 1.7.15-1~)
Breaks: wine-compholio (<< 1.7.15-1~)
Description: The Compholio Edition is a special build of the popular Wine software
with patches representing my current staging tree for Wine.
Currently these patches fix:
* Netflix on Firefox hangs with loading bar at 100% (Bug 31993).
* Netflix on Firefox fails with Internet Connection Problem when loading bar is
at 99% (Bug 31858).
.
Microsoft Windows Compatibility Layer (Binary Emulator and Library)
Wine is a compatibility layer for running Windows applications on Linux.
Applications are run at full speed without the need of cpu emulation. Wine
does not require Microsoft Windows, however it can use native system dll
files in place of its own if they are available.
.
This package provides support for loading 64-bit x86 Windows applications
.
This package is based on a recent Wine beta. While many more applications will
work, there may be some loss of functionality compared with the stable release
provided by the regular wine package.
Package: wine-compholio
Architecture: i386 amd64
Multi-Arch: foreign
Pre-Depends: dpkg (>= 1.14.12ubuntu3), ${misc:Pre-Depends}
Depends: ${misc:Depends}, ${shlibs:Depends},
wine-compholio-i386 (= ${binary:Version}) [i386 amd64],
wine-compholio-amd64 (= ${binary:Version}) [amd64],
Section: otherosfs
Priority: optional
Description: The Compholio Edition is a special build of the popular Wine software
@@ -139,3 +217,57 @@ Description: The Compholio Edition is a special build of the popular Wine softwa
This package is based on a recent Wine beta. While many more applications will
work, there may be some loss of functionality compared with the stable release
provided by the regular wine package.
Package: wine-compholio-dev
Architecture: i386 amd64
Pre-Depends: dpkg (>= 1.14.12ubuntu3), ${misc:Pre-Depends}
Depends: libc6-dev,
${shlibs:Depends},
wine-compholio-i386 (= ${binary:Version}) [i386 amd64],
wine-compholio-amd64 (= ${binary:Version}) [amd64],
Section: libdevel
Priority: optional
Replaces: wine-compholio (<< 1.7.15-1~)
Breaks: wine-compholio (<< 1.7.15-1~)
Description: The Compholio Edition is a special build of the popular Wine software
with patches representing my current staging tree for Wine.
Currently these patches fix:
* Netflix on Firefox hangs with loading bar at 100% (Bug 31993).
* Netflix on Firefox fails with Internet Connection Problem when loading bar is
at 99% (Bug 31858).
.
Microsoft Windows Compatibility Layer (Binary Emulator and Library)
Wine is a compatibility layer for running Windows applications on Linux.
Applications are run at full speed without the need of cpu emulation. Wine
does not require Microsoft Windows, however it can use native system dll
files in place of its own if they are available.
.
This package consists of the development files needed to compile programs
using wine's free version of the Microsoft Windows API.
Package: wine-compholio-dbg
Architecture: i386 amd64
Multi-Arch: same
Pre-Depends: dpkg (>= 1.14.12ubuntu3), ${misc:Pre-Depends}
Depends: ${shlibs:Depends},
wine-compholio-i386 (= ${binary:Version}) [i386 amd64],
wine-compholio-amd64 (= ${binary:Version}) [amd64],
Section: debug
Priority: optional
Replaces: wine-compholio (<< 1.7.15-1~)
Breaks: wine-compholio (<< 1.7.15-1~)
Description: The Compholio Edition is a special build of the popular Wine software
with patches representing my current staging tree for Wine.
Currently these patches fix:
* Netflix on Firefox hangs with loading bar at 100% (Bug 31993).
* Netflix on Firefox fails with Internet Connection Problem when loading bar is
at 99% (Bug 31858).
.
Microsoft Windows Compatibility Layer (Binary Emulator and Library)
Wine is a compatibility layer for running Windows applications on Linux.
Applications are run at full speed without the need of cpu emulation. Wine
does not require Microsoft Windows, however it can use native system dll
files in place of its own if they are available.
.
This package includes debugging symbols useful for reporting crashes and other
failures.

154
debian/rules vendored
View File

@@ -1,36 +1,4 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
# These are used for cross-compiling and for saving the configure script
# from having to guess our platform (since we know it already)
DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
ifneq ($(DEB_HOST_GNU_TYPE),$(DEB_BUILD_GNU_TYPE))
CROSS= --build $(DEB_BUILD_GNU_TYPE) --host $(DEB_HOST_GNU_TYPE)
else
CROSS= --build $(DEB_BUILD_GNU_TYPE)
endif
# Apparently it's important to have an empty LDFLAGS, see:
# http://www.winehq.org/pipermail/wine-bugs/2007-July/062505.html
# For Wine 1.1.44 it's also important not to compile at -O0
LDFLAGS =
CFLAGS = -Wall -g -O2
# On amd64 the 32-bit libraries are in lib32 instead of lib
ifeq ($(DEB_BUILD_ARCH), amd64)
CONFFLAGS += --libdir=\$${prefix}/lib32
endif
# Use gcc-4.5 if it's available
ifeq ($(shell which gcc-4.5),)
@@ -39,106 +7,40 @@ else
CC = gcc-4.5
endif
# Support passing of parallel=<n> in build options
ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
NUMJOBS = $(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
MAKEFLAGS += -j$(NUMJOBS)
endif
%:
dh $@ --parallel
configure:
# Unpack the original Wine version
tar -xjvf wine-*.tar.bz2
mv wine-*/* .
rm wine-*/.* || true
rm wine-*.tar.bz2
rmdir wine-*
config.status: configure
dh_testdir
# Add here commands to configure the package.
ifneq "$(wildcard /usr/share/misc/config.sub)" ""
cp -f /usr/share/misc/config.sub config.sub
endif
ifneq "$(wildcard /usr/share/misc/config.guess)" ""
cp -f /usr/share/misc/config.guess config.guess
endif
override_dh_auto_configure:
# Apply our patches, reconfigure, and update the wineserver protocol request data
make -C "$(CURDIR)/patches/" DESTDIR="$(CURDIR)" install
# Configure
CC="$(CC)" CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" ./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/opt/wine-compholio --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info --with-xattr $(CONFFLAGS)
build: build-stamp
build-stamp: config.status
dh_testdir
# Add here commands to compile the package.
$(MAKE) depend
$(MAKE) $(MAKEFLAGS)
#docbook-to-man debian/wine-compholio.sgml > wine-compholio.1
touch $@
clean:
dh_testdir
dh_testroot
rm -f build-stamp
# Add here commands to clean up after the build process.
[ ! -f Makefile ] || $(MAKE) distclean
rm -f config.sub config.guess
dh_clean
install: build
dh_testdir
dh_testroot
dh_prep
dh_installdirs
# Add here commands to install the package into debian/wine-compholio.
$(MAKE) DESTDIR=$(CURDIR)/debian/wine-compholio install
# Build architecture-independent files here.
binary-indep: build install
# We have nothing to do by default.
# Build architecture-dependent files here.
binary-arch: build install
dh_testdir
dh_testroot
# dh_installchangelogs ChangeLog
# dh_installdocs
dh_installexamples
# dh_install
# dh_installmenu
# dh_installdebconf
# dh_installlogrotate
# dh_installemacsen
# dh_installpam
# dh_installmime
# dh_python
# dh_installinit
# dh_installcron
# dh_installinfo
dh_installman
dh_link
dh_strip
dh_compress
dh_fixperms
# dh_perl
dh_makeshlibs
dh_installdeb
ifeq ($(DEB_BUILD_ARCH), amd64)
dh_gencontrol -- -V"shlibs:Depends= ia32-libs (>= 1.6), lib32asound2 (>> 1.0.14), libc6-i386 (>= 2.6-1), lib32nss-mdns (>= 0.10-3)"
./configure --prefix=/opt/wine-compholio --libdir=\$${prefix}/lib64 --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info --enable-win64 --with-xattr $(CONFFLAGS)
else
LD_LIBRARY_PATH="$(CURDIR)/debian/wine-compholio/opt/wine-compholio/lib:${LD_LIBRARY_PATH}" dh_shlibdeps -L wine-compholio -l debian/wine-compholio/opt/wine-compholio/lib
dh_gencontrol
./configure --prefix=/opt/wine-compholio --libdir=\$${prefix}/lib --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info --with-xattr $(CONFFLAGS)
endif
dh_md5sums
dh_builddeb -- -Z lzma
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install
override_dh_auto_test:
# Wine's test suite does not pass on build daemons, skip it for now
override_dh_installdocs:
dh_installdocs --link-doc=wine-compholio
override_dh_install:
dh_install --fail-missing
# These files will end up in multiple packages otherwise
rm -f debian/wine-compholio/opt/wine-compholio/bin/wine
rm -f debian/wine-compholio/opt/wine-compholio/bin/wine-preloader
rm -f debian/wine-compholio/opt/wine-compholio/bin/wine64
rm -f debian/wine-compholio/opt/wine-compholio/bin/wine64-preloader
override_dh_strip:
dh_strip -Xwine-pthread -Xwine-kthread --dbg-package=wine-compholio-dbg
override_dh_shlibdeps:
ifeq ($(DEB_HOST_ARCH),amd64)
dh_shlibdeps -l $(CURDIR)/debian/tmp/opt/wine-compholio/lib64/
else
dh_shlibdeps -l $(CURDIR)/debian/tmp/opt/wine-compholio/lib/
endif

View File

@@ -16,7 +16,7 @@ for FILE in patches/*/*.def; do
PATCH_DATA="${PATCH_DATA}+ { \"${UUID}:${REVISION}\", \"${AUTHOR}\", \"${TITLE}\" },";
done
PATCH_LINES=$(echo "${PATCH_DATA}" | grep -c '\n');
PATCH_LINES=$(echo "${PATCH_DATA}" | wc -l);
PATCH_LINES=$((${PATCH_LINES}+20));
PATCH_DATA=$(echo "${PATCH_DATA}" | sed ':a;N;$!ba;s/\n/\\n/g');

4
debian/wine-compholio-amd64.install vendored Normal file
View File

@@ -0,0 +1,4 @@
/opt/wine-compholio/lib64/libwine.so*
/opt/wine-compholio/lib64/wine
/opt/wine-compholio/bin/wine64
/opt/wine-compholio/bin/wine64-preloader

1
debian/wine-compholio-dev.install vendored Normal file
View File

@@ -0,0 +1 @@
/opt/wine-compholio/include

4
debian/wine-compholio-i386.install vendored Normal file
View File

@@ -0,0 +1,4 @@
/opt/wine-compholio/lib/libwine.so*
/opt/wine-compholio/lib/wine
/opt/wine-compholio/bin/wine
/opt/wine-compholio/bin/wine-preloader

4
debian/wine-compholio.docs vendored Normal file
View File

@@ -0,0 +1,4 @@
documentation/README.*
ANNOUNCE
AUTHORS
README

2
debian/wine-compholio.install vendored Normal file
View File

@@ -0,0 +1,2 @@
/opt/wine-compholio/bin
/opt/wine-compholio/share

View File

@@ -0,0 +1,77 @@
From a0625ca7d07703028fdad511c37c587e213ff481 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 3 Apr 2014 09:21:51 -0600
Subject: server: Implement socket-specific ioctl() routine.
---
server/sock.c | 26 ++++++++++++++++++++++----
1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/server/sock.c b/server/sock.c
index 5ffb1fe..3eb1bdf 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -49,6 +49,8 @@
#include "windef.h"
#include "winternl.h"
#include "winerror.h"
+#define USE_WS_PREFIX
+#include "winsock2.h"
#include "process.h"
#include "file.h"
@@ -83,9 +85,6 @@
#define FD_WINE_RAW 0x80000000
#define FD_WINE_INTERNAL 0xFFFF0000
-/* Constants for WSAIoctl() */
-#define WSA_FLAG_OVERLAPPED 0x01
-
struct sock
{
struct object obj; /* object header */
@@ -117,6 +116,8 @@ static void sock_destroy( struct object *obj );
static int sock_get_poll_events( struct fd *fd );
static void sock_poll_event( struct fd *fd, int event );
static enum server_fd_type sock_get_fd_type( struct fd *fd );
+static obj_handle_t sock_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async,
+ int blocking, const void *data, data_size_t size );
static void sock_queue_async( struct fd *fd, const async_data_t *data, int type, int count );
static void sock_reselect_async( struct fd *fd, struct async_queue *queue );
static void sock_cancel_async( struct fd *fd, struct process *process, struct thread *thread, client_ptr_t iosb );
@@ -151,7 +152,7 @@ static const struct fd_ops sock_fd_ops =
sock_poll_event, /* poll_event */
no_flush, /* flush */
sock_get_fd_type, /* get_fd_type */
- default_fd_ioctl, /* ioctl */
+ sock_ioctl, /* ioctl */
sock_queue_async, /* queue_async */
sock_reselect_async, /* reselect_async */
sock_cancel_async /* cancel_async */
@@ -518,6 +519,23 @@ static enum server_fd_type sock_get_fd_type( struct fd *fd )
return FD_TYPE_SOCKET;
}
+obj_handle_t sock_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data,
+ int blocking, const void *data, data_size_t size )
+{
+ struct sock *sock = get_fd_user( fd );
+
+ assert( sock->obj.ops == &sock_ops );
+
+ switch(code)
+ {
+ case WS_SIO_ADDRESS_LIST_CHANGE:
+ /* intentional fallthrough, not yet supported */
+ default:
+ set_error( STATUS_NOT_SUPPORTED );
+ return 0;
+ }
+}
+
static void sock_queue_async( struct fd *fd, const async_data_t *data, int type, int count )
{
struct sock *sock = get_fd_user( fd );
--
1.7.9.5

View File

@@ -1,101 +0,0 @@
From a1ad64b059de5325b15ed09a39083f5eb973a2f6 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Wed, 12 Feb 2014 13:46:28 -0700
Subject: ws2_32: Ask the server to process unsupported WSAIoctl operations.
---
dlls/ws2_32/socket.c | 60 ++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 53 insertions(+), 7 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 1c558bf..fe5577c 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -3668,6 +3668,40 @@ static const char *debugstr_wsaioctl(DWORD ioctl)
(USHORT)(ioctl & 0xffff));
}
+/* do an ioctl call through the server */
+static DWORD server_ioctl_sock( SOCKET s, DWORD code, LPVOID in_buff, DWORD in_size,
+ LPVOID out_buff, DWORD out_size, LPDWORD ret_size,
+ LPWSAOVERLAPPED overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion )
+{
+ HANDLE event = overlapped ? overlapped->hEvent : 0;
+ HANDLE handle = SOCKET2HANDLE( s );
+ struct ws2_async *wsa;
+ NTSTATUS status;
+ PIO_STATUS_BLOCK io;
+
+ if (!(wsa = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*wsa) )))
+ return WSA_NOT_ENOUGH_MEMORY;
+ wsa->hSocket = handle;
+ wsa->user_overlapped = overlapped;
+ wsa->completion_func = completion;
+ io = (overlapped ? (PIO_STATUS_BLOCK)overlapped : &wsa->local_iosb);
+
+ status = NtDeviceIoControlFile( handle, event, (PIO_APC_ROUTINE)ws2_async_apc, wsa, io, code,
+ in_buff, in_size, out_buff, out_size );
+ if (status == STATUS_NOT_SUPPORTED)
+ {
+ FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n",
+ code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
+ }
+ else if (status == STATUS_SUCCESS)
+ *ret_size = io->Information; /* "Information" is the size written to the output buffer */
+
+ if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, wsa );
+
+ return NtStatusToWSAError( status );
+}
+
/**********************************************************************
* WSAIoctl (WS2_32.50)
*
@@ -3859,12 +3893,6 @@ INT WINAPI WSAIoctl(SOCKET s, DWORD code, LPVOID in_buff, DWORD in_size, LPVOID
break;
}
- case WS_SIO_ADDRESS_LIST_CHANGE:
- FIXME("-> SIO_ADDRESS_LIST_CHANGE request: stub\n");
- /* FIXME: error and return code depend on whether socket was created
- * with WSA_FLAG_OVERLAPPED, but there is no easy way to get this */
- break;
-
case WS_SIO_ADDRESS_LIST_QUERY:
{
DWORD size;
@@ -4100,11 +4128,29 @@ INT WINAPI WSAIoctl(SOCKET s, DWORD code, LPVOID in_buff, DWORD in_size, LPVOID
WSASetLastError(WSAEOPNOTSUPP);
return SOCKET_ERROR;
default:
- FIXME("unsupported WS_IOCTL cmd (%s)\n", debugstr_wsaioctl(code));
status = WSAEOPNOTSUPP;
break;
}
+ if (status == WSAEOPNOTSUPP)
+ {
+ status = server_ioctl_sock(s, code, in_buff, in_size, out_buff, out_size, &total,
+ overlapped, completion);
+ if (status != WSAEOPNOTSUPP)
+ {
+ if (status == 0 || status == WSA_IO_PENDING)
+ TRACE("-> %s request\n", debugstr_wsaioctl(code));
+ else
+ ERR("-> %s request failed with status 0x%x\n", debugstr_wsaioctl(code), status);
+
+ /* overlapped and completion operations will be handled by the server */
+ completion = NULL;
+ overlapped = NULL;
+ }
+ else
+ FIXME("unsupported WS_IOCTL cmd (%s)\n", debugstr_wsaioctl(code));
+ }
+
if (completion)
{
FIXME( "completion routine %p not supported\n", completion );
--
1.7.9.5

View File

@@ -0,0 +1,114 @@
From 45dfbd2ddb5ca2c64fcfd56392be9c55513abc4b Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 3 Apr 2014 09:23:02 -0600
Subject: server: Add delayed processing for socket-specific ioctl().
---
server/event.c | 13 +++++++++++++
server/named_pipe.c | 13 -------------
server/object.h | 1 +
server/sock.c | 19 +++++++++++++++++--
4 files changed, 31 insertions(+), 15 deletions(-)
diff --git a/server/event.c b/server/event.c
index 4d3c562..0daa5b2 100644
--- a/server/event.c
+++ b/server/event.c
@@ -124,6 +124,19 @@ struct event *create_event( struct directory *root, const struct unicode_str *na
return event;
}
+obj_handle_t alloc_wait_event( struct process *process )
+{
+ obj_handle_t handle = 0;
+ struct event *event = create_event( NULL, NULL, 0, 1, 0, NULL );
+
+ if (event)
+ {
+ handle = alloc_handle( process, event, EVENT_ALL_ACCESS, 0 );
+ release_object( event );
+ }
+ return handle;
+}
+
struct event *get_event_obj( struct process *process, obj_handle_t handle, unsigned int access )
{
return (struct event *)get_handle_obj( process, handle, access, &event_ops );
diff --git a/server/named_pipe.c b/server/named_pipe.c
index 4c85104..6ba2145 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -587,19 +587,6 @@ static enum server_fd_type pipe_client_get_fd_type( struct fd *fd )
return FD_TYPE_PIPE;
}
-static obj_handle_t alloc_wait_event( struct process *process )
-{
- obj_handle_t handle = 0;
- struct event *event = create_event( NULL, NULL, 0, 1, 0, NULL );
-
- if (event)
- {
- handle = alloc_handle( process, event, EVENT_ALL_ACCESS, 0 );
- release_object( event );
- }
- return handle;
-}
-
static obj_handle_t pipe_server_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data,
int blocking, const void *data, data_size_t size )
{
diff --git a/server/object.h b/server/object.h
index bb3ff21..bad162f 100644
--- a/server/object.h
+++ b/server/object.h
@@ -159,6 +159,7 @@ extern struct event *create_event( struct directory *root, const struct unicode_
const struct security_descriptor *sd );
extern struct keyed_event *create_keyed_event( struct directory *root, const struct unicode_str *name,
unsigned int attr, const struct security_descriptor *sd );
+extern obj_handle_t alloc_wait_event( struct process *process );
extern struct event *get_event_obj( struct process *process, obj_handle_t handle, unsigned int access );
extern struct keyed_event *get_keyed_event_obj( struct process *process, obj_handle_t handle, unsigned int access );
extern void pulse_event( struct event *event );
diff --git a/server/sock.c b/server/sock.c
index 3eb1bdf..05fc38b 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -523,17 +523,32 @@ obj_handle_t sock_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *a
int blocking, const void *data, data_size_t size )
{
struct sock *sock = get_fd_user( fd );
+ obj_handle_t wait_handle = 0;
+ async_data_t new_data;
+ int error;
assert( sock->obj.ops == &sock_ops );
+ if (blocking)
+ {
+ if (!(wait_handle = alloc_wait_event( current->process ))) return 0;
+ new_data = *async_data;
+ new_data.event = wait_handle;
+ async_data = &new_data;
+ }
switch(code)
{
case WS_SIO_ADDRESS_LIST_CHANGE:
/* intentional fallthrough, not yet supported */
default:
- set_error( STATUS_NOT_SUPPORTED );
- return 0;
+ error = STATUS_NOT_SUPPORTED;
+ break;
}
+ set_error( error );
+ if (error == STATUS_PENDING)
+ return wait_handle;
+ close_handle( current->process, wait_handle );
+ return 0;
}
static void sock_queue_async( struct fd *fd, const async_data_t *data, int type, int count )
--
1.7.9.5

View File

@@ -1,481 +0,0 @@
From 60f7d242951be1980501f45922dbee5480ac2810 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Tue, 31 Dec 2013 18:36:58 -0700
Subject: server: Implement an interface change notification object.
---
server/event.c | 13 +++
server/named_pipe.c | 13 ---
server/object.h | 1 +
server/sock.c | 324 ++++++++++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 334 insertions(+), 17 deletions(-)
diff --git a/server/event.c b/server/event.c
index b8515af..e8a3888 100644
--- a/server/event.c
+++ b/server/event.c
@@ -124,6 +124,19 @@ struct event *create_event( struct directory *root, const struct unicode_str *na
return event;
}
+obj_handle_t alloc_wait_event( struct process *process )
+{
+ obj_handle_t handle = 0;
+ struct event *event = create_event( NULL, NULL, 0, 1, 0, NULL );
+
+ if (event)
+ {
+ handle = alloc_handle( process, event, EVENT_ALL_ACCESS, 0 );
+ release_object( event );
+ }
+ return handle;
+}
+
struct event *get_event_obj( struct process *process, obj_handle_t handle, unsigned int access )
{
return (struct event *)get_handle_obj( process, handle, access, &event_ops );
diff --git a/server/named_pipe.c b/server/named_pipe.c
index 4c85104..6ba2145 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -587,19 +587,6 @@ static enum server_fd_type pipe_client_get_fd_type( struct fd *fd )
return FD_TYPE_PIPE;
}
-static obj_handle_t alloc_wait_event( struct process *process )
-{
- obj_handle_t handle = 0;
- struct event *event = create_event( NULL, NULL, 0, 1, 0, NULL );
-
- if (event)
- {
- handle = alloc_handle( process, event, EVENT_ALL_ACCESS, 0 );
- release_object( event );
- }
- return handle;
-}
-
static obj_handle_t pipe_server_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data,
int blocking, const void *data, data_size_t size )
{
diff --git a/server/object.h b/server/object.h
index bb3ff21..bad162f 100644
--- a/server/object.h
+++ b/server/object.h
@@ -159,6 +159,7 @@ extern struct event *create_event( struct directory *root, const struct unicode_
const struct security_descriptor *sd );
extern struct keyed_event *create_keyed_event( struct directory *root, const struct unicode_str *name,
unsigned int attr, const struct security_descriptor *sd );
+extern obj_handle_t alloc_wait_event( struct process *process );
extern struct event *get_event_obj( struct process *process, obj_handle_t handle, unsigned int access );
extern struct keyed_event *get_keyed_event_obj( struct process *process, obj_handle_t handle, unsigned int access );
extern void pulse_event( struct event *event );
diff --git a/server/sock.c b/server/sock.c
index 1a3a8f7..9c8284d 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -23,6 +23,7 @@
#include "config.h"
+#include <limits.h>
#include <assert.h>
#include <fcntl.h>
#include <stdarg.h>
@@ -44,11 +45,17 @@
#include <time.h>
#include <unistd.h>
+#ifdef HAVE_LINUX_RTNETLINK_H
+# include <linux/rtnetlink.h>
+#endif
+
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winternl.h"
#include "winerror.h"
+#define USE_WS_PREFIX
+#include "winsock2.h"
#include "process.h"
#include "file.h"
@@ -83,9 +90,6 @@
#define FD_WINE_RAW 0x80000000
#define FD_WINE_INTERNAL 0xFFFF0000
-/* Constants for WSAIoctl() */
-#define WSA_FLAG_OVERLAPPED 0x01
-
struct sock
{
struct object obj; /* object header */
@@ -107,16 +111,28 @@ 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 */
+ struct async_queue *ifchange_q; /* queue for interface change notifications */
+ struct list ifchange_entry; /* entry in ifchange notification list */
};
+#ifdef HAVE_LINUX_RTNETLINK_H
+/* only keep one ifchange object around, all sockets waiting for wakeups will look to it */
+static struct object *ifchange_object = NULL;
+
+static int sock_add_ifchange( struct sock *sock, const async_data_t *async_data );
+#endif
+
static void sock_dump( struct object *obj, int verbose );
static int sock_signaled( struct object *obj, struct wait_queue_entry *entry );
static struct fd *sock_get_fd( struct object *obj );
static void sock_destroy( struct object *obj );
+static void sock_destroy_ifchange_q( struct sock *sock );
static int sock_get_poll_events( struct fd *fd );
static void sock_poll_event( struct fd *fd, int event );
static enum server_fd_type sock_get_fd_type( struct fd *fd );
+static obj_handle_t sock_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async,
+ int blocking, const void *data, data_size_t size );
static void sock_queue_async( struct fd *fd, const async_data_t *data, int type, int count );
static void sock_reselect_async( struct fd *fd, struct async_queue *queue );
static void sock_cancel_async( struct fd *fd, struct process *process, struct thread *thread, client_ptr_t iosb );
@@ -151,7 +167,7 @@ static const struct fd_ops sock_fd_ops =
sock_poll_event, /* poll_event */
no_flush, /* flush */
sock_get_fd_type, /* get_fd_type */
- default_fd_ioctl, /* ioctl */
+ sock_ioctl, /* ioctl */
sock_queue_async, /* queue_async */
sock_reselect_async, /* reselect_async */
sock_cancel_async /* cancel_async */
@@ -518,6 +534,41 @@ static enum server_fd_type sock_get_fd_type( struct fd *fd )
return FD_TYPE_SOCKET;
}
+obj_handle_t sock_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data,
+ int blocking, const void *data, data_size_t size )
+{
+#ifdef HAVE_LINUX_RTNETLINK_H
+ struct sock *sock = get_fd_user( fd );
+ obj_handle_t wait_handle = 0;
+ async_data_t new_data;
+
+ assert( sock->obj.ops == &sock_ops );
+
+ if (blocking)
+ {
+ if (!(wait_handle = alloc_wait_event( current->process ))) return 0;
+ new_data = *async_data;
+ new_data.event = wait_handle;
+ async_data = &new_data;
+ }
+ switch(code)
+ {
+ case WS_SIO_ADDRESS_LIST_CHANGE:
+ if (sock_add_ifchange( sock, async_data ))
+ {
+ set_error( STATUS_PENDING );
+ return wait_handle;
+ }
+ break;
+ default:
+ /* handled by default_fd_ioctl */
+ break;
+ }
+ close_handle( current->process, wait_handle );
+#endif
+ return default_fd_ioctl(fd, code, async_data, blocking, data, size);
+}
+
static void sock_queue_async( struct fd *fd, const async_data_t *data, int type, int count )
{
struct sock *sock = get_fd_user( fd );
@@ -592,6 +643,7 @@ static void sock_destroy( struct object *obj )
free_async_queue( sock->read_q );
free_async_queue( sock->write_q );
+ sock_destroy_ifchange_q( sock );
if (sock->event) release_object( sock->event );
if (sock->fd)
{
@@ -618,6 +670,7 @@ static void init_sock(struct sock *sock)
sock->deferred = NULL;
sock->read_q = NULL;
sock->write_q = NULL;
+ sock->ifchange_q = NULL;
memset( sock->errors, 0, sizeof(sock->errors) );
}
@@ -906,6 +959,269 @@ static void sock_set_error(void)
set_error( sock_get_ntstatus( errno ) );
}
+#ifdef HAVE_LINUX_RTNETLINK_H
+
+static void ifchange_dump( struct object *obj, int verbose );
+static struct fd *ifchange_get_fd( struct object *obj );
+static void ifchange_destroy( struct object *obj );
+
+static int ifchange_get_poll_events( struct fd *fd );
+static void ifchange_poll_event( struct fd *fd, int event );
+static void ifchange_reselect_async( struct fd *fd, struct async_queue *queue );
+
+struct ifchange
+{
+ struct object obj; /* object header */
+ struct fd *fd; /* interface change file descriptor */
+ struct list sockets; /* list of sockets to send interface change notifications */
+};
+
+static const struct object_ops ifchange_ops =
+{
+ sizeof(struct ifchange), /* size */
+ ifchange_dump, /* dump */
+ no_get_type, /* get_type */
+ add_queue, /* add_queue */
+ NULL, /* remove_queue */
+ NULL, /* signaled */
+ no_satisfied, /* satisfied */
+ no_signal, /* signal */
+ ifchange_get_fd, /* get_fd */
+ default_fd_map_access, /* map_access */
+ default_get_sd, /* get_sd */
+ default_set_sd, /* set_sd */
+ no_lookup_name, /* lookup_name */
+ no_open_file, /* open_file */
+ no_close_handle, /* close_handle */
+ ifchange_destroy /* destroy */
+};
+
+static const struct fd_ops ifchange_fd_ops =
+{
+ ifchange_get_poll_events, /* get_poll_events */
+ ifchange_poll_event, /* poll_event */
+ NULL, /* flush */
+ NULL, /* get_fd_type */
+ NULL, /* ioctl */
+ NULL, /* queue_async */
+ ifchange_reselect_async, /* reselect_async */
+ NULL /* cancel_async */
+};
+
+static void ifchange_dump( struct object *obj, int verbose )
+{
+ assert( obj->ops == &ifchange_ops );
+ printf( "ifchange\n" );
+}
+
+static struct fd *ifchange_get_fd( struct object *obj )
+{
+ struct ifchange *ifchange = (struct ifchange *)obj;
+ return (struct fd *)grab_object( ifchange->fd );
+}
+
+static void ifchange_destroy( struct object *obj )
+{
+ struct ifchange *ifchange = (struct ifchange *)obj;
+ assert( obj->ops == &ifchange_ops );
+
+ if (ifchange->fd)
+ {
+ /* reset the global ifchange object so that it will be recreated if it is needed again */
+ assert( obj == ifchange_object );
+ ifchange_object = NULL;
+
+ /* shut the socket down to force pending poll() calls in the client to return */
+ shutdown( get_unix_fd(ifchange->fd), SHUT_RDWR );
+ release_object( ifchange->fd );
+ }
+}
+
+static int ifchange_get_poll_events( struct fd *fd )
+{
+ return POLLIN;
+}
+
+static void ifchange_add_sock( struct object *obj, struct sock *sock )
+{
+ struct ifchange *ifchange = (struct ifchange *)obj;
+
+ list_add_tail( &ifchange->sockets, &sock->ifchange_entry );
+}
+
+/* we only need one of these interface notification objects, all of the sockets dependent upon
+ * it will wake up when a notification event occurs */
+static struct object *grab_ifchange( void )
+{
+ struct ifchange *ifchange;
+ struct sockaddr_nl addr;
+ int unix_fd;
+
+ if (ifchange_object)
+ {
+ /* increment the refcount for each socket that uses the ifchange object */
+ return grab_object( ifchange_object );
+ }
+
+ /* create the socket we need for processing interface change notifications */
+ unix_fd = socket( PF_NETLINK, SOCK_RAW, NETLINK_ROUTE );
+ if (unix_fd == -1)
+ {
+ sock_set_error();
+ return NULL;
+ }
+ fcntl( unix_fd, F_SETFL, O_NONBLOCK ); /* make socket nonblocking */
+ memset( &addr, 0, sizeof(addr) );
+ addr.nl_family = AF_NETLINK;
+ addr.nl_groups = RTMGRP_IPV4_IFADDR;
+ /* bind the socket to the special netlink kernel interface */
+ if (bind( unix_fd, (struct sockaddr *)&addr, sizeof(addr) ) == -1)
+ {
+ sock_set_error();
+ close( unix_fd );
+ return NULL;
+ }
+ if (!(ifchange = alloc_object( &ifchange_ops )))
+ {
+ set_error( STATUS_NO_MEMORY );
+ close( unix_fd );
+ return NULL;
+ }
+ list_init( &ifchange->sockets );
+ if (!(ifchange->fd = create_anonymous_fd( &ifchange_fd_ops, unix_fd, &ifchange->obj, 0 )))
+ {
+ set_error( STATUS_NO_MEMORY );
+ release_object( ifchange );
+ return NULL;
+ }
+ set_fd_events( ifchange->fd, POLLIN ); /* enable read wakeup on the file descriptor */
+
+ /* the ifchange object is now successfully configured */
+ ifchange_object = &ifchange->obj;
+ return ifchange_object;
+}
+
+/* create a new ifchange queue for a specific socket or, if one already exists, reuse the existing one */
+static struct async_queue *sock_get_ifchange_q( struct sock *sock )
+{
+ struct object *ifchange;
+ struct fd *fd;
+
+ if (sock->ifchange_q) /* reuse existing ifchange_q for this socket */
+ return sock->ifchange_q;
+
+ if (!(ifchange = grab_ifchange()))
+ return NULL;
+
+ /* create the ifchange notification queue */
+ fd = ifchange_get_fd( ifchange );
+ sock->ifchange_q = create_async_queue( fd );
+ release_object( fd );
+ if (!sock->ifchange_q)
+ {
+ set_error( STATUS_NO_MEMORY );
+ release_object( ifchange );
+ return NULL;
+ }
+
+ /* add the socket to the ifchange notification list */
+ ifchange_add_sock( ifchange, sock );
+ return sock->ifchange_q;
+}
+
+/* wake up all the sockets waiting for a change notification event */
+static void ifchange_wake_up( struct object *obj, unsigned int status )
+{
+ struct ifchange *ifchange = (struct ifchange *)obj;
+ struct list *ptr, *next;
+ assert( obj->ops == &ifchange_ops );
+ assert( obj == ifchange_object );
+
+ LIST_FOR_EACH_SAFE( ptr, next, &ifchange->sockets )
+ {
+ struct sock *sock = LIST_ENTRY( ptr, struct sock, ifchange_entry );
+
+ assert( sock->ifchange_q );
+ async_wake_up( sock->ifchange_q, status ); /* issue ifchange notification for the socket */
+ sock_destroy_ifchange_q( sock ); /* remove socket from list and decrement ifchange refcount */
+ }
+}
+
+static void ifchange_poll_event( struct fd *fd, int event )
+{
+ struct object *ifchange = get_fd_user( fd );
+ unsigned int status = STATUS_PENDING;
+ char buffer[PIPE_BUF];
+ int r;
+
+ r = recv( get_unix_fd(fd), buffer, sizeof(buffer), MSG_DONTWAIT );
+ if (r < 0)
+ {
+ if (errno == EWOULDBLOCK || errno == EAGAIN)
+ return; /* retry when poll() says the socket is ready */
+ status = sock_get_ntstatus( errno );
+ }
+ else if (r > 0)
+ {
+ struct nlmsghdr *nlh;
+
+ for (nlh = (struct nlmsghdr *)buffer; NLMSG_OK(nlh, r); nlh = NLMSG_NEXT(nlh, r))
+ {
+ if (nlh->nlmsg_type == NLMSG_DONE)
+ break;
+ if (nlh->nlmsg_type == RTM_NEWADDR || nlh->nlmsg_type == RTM_DELADDR)
+ status = STATUS_SUCCESS;
+ }
+ }
+ if (status != STATUS_PENDING)
+ ifchange_wake_up( ifchange, status );
+}
+
+static void ifchange_reselect_async( struct fd *fd, struct async_queue *queue )
+{
+ /* do nothing, this object is about to disappear */
+}
+
+/* add interface change notification to a socket */
+static int sock_add_ifchange( struct sock *sock, const async_data_t *async_data )
+{
+ struct async_queue *ifchange_q;
+ struct async *async;
+
+ if (!(ifchange_q = sock_get_ifchange_q( sock )))
+ return FALSE;
+
+ if (!(async = create_async( current, ifchange_q, async_data )))
+ {
+ if (!async_queued( ifchange_q ))
+ sock_destroy_ifchange_q( sock );
+
+ set_error( STATUS_NO_MEMORY );
+ return FALSE;
+ }
+
+ release_object( async );
+ return TRUE;
+}
+
+#endif
+
+/* destroy an existing ifchange queue for a specific socket */
+static void sock_destroy_ifchange_q( struct sock *sock )
+{
+#ifdef HAVE_LINUX_RTNETLINK_H
+ if (sock->ifchange_q)
+ {
+ assert( ifchange_object );
+
+ list_remove( &sock->ifchange_entry );
+ free_async_queue( sock->ifchange_q );
+ sock->ifchange_q = NULL;
+ release_object( ifchange_object );
+ }
+#endif
+}
+
/* create a socket */
DECL_HANDLER(create_socket)
{
--
1.7.9.5

View File

@@ -0,0 +1,150 @@
From 69e77bd226057f486d1c076ccbebb963d3b750ee Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 3 Apr 2014 09:25:48 -0600
Subject: server: Add socket-side support for the interface change
notification object.
---
server/sock.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 91 insertions(+), 1 deletion(-)
diff --git a/server/sock.c b/server/sock.c
index 05fc38b..20d022f 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -106,12 +106,18 @@ 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 */
+ struct async_queue *ifchange_q; /* queue for interface change notifications */
+ struct object *ifchange_obj; /* the interface change notification object */
+ struct list ifchange_entry; /* entry in ifchange notification list */
};
static void sock_dump( struct object *obj, int verbose );
+static int sock_add_ifchange( struct sock *sock, const async_data_t *async_data );
static int sock_signaled( struct object *obj, struct wait_queue_entry *entry );
static struct fd *sock_get_fd( struct object *obj );
static void sock_destroy( struct object *obj );
+static int sock_get_ifchange_q( struct sock *sock, struct async_queue **async_queue );
+static void sock_destroy_ifchange_q( struct sock *sock );
static int sock_get_poll_events( struct fd *fd );
static void sock_poll_event( struct fd *fd, int event );
@@ -539,7 +545,8 @@ obj_handle_t sock_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *a
switch(code)
{
case WS_SIO_ADDRESS_LIST_CHANGE:
- /* intentional fallthrough, not yet supported */
+ error = sock_add_ifchange( sock, async_data );
+ break;
default:
error = STATUS_NOT_SUPPORTED;
break;
@@ -625,6 +632,7 @@ static void sock_destroy( struct object *obj )
free_async_queue( sock->read_q );
free_async_queue( sock->write_q );
+ sock_destroy_ifchange_q( sock );
if (sock->event) release_object( sock->event );
if (sock->fd)
{
@@ -651,6 +659,8 @@ static void init_sock(struct sock *sock)
sock->deferred = NULL;
sock->read_q = NULL;
sock->write_q = NULL;
+ sock->ifchange_q = NULL;
+ sock->ifchange_obj = NULL;
memset( sock->errors, 0, sizeof(sock->errors) );
}
@@ -939,6 +949,86 @@ static void sock_set_error(void)
set_error( sock_get_ntstatus( errno ) );
}
+/* add interface change notification to a socket */
+static int sock_add_ifchange( struct sock *sock, const async_data_t *async_data )
+{
+ struct async_queue *ifchange_q = NULL;
+ struct async *async;
+ int error;
+
+ error = sock_get_ifchange_q( sock, &ifchange_q );
+ if (error != STATUS_PENDING)
+ return error;
+
+ if (!(async = create_async( current, ifchange_q, async_data )))
+ {
+ if (!async_queued( ifchange_q ))
+ sock_destroy_ifchange_q( sock );
+
+ return STATUS_NO_MEMORY;
+ }
+
+ release_object( async );
+ return error;
+}
+
+/* stub ifchange object */
+static int get_ifchange( struct object **obj )
+{
+ return STATUS_NOT_SUPPORTED;
+}
+
+/* stub ifchange add socket to list */
+static void ifchange_add_sock( struct object *obj, struct sock *sock )
+{
+}
+
+/* create a new ifchange queue for a specific socket or, if one already exists, reuse the existing one */
+static int sock_get_ifchange_q( struct sock *sock, struct async_queue **async_queue )
+{
+ struct object *ifchange = NULL;
+ struct fd *fd;
+ int error;
+
+ if (sock->ifchange_q) /* reuse existing ifchange_q for this socket */
+ {
+ *async_queue = sock->ifchange_q;
+ return STATUS_PENDING;
+ }
+
+ error = get_ifchange( &ifchange );
+ if (error != STATUS_PENDING)
+ return error;
+
+ /* create the ifchange notification queue */
+ fd = ifchange->ops->get_fd( ifchange );
+ sock->ifchange_q = create_async_queue( fd );
+ release_object( fd );
+ if (!sock->ifchange_q)
+ {
+ release_object( ifchange );
+ return STATUS_NO_MEMORY;
+ }
+
+ /* add the socket to the ifchange notification list */
+ ifchange_add_sock( ifchange, sock );
+ sock->ifchange_obj = ifchange;
+ *async_queue = sock->ifchange_q;
+ return error;
+}
+
+/* destroy an existing ifchange queue for a specific socket */
+static void sock_destroy_ifchange_q( struct sock *sock )
+{
+ if (sock->ifchange_q)
+ {
+ list_remove( &sock->ifchange_entry );
+ free_async_queue( sock->ifchange_q );
+ sock->ifchange_q = NULL;
+ release_object( sock->ifchange_obj );
+ }
+}
+
/* create a socket */
DECL_HANDLER(create_socket)
{
--
1.7.9.5

View File

@@ -0,0 +1,237 @@
From 85d0475a493be336c340f25cab9895846e202f26 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 3 Apr 2014 09:26:34 -0600
Subject: server: Implement the interface change notification object.
---
server/sock.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 198 insertions(+), 2 deletions(-)
diff --git a/server/sock.c b/server/sock.c
index 20d022f..82464f2 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -43,6 +43,10 @@
#endif
#include <time.h>
#include <unistd.h>
+#include <limits.h>
+#ifdef HAVE_LINUX_RTNETLINK_H
+# include <linux/rtnetlink.h>
+#endif
#include "ntstatus.h"
#define WIN32_NO_STATUS
@@ -972,15 +976,207 @@ static int sock_add_ifchange( struct sock *sock, const async_data_t *async_data
return error;
}
-/* stub ifchange object */
+#ifdef HAVE_LINUX_RTNETLINK_H
+
+/* only keep one ifchange object around, all sockets waiting for wakeups will look to it */
+static struct object *ifchange_object = NULL;
+
+static void ifchange_dump( struct object *obj, int verbose );
+static struct fd *ifchange_get_fd( struct object *obj );
+static void ifchange_destroy( struct object *obj );
+
+static int ifchange_get_poll_events( struct fd *fd );
+static void ifchange_poll_event( struct fd *fd, int event );
+static void ifchange_reselect_async( struct fd *fd, struct async_queue *queue );
+
+struct ifchange
+{
+ struct object obj; /* object header */
+ struct fd *fd; /* interface change file descriptor */
+ struct list sockets; /* list of sockets to send interface change notifications */
+};
+
+static const struct object_ops ifchange_ops =
+{
+ sizeof(struct ifchange), /* size */
+ ifchange_dump, /* dump */
+ no_get_type, /* get_type */
+ add_queue, /* add_queue */
+ NULL, /* remove_queue */
+ NULL, /* signaled */
+ no_satisfied, /* satisfied */
+ no_signal, /* signal */
+ ifchange_get_fd, /* get_fd */
+ default_fd_map_access, /* map_access */
+ default_get_sd, /* get_sd */
+ default_set_sd, /* set_sd */
+ no_lookup_name, /* lookup_name */
+ no_open_file, /* open_file */
+ no_close_handle, /* close_handle */
+ ifchange_destroy /* destroy */
+};
+
+static const struct fd_ops ifchange_fd_ops =
+{
+ ifchange_get_poll_events, /* get_poll_events */
+ ifchange_poll_event, /* poll_event */
+ NULL, /* flush */
+ NULL, /* get_fd_type */
+ NULL, /* ioctl */
+ NULL, /* queue_async */
+ ifchange_reselect_async, /* reselect_async */
+ NULL /* cancel_async */
+};
+
+static void ifchange_dump( struct object *obj, int verbose )
+{
+ assert( obj->ops == &ifchange_ops );
+ printf( "ifchange\n" );
+}
+
+static struct fd *ifchange_get_fd( struct object *obj )
+{
+ struct ifchange *ifchange = (struct ifchange *)obj;
+ return (struct fd *)grab_object( ifchange->fd );
+}
+
+static void ifchange_destroy( struct object *obj )
+{
+ struct ifchange *ifchange = (struct ifchange *)obj;
+ assert( obj->ops == &ifchange_ops );
+
+ if (ifchange->fd)
+ {
+ /* reset the global ifchange object so that it will be recreated if it is needed again */
+ assert( obj == ifchange_object );
+ ifchange_object = NULL;
+
+ /* shut the socket down to force pending poll() calls in the client to return */
+ shutdown( get_unix_fd(ifchange->fd), SHUT_RDWR );
+ release_object( ifchange->fd );
+ }
+}
+
+static int ifchange_get_poll_events( struct fd *fd )
+{
+ return POLLIN;
+}
+
+/* wake up all the sockets waiting for a change notification event */
+static void ifchange_wake_up( struct object *obj, unsigned int status )
+{
+ struct ifchange *ifchange = (struct ifchange *)obj;
+ struct list *ptr, *next;
+ assert( obj->ops == &ifchange_ops );
+ assert( obj == ifchange_object );
+
+ LIST_FOR_EACH_SAFE( ptr, next, &ifchange->sockets )
+ {
+ struct sock *sock = LIST_ENTRY( ptr, struct sock, ifchange_entry );
+
+ assert( sock->ifchange_q );
+ async_wake_up( sock->ifchange_q, status ); /* issue ifchange notification for the socket */
+ sock_destroy_ifchange_q( sock ); /* remove socket from list and decrement ifchange refcount */
+ }
+}
+
+static void ifchange_poll_event( struct fd *fd, int event )
+{
+ struct object *ifchange = get_fd_user( fd );
+ unsigned int status = STATUS_PENDING;
+ char buffer[PIPE_BUF];
+ int r;
+
+ r = recv( get_unix_fd(fd), buffer, sizeof(buffer), MSG_DONTWAIT );
+ if (r < 0)
+ {
+ if (errno == EWOULDBLOCK || errno == EAGAIN)
+ return; /* retry when poll() says the socket is ready */
+ status = sock_get_ntstatus( errno );
+ }
+ else if (r > 0)
+ {
+ struct nlmsghdr *nlh;
+
+ for (nlh = (struct nlmsghdr *)buffer; NLMSG_OK(nlh, r); nlh = NLMSG_NEXT(nlh, r))
+ {
+ if (nlh->nlmsg_type == NLMSG_DONE)
+ break;
+ if (nlh->nlmsg_type == RTM_NEWADDR || nlh->nlmsg_type == RTM_DELADDR)
+ status = STATUS_SUCCESS;
+ }
+ }
+ if (status != STATUS_PENDING)
+ ifchange_wake_up( ifchange, status );
+}
+
+static void ifchange_reselect_async( struct fd *fd, struct async_queue *queue )
+{
+ /* do nothing, this object is about to disappear */
+}
+
+#endif
+
+/* we only need one of these interface notification objects, all of the sockets dependent upon
+ * it will wake up when a notification event occurs */
static int get_ifchange( struct object **obj )
{
+#ifdef HAVE_LINUX_RTNETLINK_H
+ struct ifchange *ifchange;
+ struct sockaddr_nl addr;
+ int unix_fd;
+
+ if (ifchange_object)
+ {
+ /* increment the refcount for each socket that uses the ifchange object */
+ *obj = grab_object( ifchange_object );
+ return STATUS_PENDING;
+ }
+
+ /* create the socket we need for processing interface change notifications */
+ unix_fd = socket( PF_NETLINK, SOCK_RAW, NETLINK_ROUTE );
+ if (unix_fd == -1)
+ return sock_get_ntstatus( errno );
+ fcntl( unix_fd, F_SETFL, O_NONBLOCK ); /* make socket nonblocking */
+ memset( &addr, 0, sizeof(addr) );
+ addr.nl_family = AF_NETLINK;
+ addr.nl_groups = RTMGRP_IPV4_IFADDR;
+ /* bind the socket to the special netlink kernel interface */
+ if (bind( unix_fd, (struct sockaddr *)&addr, sizeof(addr) ) == -1)
+ {
+ close( unix_fd );
+ return sock_get_ntstatus( errno );
+ }
+ if (!(ifchange = alloc_object( &ifchange_ops )))
+ {
+ close( unix_fd );
+ return STATUS_NO_MEMORY;
+ }
+ list_init( &ifchange->sockets );
+ if (!(ifchange->fd = create_anonymous_fd( &ifchange_fd_ops, unix_fd, &ifchange->obj, 0 )))
+ {
+ release_object( ifchange );
+ return STATUS_NO_MEMORY;
+ }
+ set_fd_events( ifchange->fd, POLLIN ); /* enable read wakeup on the file descriptor */
+
+ /* the ifchange object is now successfully configured */
+ ifchange_object = &ifchange->obj;
+ *obj = &ifchange->obj;
+ return STATUS_PENDING;
+#else
return STATUS_NOT_SUPPORTED;
+#endif
}
-/* stub ifchange add socket to list */
+/* add the socket to the interface change notification list */
static void ifchange_add_sock( struct object *obj, struct sock *sock )
{
+#ifdef HAVE_LINUX_RTNETLINK_H
+ struct ifchange *ifchange = (struct ifchange *)obj;
+
+ list_add_tail( &ifchange->sockets, &sock->ifchange_entry );
+#endif
}
/* create a new ifchange queue for a specific socket or, if one already exists, reuse the existing one */
--
1.7.9.5

View File

@@ -1,6 +1,6 @@
From b3156dc253a94f9414a04569181728ec43608f2a Mon Sep 17 00:00:00 2001
From 621fe55cd32221c542df779540d3bc8ea701821d Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Mon, 18 Nov 2013 17:22:14 -0700
Date: Thu, 3 Apr 2014 09:26:45 -0600
Subject: ws2_32: Add an interactive test for interface change notifications.
---
@@ -8,10 +8,10 @@ Subject: ws2_32: Add an interactive test for interface change notifications.
1 file changed, 68 insertions(+)
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index 0abf732..4703e59 100644
index dcedd99..e55273a 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -6487,6 +6487,73 @@ static void test_sioRoutingInterfaceQuery(void)
@@ -6607,6 +6607,73 @@ static void test_sioRoutingInterfaceQuery(void)
closesocket(sock);
}
@@ -85,7 +85,7 @@ index 0abf732..4703e59 100644
static void test_synchronous_WSAIoctl(void)
{
HANDLE previous_port, io_port;
@@ -7570,6 +7637,7 @@ START_TEST( sock )
@@ -7694,6 +7761,7 @@ START_TEST( sock )
test_ConnectEx();
test_sioRoutingInterfaceQuery();

View File

@@ -1,3 +1,3 @@
Revision: 1
Revision: 2
Author: Erich E. Hoover
Title: Implement SIO_ADDRESS_LIST_CHANGE.

View File

@@ -0,0 +1,189 @@
From 565726f893787072a12329af854e072c5d325906 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Fri, 4 Apr 2014 10:11:56 +0200
Subject: ntdll: Unify exception function lookup on x86_64.
---
dlls/ntdll/signal_x86_64.c | 102 +++++++++++++++++++++-----------------------
1 file changed, 48 insertions(+), 54 deletions(-)
diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c
index b28cb99..57afe16 100644
--- a/dlls/ntdll/signal_x86_64.c
+++ b/dlls/ntdll/signal_x86_64.c
@@ -1921,6 +1921,28 @@ static RUNTIME_FUNCTION *find_function_info( ULONG64 pc, HMODULE module,
return NULL;
}
+/**********************************************************************
+ * lookup_function_info
+ */
+static RUNTIME_FUNCTION *lookup_function_info( ULONG64 pc, ULONG64 *base, LDR_MODULE **module )
+{
+ RUNTIME_FUNCTION *func = NULL;
+ ULONG size;
+
+ /* PE module or wine module */
+ if (!LdrFindEntryForAddress( (void *)pc, module ))
+ {
+ *base = (ULONG64)(*module)->BaseAddress;
+ if ((func = RtlImageDirectoryEntryToData( (*module)->BaseAddress, TRUE,
+ IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
+ {
+ /* lookup in function table */
+ func = find_function_info( pc, (*module)->BaseAddress, func, size );
+ }
+ }
+
+ return func;
+}
/**********************************************************************
* call_handler
@@ -2002,7 +2024,6 @@ static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_contex
DISPATCHER_CONTEXT dispatch;
CONTEXT context, new_context;
LDR_MODULE *module;
- DWORD size;
NTSTATUS status;
context = *orig_context;
@@ -2021,31 +2042,18 @@ static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_contex
/* first look for PE exception information */
- if (!LdrFindEntryForAddress( (void *)context.Rip, &module ))
+ if ((dispatch.FunctionEntry = lookup_function_info( context.Rip, &dispatch.ImageBase, &module )))
{
- RUNTIME_FUNCTION *dir;
-
- dispatch.ImageBase = (ULONG64)module->BaseAddress;
- if ((dir = RtlImageDirectoryEntryToData( module->BaseAddress, TRUE,
- IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
- {
- if ((dispatch.FunctionEntry = find_function_info( context.Rip, module->BaseAddress,
- dir, size )))
- {
- dispatch.LanguageHandler = RtlVirtualUnwind( UNW_FLAG_EHANDLER, dispatch.ImageBase,
- context.Rip, dispatch.FunctionEntry,
- &new_context, &dispatch.HandlerData,
- &dispatch.EstablisherFrame, NULL );
- goto unwind_done;
- }
- }
- else if (!(module->Flags & LDR_WINE_INTERNAL))
- WARN( "exception data not found in %s\n", debugstr_w(module->BaseDllName.Buffer) );
+ dispatch.LanguageHandler = RtlVirtualUnwind( UNW_FLAG_EHANDLER, dispatch.ImageBase,
+ context.Rip, dispatch.FunctionEntry,
+ &new_context, &dispatch.HandlerData,
+ &dispatch.EstablisherFrame, NULL );
+ goto unwind_done;
}
/* then look for host system exception information */
- if (!module || (module->Flags & LDR_WINE_INTERNAL))
+ else if (!module || (module->Flags & LDR_WINE_INTERNAL))
{
struct dwarf_eh_bases bases;
const struct dwarf_fde *fde = _Unwind_Find_FDE( (void *)(context.Rip - 1), &bases );
@@ -2065,6 +2073,8 @@ static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_contex
}
}
+ else WARN( "exception data not found in %s\n", debugstr_w(module->BaseDllName.Buffer) );
+
/* no exception information, treat as a leaf function */
new_context.Rip = *(ULONG64 *)context.Rsp;
@@ -2540,23 +2550,18 @@ PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry( ULONG64 pc, ULONG64 *base, UNWI
{
LDR_MODULE *module;
RUNTIME_FUNCTION *func;
- ULONG size;
/* FIXME: should use the history table to make things faster */
- if (LdrFindEntryForAddress( (void *)pc, &module ))
+ func = lookup_function_info( pc, base, &module );
+ if (!func)
{
- WARN( "module not found for %lx\n", pc );
- return NULL;
- }
- if (!(func = RtlImageDirectoryEntryToData( module->BaseAddress, TRUE,
- IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
- {
- WARN( "no exception table found in module %p pc %lx\n", module->BaseAddress, pc );
- return NULL;
+ if (module)
+ WARN( "no exception table found in module %p pc %lx\n", module->BaseAddress, pc );
+ else
+ WARN( "module not found for %lx\n", pc );
}
- func = find_function_info( pc, module->BaseAddress, func, size );
- if (func) *base = (ULONG64)module->BaseAddress;
+
return func;
}
@@ -2916,7 +2921,7 @@ void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec
CONTEXT new_context;
LDR_MODULE *module;
NTSTATUS status;
- DWORD i, size;
+ DWORD i;
RtlCaptureContext( context );
new_context = *context;
@@ -2962,31 +2967,18 @@ void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec
/* first look for PE exception information */
- if (!LdrFindEntryForAddress( (void *)context->Rip, &module ))
+ if ((dispatch.FunctionEntry = lookup_function_info( context->Rip, &dispatch.ImageBase, &module )))
{
- RUNTIME_FUNCTION *dir;
-
- dispatch.ImageBase = (ULONG64)module->BaseAddress;
- if ((dir = RtlImageDirectoryEntryToData( module->BaseAddress, TRUE,
- IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
- {
- if ((dispatch.FunctionEntry = find_function_info( context->Rip, module->BaseAddress,
- dir, size )))
- {
- dispatch.LanguageHandler = RtlVirtualUnwind( UNW_FLAG_UHANDLER, dispatch.ImageBase,
- context->Rip, dispatch.FunctionEntry,
- &new_context, &dispatch.HandlerData,
- &dispatch.EstablisherFrame, NULL );
- goto unwind_done;
- }
- }
- else if (!(module->Flags & LDR_WINE_INTERNAL))
- WARN( "exception data not found in %s\n", debugstr_w(module->BaseDllName.Buffer) );
+ dispatch.LanguageHandler = RtlVirtualUnwind( UNW_FLAG_UHANDLER, dispatch.ImageBase,
+ context->Rip, dispatch.FunctionEntry,
+ &new_context, &dispatch.HandlerData,
+ &dispatch.EstablisherFrame, NULL );
+ goto unwind_done;
}
/* then look for host system exception information */
- if (!module || (module->Flags & LDR_WINE_INTERNAL))
+ else if (!module || (module->Flags & LDR_WINE_INTERNAL))
{
struct dwarf_eh_bases bases;
const struct dwarf_fde *fde = _Unwind_Find_FDE( (void *)(context->Rip - 1), &bases );
@@ -3006,6 +2998,8 @@ void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec
}
}
+ else WARN( "exception data not found in %s\n", debugstr_w(module->BaseDllName.Buffer) );
+
/* no exception information, treat as a leaf function */
new_context.Rip = *(ULONG64 *)context->Rsp;
--
1.7.9.5

View File

@@ -0,0 +1,216 @@
From efcbb9869c71a40f88ff0c4516f0d65419394104 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Fri, 4 Apr 2014 19:32:33 +0200
Subject: ntdll: Implement dynamic unwind table functions.
---
dlls/ntdll/ntdll.spec | 1 +
dlls/ntdll/signal_x86_64.c | 128 +++++++++++++++++++++++++++++++++++++++++++-
include/winnt.h | 3 ++
3 files changed, 130 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 0dd75a2..7a3c3f1 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -689,6 +689,7 @@
# @ stub RtlInitializeStackTraceDataBase
@ stub RtlInsertElementGenericTable
# @ stub RtlInsertElementGenericTableAvl
+@ cdecl -arch=x86_64 RtlInstallFunctionTableCallback(long long long ptr ptr ptr)
@ stdcall RtlInt64ToUnicodeString(int64 long ptr)
@ stdcall RtlIntegerToChar(long long long ptr)
@ stdcall RtlIntegerToUnicodeString(long long ptr)
diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c
index 57afe16..c8e1a16 100644
--- a/dlls/ntdll/signal_x86_64.c
+++ b/dlls/ntdll/signal_x86_64.c
@@ -56,6 +56,7 @@
#include "winternl.h"
#include "wine/library.h"
#include "wine/exception.h"
+#include "wine/list.h"
#include "ntdll_misc.h"
#include "wine/debug.h"
@@ -271,6 +272,34 @@ typedef int (*wine_signal_handler)(unsigned int sig);
static wine_signal_handler handlers[256];
+/***********************************************************************
+ * Dynamic unwind table
+ */
+
+struct dynamic_unwind_entry
+{
+ struct list entry;
+
+ DWORD64 base;
+ DWORD size;
+
+ RUNTIME_FUNCTION *table;
+ DWORD table_size;
+
+ PGET_RUNTIME_FUNCTION_CALLBACK callback;
+ PVOID context;
+};
+
+static struct list dynamic_unwind_list = LIST_INIT(dynamic_unwind_list);
+
+static RTL_CRITICAL_SECTION dynamic_unwind_section;
+static RTL_CRITICAL_SECTION_DEBUG dynamic_unwind_debug =
+{
+ 0, 0, &dynamic_unwind_section,
+ { &dynamic_unwind_debug.ProcessLocksList, &dynamic_unwind_debug.ProcessLocksList },
+ 0, 0, { (DWORD_PTR)(__FILE__ ": dynamic_unwind_section") }
+};
+static RTL_CRITICAL_SECTION dynamic_unwind_section = { &dynamic_unwind_debug, -1, 0, 0, 0, 0 };
/***********************************************************************
* Definitions for Win32 unwind tables
@@ -1927,6 +1956,7 @@ static RUNTIME_FUNCTION *find_function_info( ULONG64 pc, HMODULE module,
static RUNTIME_FUNCTION *lookup_function_info( ULONG64 pc, ULONG64 *base, LDR_MODULE **module )
{
RUNTIME_FUNCTION *func = NULL;
+ struct dynamic_unwind_entry *entry;
ULONG size;
/* PE module or wine module */
@@ -1940,6 +1970,25 @@ static RUNTIME_FUNCTION *lookup_function_info( ULONG64 pc, ULONG64 *base, LDR_MO
func = find_function_info( pc, (*module)->BaseAddress, func, size );
}
}
+ else
+ {
+ RtlEnterCriticalSection( &dynamic_unwind_section );
+ LIST_FOR_EACH_ENTRY( entry, &dynamic_unwind_list, struct dynamic_unwind_entry, entry )
+ {
+ if (pc >= entry->base && pc < entry->base + entry->size)
+ {
+ *base = entry->base;
+
+ /* lookup in function table or call callback in signal handler stack */
+ if (entry->callback)
+ func = entry->callback( pc, entry->context );
+ else
+ func = find_function_info( pc, (HMODULE)entry->base, entry->table, entry->table_size );
+ break;
+ }
+ }
+ RtlLeaveCriticalSection( &dynamic_unwind_section );
+ }
return func;
}
@@ -2528,7 +2577,29 @@ void signal_init_process(void)
*/
BOOLEAN CDECL RtlAddFunctionTable( RUNTIME_FUNCTION *table, DWORD count, DWORD64 addr )
{
- FIXME( "%p %u %lx: stub\n", table, count, addr );
+ struct dynamic_unwind_entry *entry;
+ DWORD size;
+
+ TRACE( "%p %u %lx\n", table, count, addr );
+
+ /* NOTE: Windows doesn't check if table is aligned or a NULL pointer */
+
+ size = table[count - 1].EndAddress;
+ entry = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*entry) );
+ if (!entry)
+ return FALSE;
+
+ entry->base = addr;
+ entry->size = size;
+ entry->table = table;
+ entry->table_size = count * sizeof(RUNTIME_FUNCTION);
+ entry->callback = NULL; /* unused */
+ entry->context = NULL; /* unused */
+
+ RtlEnterCriticalSection( &dynamic_unwind_section );
+ list_add_tail( &dynamic_unwind_list, &entry->entry );
+ RtlLeaveCriticalSection( &dynamic_unwind_section );
+
return TRUE;
}
@@ -2538,7 +2609,60 @@ BOOLEAN CDECL RtlAddFunctionTable( RUNTIME_FUNCTION *table, DWORD count, DWORD64
*/
BOOLEAN CDECL RtlDeleteFunctionTable( RUNTIME_FUNCTION *table )
{
- FIXME( "%p: stub\n", table );
+ struct dynamic_unwind_entry *entry, *old_entry = NULL;
+
+ TRACE( "%p\n", table );
+
+ RtlEnterCriticalSection( &dynamic_unwind_section );
+ LIST_FOR_EACH_ENTRY( entry, &dynamic_unwind_list, struct dynamic_unwind_entry, entry )
+ {
+ if (entry->table == table)
+ {
+ old_entry = entry;
+ list_remove( &entry->entry );
+ break;
+ }
+ }
+ RtlLeaveCriticalSection( &dynamic_unwind_section );
+
+ if (old_entry)
+ RtlFreeHeap( GetProcessHeap(), 0, old_entry );
+
+ return (old_entry != NULL);
+}
+
+
+/**********************************************************************
+ * RtlInstallFunctionTableCallback (NTDLL.@)
+ */
+BOOLEAN CDECL RtlInstallFunctionTableCallback( DWORD64 table, DWORD64 base, DWORD length,
+ PGET_RUNTIME_FUNCTION_CALLBACK callback, PVOID context, PCWSTR dll )
+{
+ struct dynamic_unwind_entry *entry;
+
+ TRACE( "%lx %lx %d %p %p %s\n", table, base, length, callback, context, wine_dbgstr_w(dll) );
+
+ /* NOTE: Windows doesn't check if the provided callback is a NULL pointer */
+
+ /* both low-order bits must be set */
+ if ((table & 0x3) != 0x3)
+ return FALSE;
+
+ entry = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*entry) );
+ if (!entry)
+ return FALSE;
+
+ entry->base = base;
+ entry->size = length;
+ entry->table = (RUNTIME_FUNCTION *)table;
+ entry->table_size = 0; /* unused */
+ entry->callback = callback;
+ entry->context = context;
+
+ RtlEnterCriticalSection( &dynamic_unwind_section );
+ list_add_tail( &dynamic_unwind_list, &entry->entry );
+ RtlLeaveCriticalSection( &dynamic_unwind_section );
+
return TRUE;
}
diff --git a/include/winnt.h b/include/winnt.h
index 93fd70a..3f33c6b 100644
--- a/include/winnt.h
+++ b/include/winnt.h
@@ -1193,8 +1193,11 @@ typedef struct _KNONVOLATILE_CONTEXT_POINTERS
} DUMMYUNIONNAME2;
} KNONVOLATILE_CONTEXT_POINTERS, *PKNONVOLATILE_CONTEXT_POINTERS;
+typedef PRUNTIME_FUNCTION (CALLBACK *PGET_RUNTIME_FUNCTION_CALLBACK)(DWORD64,PVOID);
+
BOOLEAN CDECL RtlAddFunctionTable(RUNTIME_FUNCTION*,DWORD,DWORD64);
BOOLEAN CDECL RtlDeleteFunctionTable(RUNTIME_FUNCTION*);
+BOOLEAN CDECL RtlInstallFunctionTableCallback(DWORD64,DWORD64,DWORD,PGET_RUNTIME_FUNCTION_CALLBACK,PVOID,PCWSTR);
PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry(DWORD64,DWORD64*,UNWIND_HISTORY_TABLE*);
PVOID WINAPI RtlVirtualUnwind(ULONG,ULONG64,ULONG64,RUNTIME_FUNCTION*,CONTEXT*,PVOID*,ULONG64*,KNONVOLATILE_CONTEXT_POINTERS*);
--
1.7.9.5

View File

@@ -0,0 +1,177 @@
From fe1571d281c60aa9a1db503c8d143ac5029982c2 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Sat, 5 Apr 2014 01:04:25 +0200
Subject: ntdll/tests: Add tests for dynamic unwind table.
---
dlls/ntdll/tests/exception.c | 133 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 133 insertions(+)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c
index b4cbaf5..ac70802 100644
--- a/dlls/ntdll/tests/exception.c
+++ b/dlls/ntdll/tests/exception.c
@@ -49,6 +49,10 @@ static NTSTATUS (WINAPI *pNtReadVirtualMemory)(HANDLE, const void*, void*, SIZE
static NTSTATUS (WINAPI *pNtTerminateProcess)(HANDLE handle, LONG exit_code);
static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
static NTSTATUS (WINAPI *pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG);
+static BOOLEAN (WINAPI *pRtlAddFunctionTable)(RUNTIME_FUNCTION*, DWORD, DWORD64);
+static BOOLEAN (WINAPI *pRtlDeleteFunctionTable)(RUNTIME_FUNCTION*);
+static BOOLEAN (WINAPI *pRtlInstallFunctionTableCallback)(DWORD64, DWORD64, DWORD, PGET_RUNTIME_FUNCTION_CALLBACK, PVOID, PCWSTR);
+static PRUNTIME_FUNCTION (WINAPI *pRtlLookupFunctionEntry)(ULONG64, ULONG64*, UNWIND_HISTORY_TABLE*);
static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
#ifdef __i386__
@@ -1447,6 +1451,122 @@ static void test_virtual_unwind(void)
call_virtual_unwind( i, &tests[i] );
}
+static RUNTIME_FUNCTION* CALLBACK function_table_callback( DWORD64 pc, PVOID context )
+{
+ static const int code_offset = 1024;
+ static RUNTIME_FUNCTION runtime_func;
+ (*(DWORD *)context)++;
+
+ runtime_func.BeginAddress = code_offset;
+ runtime_func.EndAddress = code_offset + 16;
+ runtime_func.UnwindData = 0;
+ return &runtime_func;
+}
+
+static void test_dynamic_unwind(void)
+{
+ static const int code_offset = 1024;
+ char buf[sizeof(RUNTIME_FUNCTION) + 4];
+ RUNTIME_FUNCTION *runtime_func, *func;
+ ULONG_PTR table, base;
+ DWORD count;
+
+ /* Aligned RUNTIME_FUNCTION pointer */
+ runtime_func = (RUNTIME_FUNCTION *)buf;
+ runtime_func->BeginAddress = code_offset;
+ runtime_func->EndAddress = code_offset + 16;
+ runtime_func->UnwindData = 0;
+ ok( pRtlAddFunctionTable( runtime_func, 1, (ULONG_PTR)code_mem ),
+ "RtlAddFunctionTable failed for runtime_func = %p (aligned)\n", runtime_func );
+
+ /* Pointer outside of the area */
+ base = 0xdeadbeef;
+ func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 16, &base, NULL );
+ ok( func == NULL,
+ "RtlLookupFunctionEntry returned unexpected function, expected: NULL, got: %p\n", func );
+ ok( base == 0xdeadbeef,
+ "RtlLookupFunctionEntry modified base address, expected: 0xdeadbeef, got: %lx\n", base );
+
+ /* Pointer inside of a function */
+ base = 0xdeadbeef;
+ func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 8, &base, NULL );
+ ok( func == runtime_func,
+ "RtlLookupFunctionEntry didn't return expected function, expected: %p, got: %p\n", runtime_func, func );
+ ok( base == (ULONG_PTR)code_mem,
+ "RtlLookupFunctionEntry returned invalid base, expected: %lx, got: %lx\n", (ULONG_PTR)code_mem, base );
+
+ /* Ensure that deleting is also successful */
+ ok( pRtlDeleteFunctionTable( runtime_func ),
+ "RtlDeleteFunctionTable failed for runtime_func = %p (aligned)\n", runtime_func );
+ ok( !pRtlDeleteFunctionTable( runtime_func ),
+ "RtlDeleteFunctionTable returned success for nonexistent table runtime_func = %p\n", runtime_func );
+
+ /* Unaligned RUNTIME_FUNCTION pointer */
+ runtime_func = (RUNTIME_FUNCTION *)((ULONG_PTR)buf | 0x3);
+ runtime_func->BeginAddress = code_offset;
+ runtime_func->EndAddress = code_offset + 16;
+ runtime_func->UnwindData = 0;
+ ok( pRtlAddFunctionTable( runtime_func, 1, (ULONG_PTR)code_mem ),
+ "RtlAddFunctionTable failed for runtime_func = %p (unaligned)\n", runtime_func );
+ ok( pRtlDeleteFunctionTable( runtime_func ),
+ "RtlDeleteFunctionTable failed for runtime_func = %p (unaligned)\n", runtime_func );
+
+ /* Attempt to insert the same entry twice */
+ runtime_func = (RUNTIME_FUNCTION *)buf;
+ runtime_func->BeginAddress = code_offset;
+ runtime_func->EndAddress = code_offset + 16;
+ runtime_func->UnwindData = 0;
+ ok( pRtlAddFunctionTable( runtime_func, 1, (ULONG_PTR)code_mem ),
+ "RtlAddFunctionTable failed for runtime_func = %p (first attempt)\n", runtime_func );
+ ok( pRtlAddFunctionTable( runtime_func, 1, (ULONG_PTR)code_mem ),
+ "RtlAddFunctionTable failed for runtime_func = %p (second attempt)\n", runtime_func );
+ ok( pRtlDeleteFunctionTable( runtime_func ),
+ "RtlDeleteFunctionTable failed for runtime_func = %p (first attempt)\n", runtime_func );
+ ok( pRtlDeleteFunctionTable( runtime_func ),
+ "RtlDeleteFunctionTable failed for runtime_func = %p (second attempt)\n", runtime_func );
+ ok( !pRtlDeleteFunctionTable( runtime_func ),
+ "RtlDeleteFunctionTable returned success for nonexistent table runtime_func = %p\n", runtime_func );
+
+ /* Table without both low bits set */
+ table = (ULONG_PTR)code_mem;
+ ok( !pRtlInstallFunctionTableCallback( table, (ULONG_PTR)code_mem, code_offset + 16, &function_table_callback, (PVOID*)&count, NULL ),
+ "RtlInstallFunctionTableCallback returned success for table = %lx\n", table );
+
+ /* Table with both low bits set */
+ table = (ULONG_PTR)code_mem | 0x3;
+ ok( pRtlInstallFunctionTableCallback( table, (ULONG_PTR)code_mem, code_offset + 16, &function_table_callback, (PVOID*)&count, NULL ),
+ "RtlInstallFunctionTableCallback failed for table = %lx\n", table );
+
+ /* Pointer outside of the area */
+ count = 0;
+ base = 0xdeadbeef;
+ func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 16, &base, NULL );
+ ok( func == NULL,
+ "RtlLookupFunctionEntry returned unexpected function, expected: NULL, got: %p\n", func );
+ ok( base == 0xdeadbeef,
+ "RtlLookupFunctionEntry modified base address, expected: 0xdeadbeef, got: %lx\n", base );
+ ok( !count,
+ "RtlLookupFunctionEntry issued %d unexpected calls to function_table_callback\n", count );
+
+ /* Pointer inside of a function */
+ count = 0;
+ base = 0xdeadbeef;
+ func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 8, &base, NULL );
+ ok( func != NULL && func->BeginAddress == code_offset && func->EndAddress == code_offset + 16,
+ "RtlLookupFunctionEntry didn't return expected function, got: %p\n", func );
+ ok( base == (ULONG_PTR)code_mem,
+ "RtlLookupFunctionEntry returned invalid base, expected: %lx, got: %lx\n", (ULONG_PTR)code_mem, base );
+ ok( count == 1,
+ "RtlLookupFunctionEntry issued %d calls to function_table_callback, expected: 1\n", count );
+
+ /* Clean up again */
+ ok( pRtlDeleteFunctionTable( (PRUNTIME_FUNCTION)table ),
+ "RtlDeleteFunctionTable failed for table = %p\n", (PVOID)table );
+ ok( !pRtlDeleteFunctionTable( (PRUNTIME_FUNCTION)table ),
+ "RtlDeleteFunctionTable returned success for nonexistent table = %p\n", (PVOID)table );
+
+}
+
#endif /* __x86_64__ */
START_TEST(exception)
@@ -1473,6 +1593,14 @@ START_TEST(exception)
"NtQueryInformationProcess" );
pNtSetInformationProcess = (void*)GetProcAddress( hntdll,
"NtSetInformationProcess" );
+ pRtlAddFunctionTable = (void *)GetProcAddress( hntdll,
+ "RtlAddFunctionTable" );
+ pRtlDeleteFunctionTable = (void *)GetProcAddress( hntdll,
+ "RtlDeleteFunctionTable" );
+ pRtlInstallFunctionTableCallback = (void *)GetProcAddress( hntdll,
+ "RtlInstallFunctionTableCallback" );
+ pRtlLookupFunctionEntry = (void *)GetProcAddress( hntdll,
+ "RtlLookupFunctionEntry" );
pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process");
#ifdef __i386__
@@ -1537,6 +1665,11 @@ START_TEST(exception)
test_virtual_unwind();
+ if (pRtlAddFunctionTable && pRtlDeleteFunctionTable && pRtlInstallFunctionTableCallback && pRtlLookupFunctionEntry)
+ test_dynamic_unwind();
+ else
+ skip( "Rtl{Add,Delete}FunctionTable or RtlInstallFunctionTableCallback or RtlLookupFunctionEntry not found\n" );
+
#endif
VirtualFree(code_mem, 0, MEM_FREE);
--
1.7.9.5

Some files were not shown because too many files have changed in this diff Show More