1. Motivation - DSpace at ICSY

Werbung
Inhaltsverzeichnis
1.
2.
3
4.
Motivation ................................................................................................................... 2
Überblick..................................................................................................................... 2
TracePlus/Winsock2 ................................................................................................... 4
Grundlagen .................................................................................................................. 5
4.1
Dynamic Link Libraries ...................................................................................... 5
4.1.1
Allgemeines über DLLs .............................................................................. 5
4.1.2
Vorteile von DLLs ...................................................................................... 6
4.1.3
Exportieren von Funktionen aus einer DLL ............................................... 6
4.1.4
Implizites und Explizites Linken ................................................................ 8
4.1.5
Suchpfad nach einer DLL ......................................................................... 10
4.1.6 „Memory Sharing“ zwischen DLLs................................................................. 10
4.2
Architektur der Winsock2-API ......................................................................... 11
4.2.1
Unterstützung mehrerer Protokoll-Familien ............................................. 11
4.2.2
Kompatibilität mit Winsock1.1 Applikationen ......................................... 12
4.2.3
Befehle für die Datenkommunikation ....................................................... 13
4.2.4
Blockierende und nicht-blockierende Funktionen .................................... 14
5. Entwicklung .............................................................................................................. 14
5.1
Erster Ansatz: Implementierung einer neuen Winsock2-DLL ......................... 14
5.1.1
Automatisches Erzeugen des Codes ......................................................... 19
5.1.2
Implementierungsaspekte ......................................................................... 20
5.1.3
Installation................................................................................................. 20
5.2
Zweiter Ansatz: Die „Debug/Trace Version“ der Winsock2-DLL................... 21
5.2.1
Architektur der „Debug/Trace Version“ der Winsock2-DLL .................. 21
5.2.2
WSAPreApiNotify und WSAPostApiNotify............................................ 22
5.2.3
Implementierung ....................................................................................... 24
5.3
Zusammenfassung beider Ansätze .................................................................... 27
6. Daten erfassen und visualisieren ............................................................................... 27
6.1
Winsock2-API-Monitor .................................................................................... 27
6.2
Performance Monitor ........................................................................................ 28
6.3
LOG-Datei ........................................................................................................ 28
6.3.1
Ausgabe der LOG-Dateien ....................................................................... 29
6.3.2
Performance Factor ................................................................................... 30
6.3.3
Übersetzung der LOG-Datei ..................................................................... 30
7. Installation................................................................................................................. 33
8. Konfigurationsprogramm .......................................................................................... 33
9. Zusammenfassung und Ausblick .............................................................................. 36
Literaturverzeichnis .......................................................................................................... 38
-1-
1. Motivation
Netzwerktechnologien und Kommunikationsprotokolle ermöglichen dem Nutzer bzw.
den Applikationen verschiedene Dienste zu nutzen. ATM-Netzwerke bieten z.B. die
Möglichkeit, für jede einzelne Verbindung einen QoS auszuhandeln.
Soll diese Möglichkeit genutzt werden, dann müssen detaillierte Informationen über
Kommunikationsanforderungen der Applikation an die unteren Netzwerkschichten
vorliegen. Dazu gehört zum einen der Bandbreitenbedarf einer Applikation, z.B.
Häufigkeit, Dauer, oder dauerhaft genutzte Bandbreite. Zum anderen gehören dazu
Anforderungen an die Übertragungsqualität, z.B. Verzögerung, Verzögerungsschwankungen oder durchschnittliche Datenverlustraten.
Die Anwendungen im Bereich der Internetkommunikation variieren zwischen einfachem
Datenaustausch und komplexen interaktiven Multimedia-Applikationen. Demnach stellen
die Applikationen unterschiedliche Anforderungen an die Netzwerkschnittstelle.
Es gibt viele Programme, die es erlauben, den Datenaustausch auf unteren Ebenen zu
kontrollieren. Die so genannten „Sniffer“ erlauben es, den Datenverkehr auf dem
Ethernet, was dem Layer 2 des ISO/OSI-Modells entspricht, zu beobachten. Andere
Programme sind in der Lage, Statistiken über die IP-Pakete (Layer 3) bzw. TCP- oder
UDP-Pakete (Layer 4) zu erstellen. Mit diesen Programmen kann man allerdings keine
Aussagen über die Anforderungen einer Applikation und ihr Verhalten an der API
(Application Programmer Interface) treffen.
2. Überblick
In dieser Arbeit wird ein Tool entwickelt, das die Analyse des Verhaltens der
Applikationen an der API-Schnittstelle ermöglicht. Das Tool erfasst die Aufrufe von
Netzwerkfunktionen mit ihren Parametern, z.B. die Paketgröße beim Senden und
Empfangen.
Zuerst wird mit „TracePlus®/Winsock" ein kommerzielles Tool vorgestellt, das diese
Aufgabe erfüllt. Die Vor- und Nachteile von TracePlus werden beschrieben.
Danach wird ein eigenes Tool entwickelt. Es werden zum Teil die Parameter, mit denen
die Netzwerkfunktionen aufgerufen werden, protokolliert. Es werden Zeitstempel
geschrieben, damit eine genauere Analyse der QoS-Anforderungen der Applikationen
möglich wird.
Das Tool wird auf der Plattform Windows2000 entwickelt. Die API ist Winsock2, die in
der DLL (Dynamic Link Library) Ws2_32.dll realisiert ist. Bevor die Entwicklung des
Tools beschrieben wird, werden einige Grundlagen über DLLs und über die Winsock2API vorgestellt.
Die Entwicklung des Tools selbst gliedert sich in zwei Schritte:
-2-

Der erste Schritt ist die Erfassung der Funktionsaufrufe der Winsock2-API mit ihren
Parametern. Hier soll ein Verfahren implementiert werden, welches den Zugriff auf
die Schnittstelle zwischen den Applikationen und der Winsock2-API ermöglicht
(siehe Abb.1). Zwei Verfahren werden vorgestellt:
a) Im ersten Verfahren wird eine neue Winsock2-DLL implementiert, welche die
alte DLL ersetzt.
b) Im zweiten Verfahren wird eine spezielle Version der Winsock2-DLL
verwendet: die so genannte „Debug/Trace Version“. Es wird eine Dt_DLL (Dt
steht für Debug/Trace) geschrieben, mit der die Winsock2-DLL kommuniziert.

Der zweite Schritt ist die Visualisierung der Funktionsaufrufe mit ihren Parametern.
Hier werden drei Verfahren diskutiert:
a) Anzeigen der Funktionsaufrufe durch einen Winsock2-API-Monitor
b) Visualisieren der Funktionsaufrufe mit dem Performance Monitor
(PerfMon.exe).
c) Protokollieren der relevanten Daten in einer LOG-Datei und Visualisieren
dieser Daten nachträglich, z.B. in Excel-Diagrammen
Applikation
API
Messung
Winsock2
Abb.1: Vereinfachte Beschreibung des Winsock2-API-Monitoring
Anschließend wird jeweils ein Verfahren ausgewählt und ein Einblick in die Auswertung
gemacht.
-3-
3. TracePlus®/Winsock
TracePlus ist ein Tool, das in der Lage ist, Prozesse zu starten und die Winsock2-APIAufrufe auf einem Monitor anzuzeigen oder in einer Datei zu speichern. Abb. 2 zeigt,
wie TracePlus den Internet Explorer startet und die Winsock2-API-Aufrufe anzeigt.
Abb.2: „API View“ von TracePlus mit dem Internet Explorer.
Bei einem gestarteten Prozess verfügt TracePlus über vier verschiedene Fenster: „API
View“, „Data View“, „Socket View“ und „Packet Statistics“.




„API View“ zeigt die Aufrufe der Winsock2-Funktionen mit ihren Parametern
und mit Zeitstempeln an.
„Data View“ stellt den Inhalt der gesendeten bzw. empfangenen Pakete dar. Eine
Unterscheidung zwischen ASCII- und hexadezimalen Daten ist möglich.
„Socket View“ verfolgt die Änderung des Zustands eines Sockets während seines
Lebenszyklus (Allocated, Bound, Connected, Closed, Blocking, Not Blocking).
„Packet Statistics“ zeigt weitere Informationen über die gesendeten und
empfangenen Pakete an: Paketgröße, Sende- bzw. Empfangszeitpunkt und
Zeitspanne beim Senden oder Empfangen mit einer Genauigkeit von
Millisekunden.
Eine Demo-Version von TracePlus kann unter http://www.sstinc.com/ herunter geladen
werden. Dieses Programm ist gut geeignet, um einige Internetanwendungen zu
„debuggen“ oder Erkenntnisse über bestehende Anwendungen zu gewinnen. Man kann
-4-
z.B. genaue Informationen über das HTTP-Protokoll erhalten, wenn man TracePlus mit
einem Internet Browser startet.
Doch für zeitkritische Anwendungen wie „Voice Over IP“ oder Multimediaanwendungen
hilft uns TracePlus nicht weiter: Die Genauigkeit der Zeitangaben in Millisekunden ist zu
grob. Innerhalb einer Millisekunde können mehrere Funktionen aus der Winsock2-API
aufgerufen werden, insbesondere kann mehrmals gesendet und empfangen werden.
Außerdem zeigt der Test von TracePlus enttäuschende Ergebnisse:


TracePlus stürzt einfach ab, wenn es zusammen mit der „Voice Over IP“ –
Anwendung „HiNet Xpress“ gestartet wird.
Bei „Netmeeting“ ist TracePlus nicht in der Lage, die Funktionsaufrufe der
Winsock2 zu verfolgen. Das Tool liefert einfach gar keine Ausgaben.
Dadurch zeigt sich, dass TracePlus für unsere Anforderungen nicht geeignet ist.
Multimedia-Anwendungen sind ein wichtiges Gebiet, in dem die Analyse der
Anforderung einer Applikation an der API-Schnittstelle von Bedeutung ist. Der Inhalt der
gesendeten und empfangenen Daten ist nicht relevant, denn es handelt sich meistens nicht
um ASCII-Daten.
Deshalb wurde in dieser Arbeit auf dieses kommerzielle Tool verzichtet und ein eigenes
Programm entwickelt.
4. Grundlagen
In diesem Abschnitt werden Grundlagen über DLLs (Dynamic Link Libraries) und über
die Winsock2-API vorgestellt, die für das Verständnis dieser Arbeit erforderlich sind.
4.1 Dynamic Link Libraries
Hier werden DLLs definiert und ihre Charakteristika vorgestellt.
4.1.1 Allgemeines über DLLs
DLLs sind Module, die Funktionen enthalten, welche von anderen Modulen aufgerufen
werden können. Eine DLL wird zur Laufzeit durch ein anderes Modul (eine ausführbare
EXE-Datei oder eine andere DLL) geladen. Eine Instanz der DLL mit den zugehörigen
Variablen wird an den Speicherbereich, der für den laufenden Prozess reserviert ist,
angehängt.
DLLs können zwei Arten von Funktionen definieren: externe und interne Funktionen.
Externe Funktionen können von anderen Modulen aufgerufen werden. Interne
Funktionen können nur innerhalb der DLL selbst verwendet werden.
-5-
4.1.2 Vorteile von DLLs
Es gibt mehrere Gründe, DLLs einzusetzen:



Erstens lässt sich die Größe der ausführbaren Anwendungsdateien verringern, indem
man die von mehreren Anwendungen gemeinsam genutzte Funktionalität in DLLs
unterbringt.
Zweitens kann der Code der DLLs aktualisiert und modifiziert werden, ohne die
ausführbare Anwendung neu kompilieren zu müssen. Man kann sogar neue
Funktionen implementieren und exportieren, die neuen Anwendungen bereitgestellt
werden, ohne dabei alte Anwendungen zu beeinflussen.
Schließlich kann man DLLs mit nahezu jeder anderen Programmiersprache unter
Windows verwenden.
Die Win32-API ist als Sammlung von DLLs implementiert. Die Winsock2-API ist z.B. in
der Datei Ws2_32.dll implementiert.
In den nächsten zwei Abschnitten wird beschrieben, wie man Funktionen aus einer DLL
exportieren und in ein Modul importieren kann.
4.1.3 Exportieren von Funktionen aus einer DLL
Eine DLL ist ähnlich aufgebaut wie eine ausführbare Datei, allerdings gibt es zwei
entscheidende Unterschiede:


Eine DLL ist allein nicht ausführbar.
Eine DLL besitzt eine Export-Tabelle.
In der Export-Tabelle stehen die Namen der Funktionen, die von der DLL exportiert
werden. Die Export-Tabelle einer DLL kann man sich mit dem DOS-Befehl DUMPBIN
oder mit dem Programm „Dependency Walker“1 anschauen.
Als Beispiel betrachten wir hier eine einfache DLL, die zwei Funktionen exportiert:
gimme_a_string1 und gimme_a_string2.
1
Ein Tool von Visual C++
-6-
const char * gimme_a_string1(void)
{
return "Hello ";
}
const char * gimme_a_string2(void)
{
return "World\n";
Listing 4.1: Implementierung von gimme_a_string1 und gimme_a_string2.
Diese zwei Funktionen sollen in einer ausführbaren Datei wie folgt aufgerufen werden:
printf(gimme_a_string1());
printf(gimme_a_string2());
Listing 4.2: Aufruf von gimme_a_string1 und gimme_a_string2.
Damit wird die gesamte Ausgabe „Hello World“.
Es gibt zwei Methoden, eine Funktion aus einer DLL zu exportieren:


Mit dem Schlüsselwort __declspec(dllexport) (siehe Listing 4.3)
Mit einer DEF-Datei, die verwendet wird, um die Export-Tabelle zu definieren.
(siehe Listing 4.4).
………..
__declspec(dllexport) const char * gimme_a_string1(void);
__declspec(dllexport) const char * gimme_a_string2(void);
………..
Listing 4.3: Exportieren mit __declspec(dllexport)
LIBRARY STR_DLL
DESCRIPTION "a sample for using DLLs"
; Here goes explicit function export
EXPORTS
gimme_a_string1
gimme_a_string2
Listing 4.4: Exportieren mit einer DEF-Datei.
Die Interpretation einer DEF-Datei durch den Linker bietet auch einige Freiheiten: Es
gibt z.B. die Möglichkeit, eine Funktion mit einem anderen Namen zu exportieren als der
Name, mit dem sie in dem Code der DLL definiert wird; z.B.:
-7-
EXPORTS
string1 = gimme_a_string1
string2 = gimme_a_string2
Listing 4.5: Exportieren mit anderen Namen.
Diese beiden Funktionen werden im Code mit gimme_a_string1 und gimme_a_string2
definiert und sind nach außen nur mit string1 bzw. string2 sichtbar.
Es besteht auch die Möglichkeit, Funktionen aus anderen DLLs zu exportieren; z.B.:
EXPORTS
gimme_a_string1
gimme_a_string2=Proxy_Dll.gimme_a_string2
Listing 4.6: Exportieren aus anderen DLLs.
In diesem Beispiel wird die Funktion gimmme_a_string2 exportiert, die in Proxy_Dll.dll
implementiert ist. Wenn die Implementierung der Funktion gimme_a_string2 in der
Proxy_Dll wie folgt aussieht,
const char * gimme_a_string2(void)
{
return "Bob\n";
}
Listing 4.7: Implementierung von gimme_a_string2 in Proxy_Dll.
dann ist die gesamte Ausgabe des Programms “Hello Bob” und nicht “Hello World“. In
diesem Fall muss die Datei STR_DLL.dll mit der Proxy_DLL.lib durch den Linker
verknüpft werden.
4.1.4 Implizites und Explizites Linken
Das übliche Verfahren, eine Funktion in ein Modul zu importieren, besteht darin, die
Funktion mit dem Schlüsselwort __declspec(dllimport) in dem Code des Moduls zu
deklarieren.
………..
__declspec(dllimport) const char * gimme_a_string1(void);
__declspec(dllimport) const char * gimme_a_string2(void);
………..
Listing 4.8: Importieren mit __declspec(dllimport).
Wenn man mit dem Entwicklungstool Visual C++ eine DLL erzeugt, wird eine HeaderDatei erzeugt, die sowohl für die DLL als auch für die Module, welche diese DLL
-8-
verwenden, benutzt werden kann. Mit dem Makro STR_DLL_EXPORTS kann man den
Fall jeweils unterscheiden. Dieses Makro wird in der DLL von Visual C++ automatisch
definiert.2
#ifdef STR_DLL_EXPORTS
#define STR_DLL_API __declspec(dllexport)
#else
#define STR_DLL_API __declspec(dllimport)
#endif
Listing 4.9: Abkürzung von __declspec(dllimport) und __declspec(dllexport) mit Hilfe eines Makros.
Beim Kompilieren der DLL wird zusätzlich zu der Datei STR_DLL.dll eine Datei
STR_DLL.lib erzeugt. Module, die Funktionen aus der DLL benutzen sollen, müssen mit
dieser LIB-Datei durch den Linker verknüpft werden, damit die Bezeichnungen
gimme_a_string1 und gimme_a_string2 im Programmcode aufgeschlüsselt werden
können. Die Funktionen gimme_a_string1 und gimme_a_string2 können so aufgerufen
werden, als ob sie in demselben Modul definiert wären. Dieses Verfahren heißt
„Implizites Linken“.
Doch es gibt ein zweites Verfahren, eine DLL zur Laufzeit zu linken: Die DLL wird
explizit mit dem Befehl „LoadLibrary” geladen. Die Funktionen werden mit dem Befehl
„GetProcAddress“ gesucht und können über einen „Pointer to function“ ausgeführt
werden.
………..
typedef const char* (*LPFN_GIMME_A_STRING)(void);
// declare type pointer to function
………..
HINSTANCE hDLL;
// handle to DLL
LPFN_GIMME_A_STRING
lpfn_gimme_a_string1; // declare function pointer
LPFN_GIMME_A_STRING
lpfn_gimme_a_string2; // declare function pointer
………..
hDLL = LoadLibrary("STR_DLL");
.............
lpfn_gimme_a_string1 =
(LPFN_GIMME_A_STRING)GetProcAddress(hDLL,"gimme_a_string1");
.............
lpfn_gimme_a_string2 =
(LPFN_GIMME_A_STRING)GetProcAddress(hDLL,"gimme_a_string2");
..............
printf(lpfn_gimme_a_string1());
printf(lpfn_gimme_a_string2());
………..
Listing 4.10: Explizites Linken.
2
Wähle das Projekt der DLL aus; gehe auf dem Menü Project/Settings und dann auf der Seite C/C++ sieht man bei
Preprocessor definitions die vordefinierten Makros.
-9-
4.1.5 Suchpfad nach einer DLL
Wenn eine DLL geladen werden soll, muss das Betriebssystem die DLL finden. Der
Suchpfad der DLL ist wie folgt aufgebaut: Die DLL wird zunächst im Verzeichnis
gesucht, in dem sich die ausführbare Datei befindet. Falls die Suche erfolglos war, wird
in einem durch die globale Variable PATH definierten Pfad gesucht. Der Pfad kann mit
dem DOS-Befehl PATH gelesen und verändert werden. Wenn die DLL nicht gefunden
wird, gibt es eine Fehlermeldung vom Betriebssystem. Bei manchen DLLs, die durch das
Betriebssystem selbst verwendet werden, (z.B. die Ws2_32.dll) kann das System gar
nicht gestartet werden!
4.1.6 „Memory Sharing“ zwischen DLLs
Der entscheidende Vorteil der DLLs ist, dass mehrere Prozesse sich ein Code-Segment
teilen. Das Code-Segment wird geteilt, aber jeder Prozess besitzt sein eigenes DatenSegment; d.h. wenn n Prozesse eine DLL laden, dann gibt es n Instanzen der DLL und
ein einziges Segment für den Code.
Wenn das Betriebssystem eine DLL lädt, die von einem Prozess benötigt wird, dann wird
eine Instanz dieser DLL am Speicherbereich des Prozesses angehängt. Dieser Bereich
wird vom Betriebssystem streng eingegrenzt und von anderen Prozessen getrennt.
Doch es gibt einen Mechanismus, mit dem mehrere Prozesse auf die gleichen Daten
parallel zugreifen können. Das von [24] übernommene Listing 4.10 beschreibt, wie die
Daten in der DLL deklariert werden müssen, damit sie nicht bei jedem Prozess neu
initialisiert werden und von allen Prozessen, die diese DLL laden, geteilt werden.
// Global and static member variables that are not shared.
...
#pragma data_seg("SHARED") // Begin the shared data segment.
// Define simple variables
// Integers, char[] arrays and pointers
// Do not define classes that require 'deep' copy constructors.
#pragma data_seg()
// End the shared data segment and default back to
// the normal data segment behavior.
// tell to the linker that there variables have to be shared with other processes.
#pragma comment(linker, "/section:SHARED,RWS")
Listing 4.11: „Memory Sharing“ zwischen DLLs.
Der Zugriff auf die gemeinsamen Daten sollte mit einer „Critical Section“ synchronisiert
werden.
- 10 -
4.2 Architektur der Winsock2-API
In diesem Abschnitt werden die neuen Konzepte, welche die Winsock2 enthält,
beschrieben. Unter anderem wird hier die Unterstützung anderer Protokoll-Familien
außer TCP/IP hervorgehoben.
4.2.1 Unterstützung mehrerer Protokoll-Familien
Im Gegensatz zu der Winsock1.1 unterstützt die Winsock2 mehrere Protokoll-Familien
und nicht nur die Protokolle der TCP/IP-Suite. Die Schnittstelle zwischen der WinsockDLL und dem unterliegenden Protokoll-Stack ist bei Winsock1.1 nur für TCP/IP geeignet.
Winsock2 bietet eine einheitliche Schnittstelle (SPI) für alle „Transport Service
Provider“ und „Name Service Provider“. Die Einführung eines neuen Service Providers
erfordert nicht die Implementierung einer neuen Ws2_32.dll sondern nur die Anpassung
an die SPI-Schnittstelle. Abb. 2 ist von der MSDN-Library übernommen und zeigt die
Architektur der Winsock2 mit beiden API- und SPI-Schnittstellen. Die Winsock2-DLL
ist ein Interface zwischen den Applikationen und den Service Providern. In der Winsock2
selbst sind keine Protokolle implementiert.
Wenn eine Applikation ein Socket anlegen will, ruft sie die Funktion „socket“ mit dem
passenden Wert des Arguments „type“ auf.
SOCKET socket(int af, int type, int protocol );
Listing 4.12: Prototyp von socket. 3
Die gängigsten Socket-Typen sind TCP (type = 1) und UDP (type = 2).
Die Funktion „WSCEnumProtocols“ wird dann an der SPI-Schnittstelle aufgerufen, um
Informationen
über
die
installierten
Transportprotokolle
zu
finden.
„WSCEnumProtocols“ ist mit der API-Funktion „WSAEnumProtocols“ vergleichbar. Mit
„WSAEnumProtocols“ kann die Applikation selbst Informationen über die installierten
Protokolle herausfinden und eventuell dynamisch ein Transportprotokoll wählen.
3
SOCKET ist ein Makro für unsigned int. Ein „Socket Descriptor“ ist also ein unsigned int.
- 11 -
Abb.2: Unterstützung mehrerer Protokoll-Familien durch die Winsock2.
4.2.2 Kompatibilität mit Winsock1.1 Applikationen
Winsock2 unterstützt auch Applikationen, die mit Winsock1.1. entwickelt wurden. Mit
einer Kompatibilitätskomponente kann jede Applikation, die mit der Winsock1.1
ausführbar ist, an die Winsock2 zur Laufzeit angepasst werden.
Die Funktion „WSAStartUp“ wird beim Laden der Winsock2-DLL als erste aufgerufen.
In dieser Funktion wird ausgehandelt, welche Version der Winsock-DLL die Applikation
unterstützt und danach wird entschieden, ob die Winsock-Aufrufe durch die
Kompatibilitätskomponente gehen sollen.
- 12 -
Abb.3: Unterstützung von Winsock1.1-Applikationen durch die Winsock2.
4.2.3 Befehle für die Datenkommunikation
Der Datenverkehr läuft über Sockets. Die Sockets werden mit dem Befehl „socket“ oder
„WSASocket“ aufgebaut und mit „closesocket“ geschlossen. Bei Server-Applikationen
können mit dem Befehl „accept“ zusätzlich Sockets angelegt werden.
Die Datenkommunikation selbst geschieht mit send, sendto, recv, recvfrom, WSASend,
WSASendTo, WSARecv oder WSARecvFrom. Bei send, recv, sendto und recvfrom ist die
Paketgröße über dem Parameter len zu finden.
int send(SOCKET s, const char FAR *buf, int len, int flags);
Listing 4.13: Prototyp von send.
WSASend und die anderen Funktionen ermöglichen einer Applikation das Senden bzw.
Empfangen einer Menge von Datenpuffern, die in einem Array gespeichert wird. Damit
kann man das zweifache Kopieren der Daten vermeiden, welches bei einzelnen Aufrufen
von einfachen Send- und Receive-Befehlen entstehen würde.
- 13 -
int WSASend(
SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesSent,
DWORD dwFlags,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
Listing 4.14: Prototyp von WSASend.
lpBuffers ist das Array mit den Datenpuffern und lpNumberOfBytesSent ist ein Array mit
den jeweiligen Größen des Puffers. Für unsere Ziele betrachten wir die gesamte Menge
der Daten als ein Paket und rechnen die Summe der Puffergrößen zusammen.
4.2.4 Blockierende und nicht-blockierende Funktionen
Man kann unter den Netzwerkfunktionen zwischen zwei Kategorien unterscheiden:


Funktionen, die sofort beendet werden z.B. bind, getsockopt, getpeername,
Funktionen, die für ihre Ausführung eine unvorhersehbare Zeit brauchen, z.B.
recv.
Die Funktion recv blockiert den Prozess, bis Daten aus dem anderen Rechner ankommen.
Bei BSD-Sockets und früheren 16-Bit-Windows-Sockets1.1 muss eine solche
blockierende Funktion wie folgt behandelt werden.
Es wird in einer Schleife und in regelmäßigen Abständen geprüft, ob neue Daten im
Puffer angekommen sind. Falls ja, wird recv aufgerufen und die Schleife abgebrochen.
Somit wird der gesamte Prozess nicht blockiert und andere Threads können parallel zu
der Schleife weiter laufen.
5. Entwicklung
5.1 Erster Ansatz: Implementierung einer neuen Winsock2-DLL
Im Abschnitt 4.1 wurden einige Eigenschaften von DLLs aufgezählt. Wie schon erwähnt,
kann der Code einer DLL geändert werden, ohne die Applikationen, die diese DLL
benutzen, neu kompilieren zu müssen. D.h. wenn wir eine neue DLL namens Ws2_32.dll
schreiben und die „alte“ Winsock2 DLL zu Ws2_32Back.dll umbenennen, dann wird bei
Netzwerkanwendungen die neue DLL geladen.
In diesem Ansatz wird eine neue Winsock2-DLL implementiert, welche die gleichen
Funktionen exportiert wie die alte Winsock2. Diese Funktionen rufen selbst die gleichen
Funktionen aus der alten Winsock2-DLL auf und können dazwischen die
Funktionsaufrufe und ihre Parameter protokollieren. Abb. 4 veranschaulicht dieses
Verfahren.
- 14 -
4
1
Ws2_32.dll
2
I
Ws2_32Back.dll
II
3
Abb.4: Implementierung einer neuen Winsock2-DLL. Bsp. Die Funktion socket. (1) Eine Applikation
ruft die Funktion socket aus der neuen Winsock2. Die neue Winsock2 hat die Möglichkeit in (I)
Parameter und Zeitstempeln zu protokollieren. (2) Die neue Winsock2 ruft sie die Funktion socket aus
der alten Winsock2. (3) Die alte Winsock2 gibt einen „Socket Descriptor“ zurück. Die neue Winsock2
kann in (II) wieder protokollieren. (4) Die neue Winsock2 liefert den „Socket Descriptor“ zu der
Applikation zurück.
Innerhalb der Funktion „socket“ muss die ursprüngliche „socket“-Funktion von
Ws2_32Back aufgerufen werden. Die Bezeichnung der neuen Funktion ist __socket, um
eine Rekursion im Code zu vermeiden.
SOCKET __socket(int af, int type, int protocol){
…..
socket (int af, int type, int protocol)
…..
}
Listing 5.1: Implementierung von socket in der neune Winsock2-DLL.
Diese Bezeichnung __socket wird in der DEF-Datei maskiert:
EXPORTS
….
socket = __socket
….
Listing 5.2: Eintrag von socket in der DEF-Datei.
Doch damit socket innerhalb von __socket aufgerufen werden kann, muss socket
importiert werden und die LIB-Datei der alten Winsock2-DLL Ws2_32.lib muss mit der
neuen Winsock2-DLL durch den Linker verknüpft werden. Abb. 5 stellt diese Idee dar.
- 15 -
Ws2_32.lib
1
2
Ws2_32.dll
Ws2_32Back.dll
Export-Tabelle
Code
accept
__accept {...}
bind
__bind {...}
.......
.......
socket
__socket(...){
...
socket(...);
....
}
......
Export-Tabelle
accept
bind
.......
socket
Code
accept (...){....}
bind (...){....}
.......
socket(...){....}
......
....
....
Abb.5: Implementierung neuer Winsock2-Funktionen mit Hilfe von alten Funktionen. Beispiel: socket.
(1) Die alte Funktion socket wird innerhalb des Codes der neuen Funktion __socket aufgerufen. Das
Betriebssystem sucht in Ws2_32.lib, wie das Code-Segment der alten Funktion socket zu erreichen ist.
(2) Die Datei Ws2_32.lib soll darauf hinweisen, dass socket in Ws2_32Back implementiert ist und
einen „Pointer to function“ auf socket liefern.
Allerdings weist Ws2_32.lib darauf hin, dass die Funktion socket in der Datei Ws2_32.dll
ist, die jetzt Ws2_32Back.dll heißt. Abb. 6 zeigt, was bei dem Aufruf von socket
innerhalb von __socket tatsächlich geschieht.
Die LIB-Datei ist auch in Binärcode geschrieben, so dass eine effiziente kleine Änderung
nicht möglich ist.
- 16 -
Ws2_32.lib
1
2
Ws2_32.dll
Ws2_32Back.dll
Export-Tabelle
Code
accept
__accept {...}
bind
__bind {...}
.......
.......
socket
__socket(...){
...
socket(...);
....
}
......
Export-Tabelle
accept
bind
.......
socket
Code
accept (...){....}
bind (...){....}
.......
socket(...){....}
......
....
....
Abb.6: Implementierung neuer Winsock2-Funktionen mit Hilfe von alten Funktionen am Beispiel von
socket. (1) Die alte Funktion socket wird innerhalb des Codes der neuen Funktion __socket aufgerufen.
Das Betriebssystem sucht in Ws2_32.lib, wie das Code-Segment der alten Funktion socket zu erreichen
ist. (2) Die Datei Ws2_32.lib weist darauf hin, dass die Funktion socket in der Datei Ws2_32.dll
implementiert ist. Es ergibt sich eine Rekursion.
Die Datei Ws2_32.lib ist immer erforderlich, wenn Funktionen aus einer DLL implizit
importiert werden.
In dem Beispiel von Explizitem Linken im Abschnitt 4.1.4 scheint der Aufruf von
exportierten Funktionen umständlich zu sein. Doch hier eignet sich das explizite Linken
gut.
SOCKET socket( int af, int type, int protocol)
{
/* evtl. Parameter und Zeit Ausgabe */
…….
LPFN_SOCKET lpfn_socket = (LPFN_SOCKET)GetProcAddress(hDLL,"socket");
SOCKET rt = lpfn_socket( af, type, protocol);
/* evtl. noch mal Parameter und Zeit Ausgabe */
…....
return rt;
}
Listing 5.3: Implementierung von socket mit Explizitem Linken.
- 17 -
Dazu muss die Ws2_32Back.dll in der Dll_Main der neuen DLL geladen werden.
Dll_Main wird aufgerufen, wenn ein Prozess die DLL lädt und wenn der Prozess die
DLL freigibt (meistens wird die DLL erst freigegeben, wenn der Prozess beendet wird).
Dll_Main wird auch bei jedem Thread-Beginn und -Ende aufgerufen. Listing 5.4 zeigt
den Code von Dll_Main in der neuen Winsock2 DLL. Das Argument ul_reason_for_call
weist darauf hin, um welchem Fall es sich gerade handelt.
BOOL APIENTRY Dll_Main( HANDLE hModule, DWORD ul_reason_for_call, LPVOID
lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hDLL = LoadLibrary("Ws2_32Back");
if (!hDLL)
exit(-1);
/* weitere Initialisierungen */
……...
break;
case DLL_THREAD_ATTACH:
if(!hDLL)
{
hDLL = LoadLibrary("Ws2_32Back");
if (!hDLL)
exit(-1);
……...
}
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
FreeLibrary(hDLL);
……...
break;
}
return TRUE;
}
Listing 5.4: Implementierung von Dll_Main in der neuen Winsock2-DLL.
Die Funktionen werden mit einer DEF-Datei exportiert:
- 18 -
LIBRARY WS2_32
EXPORTS
; Here goes the explicit export declaration
accept
@1
bind
@2
…..
socket
@23
…..
WSACleanup @116
Listing 5.5: Die DEF-Datei der neuen Winsock2-DLL.
Die Zahlen, die in der rechten Spalte stehen, sind so genannte „Ordinals“. Hier werden
die Funktionen mit einer Ordnungszahl exportiert. In [6] wird das Exportieren von
Funktionen mit einer Ordnungszahl erklärt.
Aus Effizienzgründen werden auch alle „Pointer to function“ (lpfn_accept, lpfn_bind …)
als globale Variablen deklariert und einmalig in der DllMain berechnet. Eine grobe
Zeitmessung zeigt, dass die Berechnung aller dieser „Pointer to function“ weniger als
eine Millisekunde dauert. Dadurch wird die Applikation beim Laden der DLL nur
unbedeutend beeinflusst. Der Code einzelner Funktionen reduziert sich wie folgt.
SOCKET socket( int af, int type, int protocol)
{
/* evtl. Parameter und Zeit Ausgabe */
…….
SOCKET rt = lpfn_socket( af, type, protocol);
/* evtl. noch mal Parameter und Zeit Ausgabe */
…....
return rt;
}
Listing 5.6: Reduzierte Implementierung von socket in der neuen Winsock2-DLL.
5.1.1 Automatisches Erzeugen des Codes
Es ist nicht denkbar, den Code aller Funktionen per Hand zu schreiben, denn dies
beansprucht mühsame Arbeit und ist sehr fehleranfällig. Diese Vorgehensweise erschwert
jede Änderung oder Erweiterbarkeit des Codes.
Deshalb wird der Code mit einem Perl-Script automatisch erzeugt. Der Code der
Funktionen besitzt dieselbe Struktur. Die Funktionsprototypen werden aus den Dateien
winsock2.h und ws2spi.h ausgelesen und in einer Datenstruktur gespeichert.
Anschließend kann der Code aus dieser Datenstruktur automatisch erzeugt werden.
Einige kleine Änderungen werden zusätzlich von Hand gemacht.
- 19 -
5.1.2 Implementierungsaspekte
Bei der Entwicklung der Winsock2 wurden einige Aspekte festgestellt, die hier erläutert
werden.
Die Winsock2-DLL muss vollständig implementiert werden, bevor sie einsatzbereit ist.
Selbst einfache Client- oder Server-Applikationen, die nur wenige Funktionen aus der
BSD-Familie wie accept, socket, listen, send und recv anwenden, können nicht laufen,
wenn die Implementierung sich auf solche Funktionen beschränkt. Es gibt andere
Funktionen, die erforderlich sind, selbst wenn sie nicht explizit durch die Applikation
aufgerufen werden.
Die Funktion WSAStartup z.B. wird, wie im Abschnitt 4.2.1 schon erwähnt, immer als
erste aufgerufen. Sie bestimmt, auf welche Version der Winsock-DLL die Applikation
zugeschnitten ist, und setzt eventuell die Kompatibilitätskomponente ein. Keine weitere
Funktion aus der Winsock2-DLL kann aufrufen werden, wenn WSAStartup nicht
erfolgreich abgeschlossen wird (d.h. der Rückgabewert ist gleich Null).
Weitere Funktionen sind erforderlich, um Sockets anzulegen. Wird socket von einer
Applikation aufgerufen, so wird WSCEnumProtocols aufgerufen, um die erforderlichen
Informationen über die auf dem Rechner installierten Service Provider zu finden (siehe
Abschnitt 4.2.1). Der erste Service Provider, der die gewünschte Adressfamilie und den
Typ des Sockets unterstützt, wird verwendet.
Solange WSCEnumProtocols von der Winsock2-DLL nicht exportiert wird, können keine
Sockets angelegt werden und dadurch auch keine Daten ausgetauscht werden. Der
Rückgabewert von socket ist immer INVALID_SOCKET.
5.1.3 Installation
Nachdem die neue Winsock2-DLL mit verschiedenen Internetanwendungen erfolgreich
getestet wurde, kann sie im System installiert werden (siehe auch Abschnitt 7). Beim
Systemstart werden einige Prozesse gestartet, welche die Winsock2-DLL laden. Bei
Windows 2000 werden z.B. WinMgmt.exe, winlogon.exe, services.exe und weitere
Programme gestartet. Die neue Winsock2-DLL wurde von diesen Prozessen fehlerfrei
verwendet und das System ist erfolgreich gestartet. Dieser Schritt der Entwicklung hatte
eine besondere Bedeutung. Dadurch zeigte sich, dass die neue Winsock2-DLL die
gleiche Funktionalität erfüllen kann wie die ursprüngliche Winsock2-DLL.
Der bisher beschriebene Ansatz hat mit unseren Anforderungen übereingestimmt. Durch
seine Entwicklung wurden viele Erkenntnisse über DLLs allgemein und insbesondere
über die Winsock2-DLL gewonnen. Doch wir haben uns schließlich für einen anderen
Ansatz entschieden. Im nächsten Abschnitt werden der zweite Ansatz und seine Vorteile
vorgestellt.
- 20 -
5.2 Zweiter Ansatz: Die „Debug/Trace Version“ der Winsock2-DLL
Die „Microsoft Platform SDK“ bietet eine wenig bekannte Version der Winsock2-DLL.
Diese Version wird als „Debug/Trace Winsock2“ bezeichnet. Sie ist fast auf unsere
Anforderungen zugeschnitten. Sie wurde veröffentlicht mit dem Ziel, Entwicklern beim
„Debugging“ ihrer Internetanwendungen zu unterstützen.
Mit dieser DLL können die Entwickler die Funktionsaufrufe der Winsock2 nachvollziehen. Sie ermöglicht eine volle Kontrolle über die Parameter, mit denen diese
Funktionen aufgerufen werden, und über die jeweiligen Rückgabewerte. Diese Werte
können eventuell modifiziert werden. Ein Funktionsaufruf kann vorgetäuscht werden.
Diese DLL ermöglicht auch die Kontrolle über die Winsock2-Funktionsaufrufe durch
andere DLLs, in denen Service Provider implementiert sind. Mit anderen Worten: wir
haben nicht nur die Kontrolle über die API-Schnittstelle, sondern auch über die SPISchnittstelle.
Diese DLL soll Entwicklern dabei helfen, auftretende Probleme in der Applikation, in der
Winsock2 oder im Service Provider zu lokalisieren
5.2.1 Architektur der „Debug/Trace Version“ der Winsock2-DLL
Die „Debug/Trace Version“ der Winsock2-DLL kommuniziert mit einer zusätzlichen
DLL namens Dt_DLL (Dt steht für Debug/Trace). Die Schnittstelle zwischen beiden
Modulen ist durch zwei Funktionen definiert, welche von der Dt_Dll exportiert werden.
Diese Funktionen heißen WSAPreApiNotify und WSAPostApiNotify. Sie werden bei der
Ausführung einer Funktion aus der Winsock2-DLL am Anfang und am Ende aufgerufen.
Ruft eine Applikation eine beliebige Funktion aus der Winsock2-DLL, so ruft diese
Funktion selbst WSAPreApiNotify aus der Dt_DLL, bevor etwas anders ausgeführt wird.
Bei diesem Aufruf werden die Parameter mitgeliefert, mit denen die Winsock2-Funktion
aufgerufen wurde, sowie zusätzliche Informationen über diesen Aufruf. Wenn die
Ausführung der Winsock2-Funktion beendet ist, ruft sie als letztes WSAPostApiNotify auf.
WSAPreApiNotify und WSAPostApiNotify werden auch ausgeführt, wenn die Winsock2
selbst eine Funktion aus einem Service Provider aufruft. Die Aufrufe von
WSAPreApiNotify und WSAPostApiNotify bleiben für die Applikation unsichtbar.
Abb. 7 ist aus der Dokumentation der „Debug/Trace Version“ der Winsock2-DLL [25]
übernommen und erklärt die Interaktion zwischen der Winsock2-DLL und Dt_Dll bei der
Ausführung von connect.
Die Funktionen WSAPreApiNotify und WSAPostApiNotify werden mit GetProcAddress
gefunden. Falls sie nicht erreicht werden können, weil die Dt_Dll nicht gefunden wird
oder weil die Dt_DLL diese Funktionen nicht exportiert, so läuft die Ausführung der
jeweiligen Winsock2-Funktion ohne weiteres ab.
- 21 -
WinSock 2
DLL
8
dt_dll.dll
1
2
7
3
4
6
service provider
5
A typical execution path for WSAConnect involving the debug/trace layer is shown. (1)
A client application calls WSAConnect. The WinSock 2 DLL calls the
WSAPreApiNotify entry point in dt_dll.dll passing WSAConnect call information. The
dt_dll.dll decodes the call info and returns. (2) The WinSock 2 DLL proceeds until it is
about to call the provider. (3) The WinSock 2 DLL calls WSAPreApiNotify with
WSPConnect call information. The dt_dll.dll decodes the information and returns. (4)
The WinSock 2 DLL calls the service provider’s WSPConnect function, which (5)
performs the connect and returns.
(6) The WinSock 2 DLL calls WSAPostApiNotify with WSPConnect call information.
The dt_dll.dll decodes and returns. The WinSock 2 DLL completes its processing. (7)
the WinSock 2 DLL calls WSAPostApiNotify with WSAConnect call information. The
dt_dll.dll decodes and returns. (8) The WinSock 2 DLL returns the final result to the
application.
Abb.7: Typical execution through the debug/trace layer
5.2.2 WSAPreApiNotify und WSAPostApiNotify
Diese beiden Funktionen sind wie folgt definiert:
- 22 -
BOOL WINAPIV
WSAPreApiNotify(
IN INT NotificationCode,
OUT LPVOID ReturnCode,
IN LPSTR LibraryName,
...);
BOOL WINAPIV
WSAPostApiNotify(
IN INT NotificationCode,
OUT LPVOID ReturnCode,
IN LPSTR LibraryName,
...);
Listing 5.7: Die Prototypen von WSAPreApiNotify und WSAPostApiNotify.
NotificationCode ist eine Integer-Zahl, welche die gerade aufgerufene Winsock2Funktion kennzeichnet. Der Code der Winsock2-API- und -SPI-Funktionen ist in der
Header-Datei Dt_Dll.H definiert. Bei einer neueren Version der Winsock kann dieser
Code erweitert werden.
………..
#define DTCODE_accept
#define DTCODE_bind
#define DTCODE_closesocket
………..
#define DTCODE_socket
………..
1
2
3
21
Listing 5.8: Definition von NotificationCode in der Header-Datei von Dt_Dll.
ReturnCode ist ein Pointer auf denjenigen Wert, der zurückgeliefert werden soll. Hier hat
man die Möglichkeit bei WSAPostApiNotify diesen Wert zu lesen bzw. zu ändern.
LibraryName ist der Name der verwendeten Bibliothek. Im Fall der API-Funktionen ist
es die Winsock2. Im Fall der SPI-Funktionen ist es die Datei, in welcher der Service
Provider implementiert ist.
Schließlich kommt eine Parameterliste mit einer variablen Länge. Diese Liste enthält
Pointer zu den Parametern, mit denen die Winsock2-Funktion aufgerufen wird. Die
Extraktion der Parameter aus der Parameterliste wird später erklärt.
Wie erwähnt, kann die Ausführung von Funktionen aus der Winsock2 den Applikationen
vorgetäuscht werden. Das geschieht, indem man ReturnCode den gewünschten
Rückgabewert zuweist und die Funktion WSAPreApiNotify mit der Rückgabe true
beendet.
- 23 -
Wenn WSAPreApiNotify true zurückliefert, wird die Ausführung der Winsock2
abgebrochen und der Wert zugeliefert, der von Returnvalue adressiert wird. Sonst wird
die Funktion weiter ausgeführt. Das gleiche gilt für WSAPostApiNotify. In der
Implementierung von connect sieht der Aufruf von WSAPreApiNotify etwa wie folgt aus.
BOOL should_skip;
int connect_return;
should_skip = (* lpWSAPreApiNotify) (
DTCODE_connect,
// NotificationCode
(LPVOID) & connect_return, // ReturnCode
“winsock2.dll”,
// LibraryName
& s,
& name,
& namelen);
if (should_skip) {
return(connect_return);
}
Listing 5.9: Implementierung von connect in der „Debug/Trace Version“ der Winsock2-DLL.
Somit erlaubt uns die Dt_Dll mit ihren Funktionen WSAPreApiNotify und
WSAPostApiNotify volle Kontrolle über die Funktionsaufrufe an den API- und SPISchnittstellen. Rückgabewerte und Parameter können über ihre Pointer geändert werden
und Funktionsaufrufe können abgelehnt werden. Jedoch möchten wir diese DLL nur
verwenden, um Erkenntnisse über das Verhalten der Applikationen an der APISchnittstelle zu gewinnen und werden diese Werte nicht ändern.
5.2.3 Implementierung
An Hand von NotificationCode kann man erkennen, welche Funktion gerade aufgerufen
wird und dementsprechend die Parameter von der Parameterliste extrahieren. Listing 5.10
erklärt dieses Verfahren an Hand des Beispiels der Funktion socket.
- 24 -
BOOL WINAPIV
WSAPreApiNotify(IN
LibraryName, ...) {
INT
NotificationCode,
OUT
LPVOID
ReturnCode,
IN
LPSTR
*LogFile << "\n" << NotificationCode << " + ";
va_list vList;
// declare parameter list
va_start(vList, LibraryName);
// initialize parameter list
switch(NotificationCode)
{
case DTCODE_socket:
{
int af = (int)*va_arg(vList, int *);
// extract parameter from parameter list
int type = (int)*va_arg(vList, int *);
int protocol = (int)*va_arg(vList, int *);
*LogFile << "t " << type;
break;
}
/* weitere case-Anweisungen */
……
}
return false;
} // WSAPreApiNotify
Listing 5.10: Implementierung von WSAPreApiNotify.
Die Parameterliste va_list wird mit va_start initialisiert. Die einzelnen Argumente
werden mit va_arg in der Reihenfolge aus der Liste extrahiert. Somit kann man alle
Parameter auslesen, mit denen die Funktion socket aufgerufen wird.
Hier folgt auch die Implementierung von WSAPostApiNotify für den Fall der Funktion
socket.
- 25 -
BOOL WINAPIV
WSAPostApiNotify(IN
LibraryName, ...) {
INT
NotificationCode,
OUT
LPVOID
ReturnCode,
IN
LPSTR
*LogFile << "\n" << NotificationCode << " - ";
va_list vList;
va_start(vList, LibraryName);
switch(NotificationCode)
{
case DTCODE_socket:
{
SOCKET * s = (SOCKET *)ReturnCode;
*LogFile << "s " << *s; // write the socket descriptor in the log file
break;
}
/* weitere case-Anweisungen */
……
}
return false;
} // WSAPostApiNotify
Listing 5.11: Implementierung von WSAPostApiNotify.
Hier wird der Parameter ReturnCode verwendet. Der Rückgabewert von socket ist ein
„Socket Descriptor“. Dieser ist mit einem „File Descriptor“ im Dateisystem vergleichbar.
Nachdem das Socket abgelegt ist, kann der „Socket Descriptor“ für die Ausführung von
Send- und Receive-Befehlen und anderen Operationen verwendet werden.
Wenn NotificationCode gleich DTCODE_socket ist, dann ist ReturnCode ein Pointer auf
dem „Socket Descriptor“. Somit können dieser Wert gespeichert werden und
nachfolgende Send- und Receive-Befehle jeweils ihren Sockets richtig zugeordnet
werden.
In der „Windows Sockets 2 SDK“ befindet sich ein Beispiel für die Implementierung der
Dt_DLL von Jeffrey C. Diese Implementierung vermeidet die Switch-Anweisung mit
einem Aufruf von LOG-Funktionen über „Pointer of functions“, die dynamisch bestimmt
werden. Mit diesem Ansatz kann man eine übergroße Switch-Anweisung vermeiden,
wenn die Parameter mehrerer Funktionen protokolliert werden sollen. Schließlich können
WSAPre- und WSAPostApiNotify mit 175 verschiedenen Werten von NotificationCode
aufgerufen werden.
Doch in unserer Implementierung wurde auf dieses „elegante“ Verfahren verzichtet. Bei
Jeffrey C. wird die Parameterliste va_list auf Grund ihrer variablen Länge mehrmals
aufgeteilt und zusammengestellt, damit die Parameter zwischen Unterprogrammen
weitergegeben werden können. Dieses Verfahren beeinflusst die Performance der
Winsock2-DLL. Deshalb werden alle Fälle innerhalb von WSAPreApiNotify bzw.
WSAPostApiNotify
in
einer
Switch-Anweisung
behandelt.
Mit
diesem
„einfachen“ Programmierstil ist unser Code auch nicht unübersichtlich geworden, zumal
- 26 -
wir uns auf wenige Winsock2-Funktionen beschränkt haben. In [25] wird der Ansatz von
Jeffrey C. genauer beschrieben.
5.3 Zusammenfassung beider Ansätze
Nachdem der zweite Ansatz vorgestellt wurde, stellt man fest, dass er bedeutend
einfacher ist. Die Hauptaufgabe besteht darin, die zwei Funktionen WSAPre- und
WSAPostApiNotify zu implementieren. Im ersten Ansatz umfasste der Quellcode der
Winsock2-DLL über 2000 automatisch erzeugte Zeilen, nur um die Funktionen
weiterzuleiten, und bevor weitere Logging-Funktionalität implementiert wird. Der
Umfang der Implementierung von Dt_Dll hingegen umfaßt weniger als 400 Zeilen.
Mit der „Debug/Trace Version“ der Winsock2-DLL kann man auch einen Einblick in die
Service Provider gewinnen, so dass das Verständnis der Funktionalität der Winsock2
gefördert wird.
Außerdem ist die Dt_Dll mit einem neuen Betriebsystem einsatzbereit, sobald die
passende „Debug/Trace Version“ der Winsock2-DLL zur Verfügung steht. Die Dt_Dll
wurde mit Windows 2000 implementiert. Die „Debug/Trace Version“ der Winsock2
wurde aus der CD „Microsoft Platform SDK, April 2001“ übernommen. Sie wurde laut
Microsoft-Angaben mit der Beta-Version von Windows XP getestet.
6. Daten erfassen und visualisieren
Nachdem wir einen Eingangspunkt in die Winsock2-DLL implementiert und ein
Verfahren realisiert haben, mit dem wir von den Funktionsaufrufen aus der Winsock2DLL benachrichtigt werden und auf die Parameter zugreifen können, mit denen diese
Funktionen aufgerufen werden, möchten wir diese Ereignisse visualisieren bzw. in
Dateien protokollieren und auswerten.
Unser Ziel ist, das Verhalten der Applikation an der API-Schnittstelle zu untersuchen.
Insbesondere sind einige Informationen relevant für die Analyse dieses Verhaltens, z.B.
die Lebensdauer eines Sockets, die Zeitspanne zwischen zwei Send- oder ReceiveBefehlen und die Paketgröße. Eventuell können sich nachträglich weitere Informationen
als relevant erweisen.
6.1 Winsock2-API-Monitor
Um die Daten zu visualisieren, sind einige Möglichkeiten denkbar. Erwünscht wäre z.B.
ein Monitor, der die Aufrufe von Funktionen aus der Winsock2-DLL mit ihren
Parametern unmittelbar und in Echtzeit anzeigt4. Doch die Leistung der CPU wird durch
die unverzögerte Ausgabe der Funktionsaufrufe mit ihren Parametern stark beeinträchtigt.
Die Ausführung der Kommunikationsbefehle wird gebremst. Applikationen, die EchtzeitAnforderungen haben, wie Multimedia-Übertragung bspw. „Voice Over IP“, werden
4
Vgl. den API-Monitor von TracePlus. In der Homepage von SST Inc. wird behauptet, dass TracePlus echtzeitfähig
sei. Dies ist allerdings zu bezweifeln.
- 27 -
nicht mehr echtzeitfähig. Außerdem werden die Messwerte der Zeitspannen nicht mehr
aussagekräftig, wenn ein großer Teil der Ausführung der Kommunikationsbefehle in der
Ausgabe, und nicht in der eigentlichen Ausführung des Befehls vergeht.
6.2 Performance Monitor
Der Performance Monitor (Perfmon.exe) ist ein Feature von Windows NT/2000, mit dem
mehrere Systemeigenschaften wie Prozessorleistung, Netzwerkverkehr, Dienste und
Treiber visualisiert und analysiert werden können.
Die Daten, die der Performance Monitor visualisieren kann, sind so genannte „Counter“.
In der „Registry“ stehen Einträge für die existierenden Counter und jeweils eine DLL,
mit der die Counter berechnet werden können. Diese DLL wird von dem Prozess
PerfMon.exe geladen und muss drei Funktionen exportieren: Open, Collect und Close.
Die Counter werden mit Collect in regelmäßigen Zeitabständen gelesen und auf dem
Performance Monitor visualisiert.
Die Größe eines Pakets beim Senden oder Empfangen kann mit dem Performance
Monitor visualisiert werden, wenn sie in einem Array gespeichert wird und der Prozess
PerfMon.exe diese Daten über eine DLL lesen kann. Diese DLL muss die Funktionen
Open, Collect und Close exportieren. Dies ist unabhängig davon, welcher Ansatz bei dem
Zugriff auf die Daten implementiert wird. Beim ersten Ansatz würde die neue Winsock2DLL zusätzlich zu den üblichen Winsock2-Funktionen die drei Funktionen Open, Collect
und Close exportieren. Beim zweiten Ansatz würden diese drei Funktionen von der
Dt_Dll zusätzlich zu WSAPre- und WSAPostApiNotify exportiert werden.
Der Performance Monitor und die Applikation müssen sich einen gemeinsamen
Speicherbereich teilen, in dem diese Daten gelesen bzw. geschrieben werden. Mit dem in
Abschnitt 4.1.6 vorgestellten Verfahren „Memory Sharing“ kann sich der Performance
Monitor die Daten mit einer Applikation teilen. Somit können diese Daten mit dem
Performance Monitor visualisiert werden. Doch dieses Verfahren erfordert eine
aufwändige Synchronisation des Zugriffs auf das gemeinsame Daten-Segment, denn die
Daten werden für andere Prozesse blockiert, wenn ein Prozess auf sie zugreift. Der
Performance Monitor und die jenige Applikation würden sich gegenseitig stören.
Diese Synchronisation würde die Ausführung der Kommunikationsbefehle öfter
blockieren. Damit ist eine aussagekräftige Visualisierung der Daten durch den
Performance Monitor nicht möglich.
6.3 LOG-Datei
Nachdem die Nachteile des Winsock2-API-Monitors und des Performance Monitors
vorgestellt wurden, bleibt uns nur eine Möglichkeit, das Verhalten der Applikation an der
API-Schnittstelle zu kontrollieren: Die Daten werden in einer Log-Datei gespeichert und
sämtliche unmittelbaren Ausgaben auf dem Bildschirm vermieden. Selbst die Ausgaben
in der Datei müssen möglichst gering bleiben. Hier kommt uns der NotoficationCode von
- 28 -
der „Debug/Trace Version“ der Winsock2-DLL zugute: Eine kleine Zahl in die Datei zu
schreiben, ist viel effizienter als den ganzen Namen der Funktion zu schreiben. Die LOGDatei kann nachträglich mit einem Perl-Script dekodiert werden.
6.3.1 Ausgabe der LOG-Dateien
Listing 6.1 zeigt einen Abschnitt einer LOG-Datei, die mit der Ausführung von „Internet
Explorer“ erzeugt wurde.
% Winsock API Log File
% Module: E:\Program Files\Internet Explorer\IEXPLORE.EXE
% Node: ALADIN
% Initiated: 10-20-2001, 15:6:12
% Frequency 1193182
% Start 1382167807
54 + 1382169073
54 - 1382172247
21 + 1382177450
t
102 + 1382180302
102 - 1382188435
21 – 1382190986
s
......
43 + 1395041212
s
736
92 + 1395041254
92 - 1395041318
……
25 + 1401918166
25 - 1401918208
% Performance factor: 0.220271 %
2
736
l
32
Listing 6.1: Ausschnitt einer Winsock2-API-LOG-Datei.
Die Zeilen, die mit dem Zeichen ‚%’ anfangen, geben allgemeine Informationen über den
gesamten Prozess, z.B. Modul-Name, NetBIOS-Name des Knoten und die Uhrzeit, zu
der Winsock2 DLL geladen wird.
Beim Aufruf von WSAPre bzw. WSAPostApiNotify wird der NotificationCode der
jeweiligen Funktion in die LOG-Datei geschrieben. Das Zeichen ‚+’ steht dafür, dass die
Funktion aufgerufen wird, und ‚-’ steht dafür, dass sie beendet wird.
Danach kommt ein Counter der Zeit in hoher Genauigkeit. Dieser Counter wird mit dem
Befehl QueryPerformanceCounter hardwarenah gemessen. Dieser Befehl wird nicht von
jeder Hardware unterstützt. Der Befehl QueryPerformanceFrequency gibt an, wie oft in
einer Sekunde dieser Counter inkrementiert wird. Wenn z.B. diese Frequenz in der
Größenordnung von 106 ist, dann ist die Genauigkeit des Counters im Bereich von
Mikrosekunden. Die Frequenz wird am Anfang gemessen und in die Datei ausgegeben,
damit sie später für die Übersetzung des Counters in natürliche Zeiteinheiten verwendet
- 29 -
wird. Der Counter Start 1382167807 gibt den Zeitpunkt an, an dem die Winsock2-DLL
geladen wird. So wird später die relative Zeit am Startpunkt berechnet.
Zusätzlich dazu kommt bei einigen Funktionen die Ausgabe von wichtigen Parametern.
So wird z.B. beim Aufruf von socket (NotificationCode = 21) protokolliert, welchen Typ
von Socket die Applikation wünscht. Die gängigsten Socket-Typen sind TCP (type = 1)
und UDP (type = 2). Beim Beenden von socket wird der Rückgabewert, also der „Socket
Descriptor“, gespeichert. Bei Send- und Receive-Befehlen wird die Länge des Pakets
gespeichert.
Damit die Syntaxanalyse der LOG-Datei später vereinfacht wird, steht vor diesen Zahlen
jeweils ein Zeichen, das erklärt, welche Bedeutung diese Zahl hat. Unter anderem steht s
für den Socket Descriptor, t für den Typ des Sockets und l für die Länge des Pakets.
6.3.2 Performance Factor
Zum Schluss der LOG-Datei kommt der „Performance factor“: der Anteil der
Ausführung der Logging-Befehle zu der gesamten Ausführung des Winsock2-Befehls in
Prozent.
Die Zeit zum Schreiben in die Datei und die Zeit zur Ausführung des gesamten Befehls
wird bei jeder Winsock2-Operation mit dem Befehl QueryPerformanceCounter gelesen
und addiert. Zum Schluss wird der durchschnittliche Anteil in Prozent ausgerechnet.
Der „Performance Factor“ entspricht dem Einfluss der Protokollierung der erforderlichen
Daten auf die Ausführung der Winsock2-Funktionsaufrufe. Er variiert nach Applikation
und Hardware. Bei einer CPU mit 466 MHZ Taktfrequenz und 128 MB RAM bleibt der
„Performance Factor“ bei Internet Explorer meistens unter 1%. Bei anderen
Applikationen wie Netscape steigt er leider manchmal bis 33%.
Die Daten könnten in einem statischen Array gespeichert werden und erst innerhalb eines
Threads niedriger Priorität vom Array zu der Datei kopiert werden. Dies macht allerdings
das Logging nicht schneller. Zeitmessungen weisen nach, dass der Zugriff auf ein
statisches Array innerhalb von WSAPre- oder WSAPostApiNotify nicht schneller ist als
der Zugriff auf eine Datei. Das parallele Thread würde trotz seiner niedrigen Priorität den
Prozess nur langsamer machen. Die aufwändige Entwicklung eines solchen Verfahrens
ist die Mühe nicht Wert.
Die Daten werden mit einfachen Schreib-Befehle in die Datei geschrieben.
*LogFile << NotificationCode << " + ";
6.3.3 Übersetzung der LOG-Datei
Die Log-Dateien können auf zwei verschiedenen Arten mit Perl-Scripten dekodiert und
interpretiert werden. Ein Script namens Ws2_API.pl übersetzt einfach jeweils den
- 30 -
NotificationCode in Funktionsnamen, rechnet den Zeit-Counter in Mikrosekunden um
und übersetzt weitere Daten wie „Socket Descriptor“ und Paketgröße in Klartext. Mit
Hilfe von Frequency und Start, die aus der LOG-Datei gelesen werden, kann die relative
Zeit ab dem Laden der Dt_Dll in Mikrosekunden ausgerechnet werden.
Winsock API Log File
Module: E:\Program Files\Internet
Explorer\IEXPLORE.EXE
Node: ALADIN
Initiated: 11-2-2001, 19:27:11
Performance factor: 0.0590816 %
WSAStartup
WSAStartup
socket
WSAStartup
WSAStartup
socket
htonl
htonl
bind
bind
getsockname
getsockname
connect
ntohs
ntohs
connect
select
gethostbyname
inet_addr
Called
returned
Called
Called
returned
returned
Called
returned
Called
returned
Called
returned
Called
Called
returned
returned
Called
Called
Called
00.000.126
00.003.997
00.006.233
00.231.857
00.232.114
00.255.904
00.255.936
00.255.960
00.255.984
00.256.291
00.256.317
00.256.406
00.256.431
00.256.470
00.256.486
00.256.579
00.256.608
00.397.361
00.587.152
Type UDP
Socket 804
Socket 804
Socket 804
Socket 804
Listing 6.2: Ein Ausschnitt aus einer HTML-Datei: Die Übersetzung der
Winsock2-Befehle mit dem Script Ws2_API.pl.
Ein zweites Script namens Ws2_Sockets.pl kann Statistiken über jeden Socket erstellen.
Es wird bei jedem Socket



die Lebensdauer,
die Anzahl der gesendeten und empfangenen Pakete,
die maximale, minimale und durchschnittliche Paketgröße jeweils beim Senden und
Empfangen
ausgerechnet.
- 31 -
Zu jedem Socket wird eine Tabelle für die gesendeten Pakete und eine Tabelle für die
empfangenen Pakete im Zusammenhang mit der Zeit erstellt. Mit diesen Tabellen können
die Daten in eine Excel-Tabelle exportiert werden und damit Excel-Diagramme erstellt
werden, damit der Zusammenhang zwischen Zeit und Paketgröße, und die Zeitspannen
zwischen zwei Send- bzw. Receive-Befehlen graphisch analysiert werden können.
Sockets Statistics:
Socket Type Allocated at Duration
804
UDP 00.255.904 N.A.
956
TCP 00.715.513 11.108.808
1184
TCP 11.696.324 08.090.950
1192
TCP 11.698.564 N.A.
1204
TCP 11.701.841 N.A.
980
TCP 11.826.042 N.A.
Packets
Action
Number of Packets Min size
Max size Avg. size
Send
26
1
1
1
Received 26
32
32
32
Send
414
474
444
Received 18
1
8192
3544
Send
422
502
450
Received 28
1
8192
2853
Send
422
433
427
Received 16
1
1289
578
Send
422
429
425
Received 10
1
1024
488
Send
421
427
424
1
1024
455
2
3
3
2
2
Received 9
Listing 6.3: Ein Ausschnitt aus einer HTML-Datei: Die Berechnung der
Sockets-Statistiken mit dem Script Ws2_Sockets.pl.
Winsock2
1400
1200
Byte
1000
800
600
400
200
0
0
5000000
10000000 15000000 20000000 25000000 30000000
Zeit (m ikrosek.)
Abb.8: Excel-Diagramm der empfangenen Paketgröße im
Zusammenhang mit der Zeit auf einem Socket.
- 32 -
7. Installation
In der Entwicklungsphase ist es schwer, die System-Winsock2-DLL zu ersetzen. Die
Winsock2-DLL befindet sich in dem Verzeichnis WINNT\System32\ und wird schon
beim Systemstart geladen. Versucht man diese Datei zu verschieben, zu löschen oder
umzubenennen, bekommt man eine Fehlermeldung: „Diese Datei wird von Windows
benutzt“.
Bei einem System, auf dem mehr als ein Betriebsystem installiert ist, kann man diese
Datei manipulieren, solange ein anderes Betriebsystem läuft. Wenn die zu ersetzende
DLL auf einer NTFS-Partition installiert ist, ist diese Partition allerdings von anderen
Betriebssystemen nicht sichtbar.
Es gibt die Möglichkeit, dem Betriebssystem über eine Shell oder ein Programm zu
benachrichtigen, dass bestimmte System-Dateien bei einem neuen Start ersetzt werden
sollen5. Dies wäre eine Lösung für Rechner mit einem einzigen Betriebssystem oder für
NTFS-Partitionen. Diese Möglichkeit wurde allerdings in dieser Arbeit nicht behandelt,
weil die Entwicklung auf einem Rechner mit zwei Betriebssystemen lief.
Jedoch besteht während der Entwicklungsphase ein Problem: Wenn die Winsock2-DLL
oder die Dt_DLL fehlerhaft ist, kann das System nicht starten. Man hat keine
Möglichkeit, Fehler zu suchen und den Code zu „debuggen“. Man könnte einen
Nachbarrechner über eine serielle Schnittstelle anschließen und auf dem zweiten Rechner
einen Debugger starten. Das wäre aber ziemlich umständlich und würde die Entwicklung
verlangsamen.
Hier wird ein einfacher Trick verwendet. Wenn eine DLL während eines Prozesses
geladen werden soll, sucht das Betriebsystem nach der DLL zunächst im selben
Verzeichnis, in dem sich die ausführbare Datei befindet. Erst wenn die DLL in diesem
Verzeichnis nicht existiert, wird über den globalen Pfad gesucht.
Wir können die „Debug/Trace Version“ der Winsock2-DLL und die Dt_Dll in dieses
Verzeichnis kopieren und mit einzelnen Applikationen testen. Dieses Verfahren war sehr
effizient bei der Entwicklung. So wurde die Dt_Dll entwickelt und mit verschiedenen
Internetanwendungen erfolgreich getestet, vor allem mit dem Internet Explorer,
NetMeeting, Netscape, Telnet und „Secure Shell Client“.
8. Konfigurationsprogramm
Wenn die Ws2_32.dll und Dt_Dll installiert sind, fehlen noch einige Eingaben, die das
Protokollieren der Winsock-Aufrufe steuern.

5
Es gibt viele Programme, die die Winsock2-DLL laden. Wenn das Protokollieren
der Winsock2-Aufrufe für alle Programme gelten soll, bekommt man sehr schnell
Vergleiche die Installation von Service Pack von Windows.
- 33 -

eine große Anzahl von Dateien, die gar nicht interessieren. Daher ist es sinnvoll
zu bestimmen, bei welchen Internetanwendungen protokolliert werden soll.
Die Aufrufe der Winsock-Funktionen sind nicht alle relevant für die Analyse der
Anforderungen der Applikation an der API-Schnittstelle. Das Protokollieren der
SPI-Aufrufe ist z.B. interessant, um Erkenntnisse über die SPI-Schnittstelle zu
gewinnen. Doch für unsere Ziele ist es nicht relevant. Einige API-Funktionen wie
gethostbyname oder gethostbyaddr können auch keine Aussagen über das
Verhalten der Applikation bringen. Am meisten interessant sind diejenigen
Befehle, die den Zustand eines Sockets ändern oder die Befehle für den
Datenverkehr: Send und Receive.
Für diese Einstellungen ist ein Programm mit einer Benutzeroberfläche entwickelt
worden. Dieses Konfigurationsprogramm schreibt die Einstellungen in die „RegistryDatenbank“.
Wenn ein Prozess die Winsock2-DLL lädt, dann wird die Dt_Dll ebenfalls geladen. In
der Dll_Main von Dt_Dll werden die Einträge aus der „Registry“ gelesen.
Beim erstmaligen Starten des Konfigurationsprogramms, wird ein neuer Schlüssel in die
„Registry“ unter
HKEY_LOCAL_MACHINE\ SYSTEM\CurrentControlSet\Services\WinSock2\Parameter\
namens Dt_Parameter eingefügt.
In diesem Schlüssel sind drei Unterschlüssel namens: „Filter“, „LogDir“ und „Modules“.



Der Schlüssel „Modules“ bestimmt, bei welchen Programmen protokolliert wird.
Der Schlüssel „Filter“ legt fest, welche Funktionen protokolliert werden.
Der Schlüssel „LogDir“ bestimmt, in welchem Verzeichnis die LOG-Datei
erzeugt wird, wenn das Programm in der Modul-Liste steht.
Abb. 8 zeigt die Benutzeroberfläche des Konfigurationsprogramms. Die untersten
Schaltflächen „API View“ und „Socket Statistics“ ermöglichen die Auswahl einer LOGDatei und die direkte Ausführung der Perl-Scripte Ws2_API.pl bzw. Ws2_Sockets.pl,
sobald sich diese in dem gleichen Verzeichnis wie die LOG-Datei befinden.
Man kann auch die Einstellungen direkt in die „Registry-Datenbank“ mit dem Programm
„regedit.exe“ eingeben und die Perl-Scripte in einem DOS-Fenster ausführen. Allerdings
werden mit dem Konfigurationsprogramm diese Operationen viel praktikabler.
- 34 -
Abb.9: Konfigurationsprogramm der Winsock2
Startet man ein Programm, welches auf der Modulliste steht, wird noch nachgefragt, ob
die Winsock2-API-Aufrufe geloggt werden sollen (Abb. 9). Diese zusätzliche Abfrage
wird in der Dll_Main der Dt_DLL ausgeführt und ist zugleich ein Nachweis dafür, dass
die Dt_DLL geladen wurde.
- 35 -
Abb.10: Zusätzliche Abfrage, ob die Winsock2-API-Aufrufe geloggt werden sollen.
Achtung: Man darf auf keinen Fall, Programme in die Modulliste einfügen, die beim
Systemstart schon gestartet werden wie z.B. WinMgmt.exe, winlogon.exe, services.exe.
Beim Systemstart kann diese Abfrage vom Benutzer nicht verarbeitet werden. Das
System kann nicht starten.
Diese Abfrage läuft im Code über den Befehl „MessageBox“, der in User32.dll definiert
ist. Für Programme, die beim Systemstart geladen werden und andere Programme, die
über keine Benutzeroberfläche verfügen, könnte man in dem Code überprüfen, ob die
User32.dll schon geladen ist. Damit könnte man ein solches Problem vermeiden. Dieses
Verfahren wurde aber in dieser Arbeit nicht realisiert.
9. Zusammenfassung und Ausblick
In dieser Arbeit wurde ein Tool entwickelt, das die Analyse des Verhaltens der
Applikationen an der API-Schnittstelle ermöglicht. Das Tool erfasst die Aufrufe von
Netzwerkfunktionen und ihre Parameter.
Zuerst wurde mit TracePlus ein kommerzielles Tool vorgestellt, das diese Aufgabe erfüllt.
Die Vor- und Nachteile von TracePlus wurden beschrieben.
Danach wurden einige Grundlagen über DLLs und die Winsock2-API vorgestellt. Die
Unterstützung mehrerer Protokollfamilien wurde hervorgehoben. Die Kompatibilitätskomponente wurde vorgestellt.
Die Entwicklung des Tools selbst gliederte sich in zwei große Schritte:

Die Erfassung der Funktionsaufrufe der Winsock2-API und ihrer Parameter.
1. In einem Verfahren wurde eine neue Winsock2-DLL implementiert.
2. Im anderen Verfahren wurde die „Debug/Trace Version“ der Winsock2-DLL
eingesetzt.
Letztendlich wurde das zweite Verfahren ausgewählt.

Die Visualisierung der Funktionsaufrufe und ihrer Parameter. Hier wurden drei
Verfahren diskutiert:
1. Anzeigen der Funktionsaufrufe auf einen Monitor
- 36 -
2. Implementierung einer Schnittstelle zwischen der Winsock2-DLL und dem
Performance Monitor (PerfMon.exe)
3. Protokollieren der Daten in einer LOG-Datei und Visualisierung in ExcelDiagrammen.
Der Umfang dieser Arbeit war nicht ausreichend für eine ausführliche Auswertung der
Ergebnisse. Jedoch werden hier einige Feststellungen erläutert, die weitere Arbeiten in
diese Richtung motivieren sollen.
Es wurde eine Nichtübereinstimmung mit den Ergebnissen von TracePlus festgestellt.
Unser Programm zeigt öfter Funktionen auf, die durch die Applikation gar nicht
aufgerufen werden. Einige „Open Source“-Anwendungen bestätigen das. Wie schon im
Abschnitt 4.2.2 erwähnt, werden z.B. WSAStartUp und WSCEnumProtocols aufgerufen,
selbst wenn die Applikation das nicht tut.
Außerdem werden alle Aufrufe von recv durch WSARecv ersetzt. In Winsock2 wird
WSARecv automatisch aufgerufen, wenn neue Daten ankommen. Damit wird gesichert,
dass der Prozess durch den Aufruf von recv nicht blockiert wird.
Möglicherweise werden diese zusätzlichen Aufrufe bzw. die Konvertierung von einigen
Aufrufen teilweise durch die Kompatibilitätskomponente der Winsock2 abgewickelt.
Eventuell werden sie auch durch eine weitere DLL des Betriebssystems durchgeführt.
TracePlus beschränkt sich auf die Aufrufe der Applikation selbst, weil es einzelne
Prozesse startet und wahrscheinlich in der Lage ist, die Winsock2-Aufrufe aus der
ausführbaren Datei einzufangen.
- 37 -
Literaturverzeichnis
[1] MSDN Library: Platform SDK Documentation; DLLs Processes, and Threads;
Dynamic Link Libraries; About Dynamic Link Libraries
[2] MSDN Library: Platform SDK Documentation; DLLs Processes, and Threads;
Dynamic Link Libraries; Advantages of Dynamic Linking
[3] MSDN Library: Visual C++ Documentation; DLL Tasks; Link Implicitly
[4] MSDN Library: Visual C++ Documentation; DLL Tasks; Link Explicitly
[5] MSDN Library: Visual C++ Documentation; DLL Tasks; Export from a DLL using
a .DEF files
[6] MSDN Library: Visual C++ Documentation; DLL Tasks; Export from a DLL by
ordinal rather by name
[7] MSDN Library: Platform SDK Documentation; Networking and Directory Services;
Windows Sockets Version 2; Windows Sockets Version 2 API; New Concepts,
Additions, and Changes for Windows Sockets 2, Windows Sockets 2 Architecture
[8] MSDN Library: Platform SDK Documentation; Networking and Directory Services;
Windows Sockets Version 2; Windows Sockets Version 2 API; New Concepts,
Additions, and Changes for Windows Sockets 2; Windows Sockets 2 Architecture;
Simultaneous Access to Multiple Transport Protocols
[9] MSDN Library: Platform SDK Documentation; Networking and Directory Services;
Windows Sockets Version 2; Windows Sockets Version 2 API; New Concepts,
Additions, and Changes for Windows Sockets 2; Windows Sockets 2 Architecture;
Backward Compatibility for Windows Sockets 1.1 Applications
[10] MSDN Library: Platform SDK Documentation; Networking and Directory
Services; Windows Sockets Version 2; Windows Sockets Version 2 API; New
Concepts, Additions, and Changes for Windows Sockets 2; Overlapped I/O and Event
Objects
[11] MSDN Library: Platform SDK Documentation; Networking and Directory
Services; Windows Sockets Version 2; Windows Sockets Version 2 API; New
Concepts, Additions, and Changes for Windows Sockets 2; Making Transport
Protocols Available to Windows Sockets; Debug and Trace Facilities
[12] MSDN Library: Platform SDK Documentation; Networking and Directory
Services; Windows Sockets Version 2; Windows Sockets Version 2 API; Windows
Sockets Programming Considerations; Windows Socket 1.1 Blocking Routines and
EINPROGRESS
[13] MSDN Library: Platform SDK Documentation; Networking and Directory
Services; Windows Sockets Version 2; Windows Sockets Version 2 API; References;
Functions
[14] MSDN Library: Platform SDK Documentation; Networking and Directory
Services; Windows Sockets Version 2; Windows Sockets Version 2 API; References;
Structures
[15] MSDN Library: Platform SDK Documentation; Networking and Directory
Services; Windows Sockets Version 2; Windows Sockets Version 2 SPI
[16] MSDN Library: Platform SDK Documentation; Bases Services; Performance
Monitoring; Performance Monitoring Architecture
- 38 -
Abb.4:
Implementier
ung einer
neuen
Winsock2DLL. Bsp.
Die Funktion
socket. (1)
Eine
Applikation
ruft die
Funktion
socket aus der
neuen
Winsock2.
Die neue
Winsock2 hat
die
Möglichkeit
in (I)
Parameter
und
Zeitstempeln
zu
protokollieren
. (2) Die neue
Winsock2
ruft sie die
Funktion
socket aus der
alten
Winsock2.
(3) Die alte
Winsock2
gibt einen
„Socket
Descriptor“ z
urück. Die
neue
Winsock2
kann in (II)
wieder
protokollieren
. (4) Die neue
Winsock2
liefert den
„Socket
Descriptor“ z
u der
Applikation
zurück.
[17] MSDN Library: Periodicals; Custom Performance Monitoring for Your Windows
NT Applications
[18] MSDN Library: Platform SDK Documentation; Bases Services; Windows System
Information, Registry Functions
[19] MSDN Library: Platform SDK Documentation; Bases Services; Windows System
Information, Registry Structures
[20] MSDN Library: Technical Articles; Microsoft Office and Visio; Microsoft Office;
Automating Microsoft Office 97 and Microsoft Office 2000
[21] “Visual C++ in 21 Tagen”
http://www.mut.com/media/buecher/VCPLUS6/data/start.htm
[22] “Technical Work Forums For Computer Professionals” http://www.tek-tips.com/
[23] “SST Homepage” http://www.sstinc.com
[24] “How to share a data segment in a DLL”
http://www.codeproject.com/dll/data_seg_share.asp
[25] “WinSock 2 Debug and Trace Facilities”: SDK Platform CD;
\Samples\NetDs\WinSock\Dt_Dll\DbgSpec.doc
[26] Kurzfassung des Projektantrags DANCE; AG Müller.
- 39 -
Herunterladen