NPF驱动核心指南
[WinPcap核心资料]


模块

 NPF 结构与定义
 NPF 函数

数据结构

struct  binary_stream
 A stream of X86 binary code. More...
struct  JIT_BPF_Filter
 Structure describing a x86 filtering program created by the jitter. More...

定义

#define EAX   0
#define ECX   1
#define EDX   2
#define EBX   3
#define ESP   4
#define EBP   5
#define ESI   6
#define EDI   7
#define AX   0
#define CX   1
#define DX   2
#define BX   3
#define SP   4
#define BP   5
#define SI   6
#define DI   7
#define AL   0
#define CL   1
#define DL   2
#define BL   3
#define MOVid(r32, i32)   emitm(&stream, 11 << 4 | 1 << 3 | r32 & 0x7, 1); emitm(&stream, i32, 4);
 mov r32,i32
#define MOVrd(dr32, sr32)   emitm(&stream, 8 << 4 | 3 | 1 << 3, 1); emitm(&stream, 3 << 6 | (dr32 & 0x7) << 3 | sr32 & 0x7, 1);
 mov dr32,sr32
#define MOVodd(dr32, sr32, off)
 mov dr32,sr32[off]
#define MOVobd(dr32, sr32, or32)
 mov dr32,sr32[or32]
#define MOVobw(dr32, sr32, or32)
 mov dr16,sr32[or32]
#define MOVobb(dr8, sr32, or32)
 mov dr8,sr32[or32]
#define MOVomd(dr32, or32, sr32)
 mov [dr32][or32],sr32
#define BSWAP(dr32)
 bswap dr32
#define SWAP_AX()
 xchg al,ah
#define PUSH(r32)   emitm(&stream, 5 << 4 | 0 << 3 | r32 & 0x7, 1);
 push r32
#define POP(r32)   emitm(&stream, 5 << 4 | 1 << 3 | r32 & 0x7, 1);
 pop r32
#define RET()   emitm(&stream, 12 << 4 | 0 << 3 | 3, 1);
 ret
#define ADDrd(dr32, sr32)
 add dr32,sr32
#define ADD_EAXi(i32)
 add eax,i32
#define ADDid(r32, i32)
 add r32,i32
#define ADDib(r32, i8)
 add r32,i8
#define SUBrd(dr32, sr32)
 sub dr32,sr32
#define SUB_EAXi(i32)
 sub eax,i32
#define MULrd(r32)
 mul r32
#define DIVrd(r32)
 div r32
#define ANDib(r8, i8)
 and r8,i8
#define ANDid(r32, i32)
 and r32,i32
#define ANDrd(dr32, sr32)
 and dr32,sr32
#define ORrd(dr32, sr32)
 or dr32,sr32
#define ORid(r32, i32)
 or r32,i32
#define SHLib(r32, i8)
 shl r32,i8
#define SHL_CLrb(dr32)
 shl dr32,cl
#define SHRib(r32, i8)
 shr r32,i8
#define SHR_CLrb(dr32)
 shr dr32,cl
#define NEGd(r32)
 neg r32
#define CMPodd(dr32, sr32, off)
 cmp dr32,sr32[off]
#define CMPrd(dr32, sr32)
 cmp dr32,sr32
#define CMPid(dr32, i32)
 cmp dr32,i32
#define JNEb(off8)
 jne off32
#define JE(off32)
 je off32
#define JLE(off32)
 jle off32
#define JLEb(off8)
 jle off8
#define JA(off32)
 ja off32
#define JAE(off32)
 jae off32
#define JG(off32)
 jg off32
#define JGE(off32)
 jge off32
#define JMP(off32)
 jmp off32

自定义类型

typedef UINT(__cdecl *) BPF_filter_function (PVOID *, ULONG, UINT)
 Prototype of a filtering function created by the jitter.
typedef void(*) emit_func (binary_stream *stream, ULONG value, UINT n)
 Prototype of the emit functions.

详细描述

This section documents the internals of the Netgroup Packet Filter (NPF), the kernel portion of WinPcap. Normal users are probably interested in how to use WinPcap and not in its internal structure. Therefore the information present in this module is destined mainly to WinPcap developers and maintainers, or to the people interested in how the driver works. In particular, a good knowledge of OSes, networking and Win32 kernel programming and device drivers development is required to profitably read this section. 

NPF is the WinPcap component that does the hard work, processing the packets that transit on the network and exporting capture, injection and analysis capabilities to user-level.

The following paragraphs will describe the interaction of NPF with the OS and its basic structure.

NPF and NDIS

NDIS (Network Driver Interface Specification) is a standard that defines the communication between a network adapter (or, better, the driver that manages it) and the protocol drivers (that implement for example TCP/IP). Main NDIS purpose is to act as a wrapper that allows protocol drivers to send and receive packets onto a network (LAN or WAN) without caring either the particular adapter or the particular Win32 operating system.

NDIS supports three types of network drivers:

  1. Network interface card or NIC drivers. NIC drivers directly manage network interface cards, referred to as NICs. The NIC drivers interface directly to the hardware at their lower edge and at their upper edge present an interface to allow upper layers to send packets on the network, to handle interrupts, to reset the NIC, to halt the NIC and to query and set the operational characteristics of the driver. NIC drivers can be either miniports or legacy full NIC drivers.
  2. Intermediate drivers. Intermediate drivers interface between an upper-level driver such as a protocol driver and a miniport. To the upper-level driver, an intermediate driver looks like a miniport. To a miniport, the intermediate driver looks like a protocol driver. An intermediate protocol driver can layer on top of another intermediate driver although such layering could have a negative effect on system performance. A typical reason for developing an intermediate driver is to perform media translation between an existing legacy protocol driver and a miniport that manages a NIC for a new media type unknown to the protocol driver. For instance, an intermediate driver could translate from LAN protocol to ATM protocol. An intermediate driver cannot communicate with user-mode applications, but only with other NDIS drivers.
  3. Transport drivers or protocol drivers. A protocol driver implements a network protocol stack such as IPX/SPX or TCP/IP, offering its services over one or more network interface cards. A protocol driver services application-layer clients at its upper edge and connects to one or more NIC driver(s) or intermediate NDIS driver(s) at its lower edge.

NPF is implemented as a protocol driver. This is not the best possible choice from the performance point of view, but allows reasonable independence from the MAC layer and as well as complete access to the raw traffic.

Notice that the various Win32 operating systems have different versions of NDIS: NPF is NDIS 5 compliant under Windows 2000 and its derivations (like Windows XP), NDIS 3 compliant on the other Win32 platforms. 

Next figure shows the position of NPF inside the NDIS stack:

Figure 1: NPF inside NDIS.

The interaction with the OS is normally asynchronous. This means that the driver provides a set of callback functions that are invoked by the system when some operation is required to NPF. NPF exports callback functions for all the I/O operations of the applications: open, close, read, write, ioctl, etc.

The interaction with NDIS is asynchronous as well: events like the arrival of a new packet are notified to NPF through a callback function (Packet_tap() in this case). Furthermore, the interaction with NDIS and the NIC driver takes always place by means of non blocking functions: when NPF invokes a NDIS function, the call returns immediately; when the processing ends, NDIS invokes a specific NPF callback to inform that the function has finished. The driver exports a callback for any low-level operation, like sending packets, setting or requesting parameters on the NIC, etc.

NPF structure basics

Next figure shows the structure of WinPcap, with particular reference to the NPF driver.

Figure 2: NPF device driver.

NPF is able to perform a number of different operations: capture, monitoring, dump to disk, packet injection. The following paragraphs will describe shortly each of these operations.

Packet Capture

The most important operation of NPF is packet capture. During a capture, the driver sniffs the packets using a network interface and delivers them intact to the user-level applications. 

The capture process relies on two main components:

The size of the user buffer is very important because it determines the maximum amount of data that can be copied from kernel space to user space within a single system call. On the other hand, it can be noticed that also the minimum amount of data that can be copied in a single call is extremely important. In presence of a large value for this variable, the kernel waits for the arrival of several packets before copying the data to the user. This guarantees a low number of system calls, i.e. low processor usage, which is a good setting for applications like sniffers. On the other side, a small value means that the kernel will copy the packets as soon as the application is ready to receive them. This is excellent for real time applications (like, for example, ARP redirectors or bridges) that need the better responsiveness from the kernel. From this point of view, NPF has a configurable behavior, that allows users to choose between best efficiency or best responsiveness (or any intermediate situation). 

The wpcap library includes a couple of system calls that can be used both to set the timeout after which a read expires and the minimum amount of data that can be transferred to the application. By default, the read timeout is 1 second, and the minimum amount of data copied between the kernel and the application is 16K.

Packet injection

NPF allows to write raw packets to the network. To send data, a user-level application performs a WriteFile() system call on the NPF device file. The data is sent to the network as is, without encapsulating it in any protocol, therefore the application will have to build the various headers for each packet. The application usually does not need to generate the FCS because it is calculated by the network adapter hardware and it is attached automatically at the end of a packet before sending it to the network.

In normal situations, the sending rate of the packets to the network is not very high because of the need of a system call for each packet. For this reason, the possibility to send a single packet more than once with a single write system call has been added. The user-level application can set, with an IOCTL call (code pBIOCSWRITEREP), the number of times a single packet will be repeated: for example, if this value is set to 1000, every raw packet written by the application on the driver's device file will be sent 1000 times. This feature can be used to generate high speed traffic for testing purposes: the overload of context switches is no longer present, so performance is remarkably better. 

Network monitoring

WinPcap offers a kernel-level programmable monitoring module, able to calculate simple statistics on the network traffic. The idea behind this module is shown in Figure 2: the statistics can be gathered without the need to copy the packets to the application, that simply receives and displays the results obtained from the monitoring engine. This allows to avoid great part of the capture overhead in terms of memory and CPU clocks.

The monitoring engine is made of a classifier followed by a counter. The packets are classified using the filtering engine of NPF, that provides a configurable way to select a subset of the traffic. The data that pass the filter go to the counter, that keeps some variables like the number of packets and the amount of bytes accepted by the filter and updates them with the data of the incoming packets. These variables are passed to the user-level application at regular intervals whose period can be configured by the user. No buffers are allocated at kernel and user level.

Dump to disk

The dump to disk capability can be used to save the network data to disk directly from kernel mode.

Figure 3: packet capture versus kernel-level dump.

In traditional systems, the path covered by the packets that are saved to disk is the one followed by the black arrows in Figure 3: every packet is copied several times, and normally 4 buffers are allocated: the one of the capture driver, the one in the application that keeps the captured data, the one of the stdio functions (or similar) that are used by the application to write on file, and finally the one of the file system.

When the kernel-level traffic logging feature of NPF is enabled, the capture driver addresses the file system directly, hence the path covered by the packets is the one of the red dotted arrow: only two buffers and a single copy are necessary, the number of system call is drastically reduced, therefore the performance is considerably better.

Current implementation dumps the to disk in the widely used libpcap format. It gives also the possibility to filter the traffic before the dump process in order to select the packet that will go to the disk.

Further reading

The structure of NPF and its filtering engine derive directly from the one of the BSD Packet Filter (BPF), so if you are interested the subject you can read the following papers:

- S. McCanne and V. Jacobson, The BSD Packet Filter: A New Architecture for User-level Packet Capture. Proceedings of the 1993 Winter USENIX Technical Conference (San Diego, CA, Jan. 1993), USENIX. 

- A. Begel, S. McCanne, S.L.Graham, BPF+: Exploiting Global Data-flow Optimization in a Generalized Packet Filter Architecture, Proceedings of ACM SIGCOMM '99, pages 123-134, Conference on Applications, technologies, architectures, and protocols for computer communications, August 30 - September 3, 1999, Cambridge, USA

Note

The code documented in this manual is the one of the Windows NTx version of NPF. The Windows 9x code is very similar, but it is less efficient and lacks advanced features like kernel-mode dump.


Define Documentation

#define ADD_EAXi ( i32   ) 

Value:

emitm(&stream, 0x05, 1);\
  emitm(&stream, i32, 4);
add eax,i32

Definition at line 171 of file jitter.h.

#define ADDib ( r32,
i8   ) 

Value:

emitm(&stream, 0x83, 1);\
  emitm(&stream, 24 << 3 | r32, 1);\
  emitm(&stream, i8, 1);
add r32,i8

Definition at line 182 of file jitter.h.

#define ADDid ( r32,
i32   ) 

Value:

emitm(&stream, 0x81, 1);\
  emitm(&stream, 24 << 3 | r32, 1);\
  emitm(&stream, i32, 4);
add r32,i32

Definition at line 176 of file jitter.h.

#define ADDrd ( dr32,
sr32   ) 

Value:

emitm(&stream, 0x03, 1);\
  emitm(&stream, 3 << 6 | (dr32 & 0x7) << 3 | (sr32 & 0x7), 1);
add dr32,sr32

Definition at line 166 of file jitter.h.

#define AL   0

Definition at line 59 of file jitter.h.

#define ANDib ( r8,
i8   ) 

Value:

emitm(&stream, 0x80, 1);\
  emitm(&stream, 7 << 5 | r8, 1);\
  emitm(&stream, i8, 1);
and r8,i8

Definition at line 208 of file jitter.h.

#define ANDid ( r32,
i32   ) 

Value:

if (r32 == EAX){ \
  emitm(&stream, 0x25, 1);\
  emitm(&stream, i32, 4);}\
  else{ \
  emitm(&stream, 0x81, 1);\
  emitm(&stream, 7 << 5 | r32, 1);\
  emitm(&stream, i32, 4);}
and r32,i32

Definition at line 214 of file jitter.h.

#define ANDrd ( dr32,
sr32   ) 

Value:

emitm(&stream, 0x23, 1);\
  emitm(&stream,  3 << 6 | (dr32 & 0x7) << 3 | sr32 & 0x7, 1);
and dr32,sr32

Definition at line 224 of file jitter.h.

#define AX   0

Definition at line 50 of file jitter.h.

#define BL   3

Definition at line 62 of file jitter.h.

#define BP   5

Definition at line 55 of file jitter.h.

#define BSWAP ( dr32   ) 

Value:

emitm(&stream, 0xf, 1); \
  emitm(&stream,  0x19 << 3 | dr32 , 1);
bswap dr32

Definition at line 144 of file jitter.h.

#define BX   3

Definition at line 53 of file jitter.h.

#define CL   1

Definition at line 60 of file jitter.h.

#define CMPid ( dr32,
i32   ) 

Value:

if (dr32 == EAX){ \
  emitm(&stream, 0x3d, 1); \
  emitm(&stream,  i32, 4);} \
  else{ \
  emitm(&stream, 0x81, 1); \
  emitm(&stream,  0x1f << 3 | (dr32 & 0x7), 1);\
  emitm(&stream,  i32, 4);}
cmp dr32,i32

Definition at line 282 of file jitter.h.

#define CMPodd ( dr32,
sr32,
off   ) 

Value:

emitm(&stream, 3 << 4 | 3 | 1 << 3, 1); \
  emitm(&stream,  1 << 6 | (dr32 & 0x7) << 3 | sr32 & 0x7, 1);\
  emitm(&stream,  off, 1);
cmp dr32,sr32[off]

Definition at line 271 of file jitter.h.

#define CMPrd ( dr32,
sr32   ) 

Value:

emitm(&stream, 0x3b, 1); \
  emitm(&stream,  3 << 6 | (dr32 & 0x7) << 3 | sr32 & 0x7, 1);
cmp dr32,sr32

Definition at line 277 of file jitter.h.

#define CX   1

Definition at line 51 of file jitter.h.

#define DI   7

Definition at line 57 of file jitter.h.

#define DIVrd ( r32   ) 

Value:

emitm(&stream, 0xf7, 1);\
  emitm(&stream, 15 << 4 | (r32 & 0x7), 1);
div r32

Definition at line 203 of file jitter.h.

#define DL   2

Definition at line 61 of file jitter.h.

#define DX   2

Definition at line 52 of file jitter.h.

#define EAX   0

Definition at line 41 of file jitter.h.

#define EBP   5

Definition at line 46 of file jitter.h.

#define EBX   3

Definition at line 44 of file jitter.h.

#define ECX   1

Definition at line 42 of file jitter.h.

#define EDI   7

Definition at line 48 of file jitter.h.

#define EDX   2

Definition at line 43 of file jitter.h.

#define ESI   6

Definition at line 47 of file jitter.h.

#define ESP   4

Definition at line 45 of file jitter.h.

#define JA ( off32   ) 

Value:

emitm(&stream, 0x0f, 1);\
   emitm(&stream, 0x87, 1);\
   emitm(&stream, off32, 4);
ja off32

Definition at line 314 of file jitter.h.

#define JAE ( off32   ) 

Value:

emitm(&stream, 0x0f, 1);\
   emitm(&stream, 0x83, 1);\
   emitm(&stream, off32, 4);
jae off32

Definition at line 320 of file jitter.h.

#define JE ( off32   ) 

Value:

emitm(&stream, 0x0f, 1);\
   emitm(&stream, 0x84, 1);\
   emitm(&stream, off32, 4);
je off32

Definition at line 297 of file jitter.h.

#define JG ( off32   ) 

Value:

emitm(&stream, 0x0f, 1);\
   emitm(&stream, 0x8f, 1);\
   emitm(&stream, off32, 4);
jg off32

Definition at line 326 of file jitter.h.

#define JGE ( off32   ) 

Value:

emitm(&stream, 0x0f, 1);\
   emitm(&stream, 0x8d, 1);\
   emitm(&stream, off32, 4);
jge off32

Definition at line 332 of file jitter.h.

#define JLE ( off32   ) 

Value:

emitm(&stream, 0x0f, 1);\
   emitm(&stream, 0x8e, 1);\
   emitm(&stream, off32, 4);
jle off32

Definition at line 303 of file jitter.h.

#define JLEb ( off8   ) 

Value:

emitm(&stream, 0x7e, 1);\
   emitm(&stream, off8, 1);
jle off8

Definition at line 309 of file jitter.h.

#define JMP ( off32   ) 

Value:

emitm(&stream, 0xe9, 1);\
   emitm(&stream, off32, 4);
jmp off32

Definition at line 338 of file jitter.h.

#define JNEb ( off8   ) 

Value:

emitm(&stream, 0x75, 1);\
   emitm(&stream, off8, 1);
jne off32

Definition at line 292 of file jitter.h.

#define MOVid ( r32,
i32   )     emitm(&stream, 11 << 4 | 1 << 3 | r32 & 0x7, 1); emitm(&stream, i32, 4);

mov r32,i32

Definition at line 105 of file jitter.h.

#define MOVobb ( dr8,
sr32,
or32   ) 

Value:

emitm(&stream, 0x8a, 1); \
  emitm(&stream,  (dr8 & 0x7) << 3 | 4 , 1);\
  emitm(&stream,  (or32 & 0x7) << 3 | (sr32 & 0x7) , 1);
mov dr8,sr32[or32]

Definition at line 132 of file jitter.h.

#define MOVobd ( dr32,
sr32,
or32   ) 

Value:

emitm(&stream, 8 << 4 | 3 | 1 << 3, 1); \
  emitm(&stream,  (dr32 & 0x7) << 3 | 4 , 1);\
  emitm(&stream,  (or32 & 0x7) << 3 | (sr32 & 0x7) , 1);
mov dr32,sr32[or32]

Definition at line 119 of file jitter.h.

#define MOVobw ( dr32,
sr32,
or32   ) 

Value:

emitm(&stream, 0x66, 1); \
  emitm(&stream, 8 << 4 | 3 | 1 << 3, 1); \
  emitm(&stream,  (dr32 & 0x7) << 3 | 4 , 1);\
  emitm(&stream,  (or32 & 0x7) << 3 | (sr32 & 0x7) , 1);
mov dr16,sr32[or32]

Definition at line 125 of file jitter.h.

#define MOVodd ( dr32,
sr32,
off   ) 

Value:

emitm(&stream, 8 << 4 | 3 | 1 << 3, 1); \
  emitm(&stream,  1 << 6 | (dr32 & 0x7) << 3 | sr32 & 0x7, 1);\
  emitm(&stream,  off, 1);
mov dr32,sr32[off]

Definition at line 113 of file jitter.h.

#define MOVomd ( dr32,
or32,
sr32   ) 

Value:

emitm(&stream, 0x89, 1); \
  emitm(&stream,  (sr32 & 0x7) << 3 | 4 , 1);\
  emitm(&stream,  (or32 & 0x7) << 3 | (dr32 & 0x7) , 1);
mov [dr32][or32],sr32

Definition at line 138 of file jitter.h.

#define MOVrd ( dr32,
sr32   )     emitm(&stream, 8 << 4 | 3 | 1 << 3, 1); emitm(&stream, 3 << 6 | (dr32 & 0x7) << 3 | sr32 & 0x7, 1);

mov dr32,sr32

Definition at line 109 of file jitter.h.

#define MULrd ( r32   ) 

Value:

emitm(&stream, 0xf7, 1);\
  emitm(&stream, 7 << 5 | (r32 & 0x7), 1);
mul r32

Definition at line 198 of file jitter.h.

#define NEGd ( r32   ) 

Value:

emitm(&stream, 0xf7, 1);\
  emitm(&stream,  27 << 3 | r32 & 0x7, 1);
neg r32

Definition at line 266 of file jitter.h.

#define ORid ( r32,
i32   ) 

Value:

if (r32 == EAX){ \
  emitm(&stream, 0x0d, 1);\
  emitm(&stream, i32, 4);}\
  else{ \
  emitm(&stream, 0x81, 1);\
  emitm(&stream, 25 << 3 | r32, 1);\
  emitm(&stream, i32, 4);}
or r32,i32

Definition at line 234 of file jitter.h.

#define ORrd ( dr32,
sr32   ) 

Value:

emitm(&stream, 0x0b, 1);\
  emitm(&stream,  3 << 6 | (dr32 & 0x7) << 3 | sr32 & 0x7, 1);
or dr32,sr32

Definition at line 229 of file jitter.h.

#define POP ( r32   )     emitm(&stream, 5 << 4 | 1 << 3 | r32 & 0x7, 1);

pop r32

Definition at line 158 of file jitter.h.

#define PUSH ( r32   )     emitm(&stream, 5 << 4 | 0 << 3 | r32 & 0x7, 1);

push r32

Definition at line 154 of file jitter.h.

 
#define RET (  )     emitm(&stream, 12 << 4 | 0 << 3 | 3, 1);

ret

Definition at line 162 of file jitter.h.

#define SHL_CLrb ( dr32   ) 

Value:

emitm(&stream, 0xd3, 1);\
  emitm(&stream,  7 << 5 | dr32 & 0x7, 1);
shl dr32,cl

Definition at line 250 of file jitter.h.

#define SHLib ( r32,
i8   ) 

Value:

emitm(&stream, 0xc1, 1);\
  emitm(&stream, 7 << 5 | r32 & 0x7, 1);\
  emitm(&stream, i8, 1);
shl r32,i8

Definition at line 244 of file jitter.h.

#define SHR_CLrb ( dr32   ) 

Value:

emitm(&stream, 0xd3, 1);\
  emitm(&stream,  29 << 3 | dr32 & 0x7, 1);
shr dr32,cl

Definition at line 261 of file jitter.h.

#define SHRib ( r32,
i8   ) 

Value:

emitm(&stream, 0xc1, 1);\
  emitm(&stream, 29 << 3 | r32 & 0x7, 1);\
  emitm(&stream, i8, 1);
shr r32,i8

Definition at line 255 of file jitter.h.

#define SI   6

Definition at line 56 of file jitter.h.

#define SP   4

Definition at line 54 of file jitter.h.

#define SUB_EAXi ( i32   ) 

Value:

emitm(&stream, 0x2d, 1);\
  emitm(&stream, i32, 4);
sub eax,i32

Definition at line 193 of file jitter.h.

#define SUBrd ( dr32,
sr32   ) 

Value:

emitm(&stream, 0x2b, 1);\
  emitm(&stream, 3 << 6 | (dr32 & 0x7) << 3 | (sr32 & 0x7), 1);
sub dr32,sr32

Definition at line 188 of file jitter.h.

 
#define SWAP_AX (  ) 

Value:

emitm(&stream, 0x86, 1); \
  emitm(&stream,  0xc4 , 1);
xchg al,ah

Definition at line 149 of file jitter.h.


Typedef Documentation

typedef UINT(__cdecl *) BPF_filter_function(PVOID *, ULONG, UINT)

Prototype of a filtering function created by the jitter.

The syntax and the meaning of the parameters is analogous to the one of bpf_filter(). Notice that the filter is not among the parameters, because it is hardwired in the function.

Definition at line 78 of file jitter.h.

typedef void(*) emit_func(binary_stream *stream, ULONG value, UINT n)

Prototype of the emit functions.

Different emit functions are used to create the reference table and to generate the actual filtering code. This allows to have simpler instruction macros. The first parameter is the stream that will receive the data. The secon one is a variable containing the data, the third one is the length, that can be 1,2 or 4 since it is possible to emit a byte, a short or a work at a time.

Definition at line 88 of file jitter.h.


documentation. Copyright (c) 2002-2005 Politecnico di Torino. Copyright (c) 2005-2007 CACE Technologies. All rights reserved.
2007 Translated By CoffeeCat Studio