You've already forked wine-staging
mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2025-04-13 14:42:51 -07:00
Compare commits
27 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
9fcd7e7113 | ||
|
903a8e54d4 | ||
|
3de6b17d8a | ||
|
74bd451363 | ||
|
22a1e1ff59 | ||
|
c781d177e1 | ||
|
f13c0f3cd8 | ||
|
9ebbbcfc9f | ||
|
d886426f50 | ||
|
d30bfe1a41 | ||
|
30825c59a9 | ||
|
7d03df647f | ||
|
a046f03792 | ||
|
b744f3d37b | ||
|
c52df465c1 | ||
|
09bfdcb009 | ||
|
2f449562d1 | ||
|
3c6c730333 | ||
|
809ee539f3 | ||
|
339892ffe6 | ||
|
2e7f83fbf8 | ||
|
9043eadbcb | ||
|
5386c7843d | ||
|
0675620019 | ||
|
552b6acf97 | ||
|
86c9842e64 | ||
|
d0e9447fb6 |
14
debian/changelog
vendored
14
debian/changelog
vendored
@@ -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
172
debian/control
vendored
@@ -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
154
debian/rules
vendored
@@ -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
|
||||
|
2
debian/tools/generate-patchlist.sh
vendored
2
debian/tools/generate-patchlist.sh
vendored
@@ -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
4
debian/wine-compholio-amd64.install
vendored
Normal 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
1
debian/wine-compholio-dev.install
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/opt/wine-compholio/include
|
4
debian/wine-compholio-i386.install
vendored
Normal file
4
debian/wine-compholio-i386.install
vendored
Normal 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
4
debian/wine-compholio.docs
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
documentation/README.*
|
||||
ANNOUNCE
|
||||
AUTHORS
|
||||
README
|
2
debian/wine-compholio.install
vendored
Normal file
2
debian/wine-compholio.install
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/opt/wine-compholio/bin
|
||||
/opt/wine-compholio/share
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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();
|
@@ -1,3 +1,3 @@
|
||||
Revision: 1
|
||||
Revision: 2
|
||||
Author: Erich E. Hoover
|
||||
Title: Implement SIO_ADDRESS_LIST_CHANGE.
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
Reference in New Issue
Block a user