7.3 The ACE_Acceptor Class

来源:互联网 发布:网络协议的功能 编辑:程序博客网 时间:2024/05/17 04:23

7.3 The ACE_Acceptor Class

Motivation

Many connection-oriented server applications tightly couple their connection establishment and service initialization code in ways that make it hard to reuse existing code. For example, if you examine the Logging_Acceptor (page 58), Logging_Acceptor_Ex (page 67), Logging_Acceptor_WFMO (page 112), CLD_Acceptor (page 176), and TP_Logging_Acceptor (page 193) classes, you'll see that the handle_input() method was rewritten for each logging handler, even though the structure and behavior of the code was nearly identical. The ACE Acceptor-Connector framework defines the ACE_Acceptor class so that application developers needn't rewrite this code repeatedly.

许多面向连接的服务应用程序把连接建立和服务初始化紧密的结合在一起,很难重用现有的代码。举个例子,如果你是用Logging_Acceptor,Logging_Acceptor_Ex,Loggging_Acceptor_WFMO,CLD_Acceptor,和TP_Logging_Acceptor类,你可以看见handle_input()方法每一次都重写了,甚至代码的结构和行为几乎一致。ACE_Acceptor-Connector框架定义了ACE_Acceptor类,因此应用开发这不需要重复重写代码。

Class Capabilities

ACE_Acceptor is a factory that implements the Acceptor role in the Acceptor-Connector pattern [POSA2]. This class provides the following capabilities:

在Acceptor-Connector模式中ACE_Acceptor是一个实现Acceptor规则的工厂。这个类提供一下性能:

  • It decouples the passive connection establishment and service initialization logic from the processing performed by a service handler after it's connected and initialized.

    在它连接上和初始化后,service handler执行的处理中解除被动连接建立和服务初始化逻辑的耦合。

  • It provides a passive-mode IPC endpoint used to listen for and accept connections from peers. The type of this IPC endpoint can be parameterized with many of ACE's IPC wrapper facade classes, thereby separating lower-level connection mechanisms from application-level service initialization policies.

    他提供用来侦听和从对端接收连接的IPC端点。这个类型的IPC端点可以被许多ACE的IPC wrapper facade类参数化。因而从应用服务初始化策略中分离了低级的连接机制。

  • It automates the steps necessary to connect the IPC endpoint passively and create/activate its associated service handler.

    他自动执行被动连接到IPC对端必须的步骤和创建激活他相关的服务处理器。

  • Since ACE_Acceptor is derived from ACE_Service_Object, it inherits the event-handling and configuration capabilities described in Chapters 3 and 5.

    因为ACE_Acceptor从ACE_Service_Object继承,所以他继承了事件处理和配置性能,在Chapters 3和5中描述的。

The interface for ACE_Acceptor is shown in Figure 7.4. As shown in the figure, this class template is parameterized by:

ACE_Acceptor的接口显示在Figure 7.4中。按图所示,这个类模板被参数化:

Figure 7.4. The ACE_Acceptor Class

  • An SVC_HANDLER class, which provides an interface for processing services defined by clients, servers, or both client and server roles in peer-to-peer services. This parameter is instantiated by a subclass of the ACE_Svc_Handler class described in Section 7.2.

    一个SVC_HANDLER类,在点到点的服务中,提供一个处理客户端,服务端,或他们一起定义的服务规则的接口。这个参数可以被ACE_Svc_Handler的子类初始化,在Section 7.2中描述的。

  • A PEER_ACCEPTOR class, which is able to accept client connections passively. This parameter is often specified as one of the ACE IPC wrapper facades, such as the ACE_SOCK_Acceptor described in Chapter 3 of C++NPv1.

    PEER_ACCEPTOR类,能够被动接收客户端连接。这个参数经常被指定为ACE IPC wrapper facades类之一,例如在C++NPv1 Chapter 3中描述的 ACE_SOCK_Acceptor。

Since ACE_Acceptor is a descendant of ACE_Event_Handler, an instance of it can be registered with the ACE Reactor framework to process ACCEPT events. Its handle_input() method will be dispatched automatically by a reactor when a new connection request arrives from a client.

因为ACE_Acceptor是ACE_Event_Handler的后代,所以他的实例可以注册到ACE Reactor框架中处理ACCEPT事件。他的handle_input()方法会自动分发当一个连接请求到达。

The ACE_Acceptor class has a flexible interface that can be customized extensively by application developers. We therefore group the description of its methods into the two categories described below.

ACE_Acceptor类有灵活的接口,可以由开发者自定义扩展。我们因此将他的方法分成下面描述的两组。

1. Acceptor initialization, destruction, and accessor methods. The following methods are used to initialize and destroy an ACE_Acceptor:

Acceptor初始化,析够,和处理方法。下面方法被用来初始化和析够ACE_Acceptor:

Method

Description

ACE_Acceptor() open()

Bind an acceptor's passive-mode IPC endpoint to a particular address, such as a TCP port number and IP host address, then listen for the arrival of connection requests.

绑定一个acceptor的被动模式的IPC端点到一个特定的地址,例如TCP端口和IP地址,然后侦听到达的连接请求。

ACE_Acceptor() close()

Close the acceptor's IPC endpoint and release its resources.

关闭acceptor的IPC端点和释放他的资源。

acceptor()

Returns a reference to the underlying PEER_ACCEPTOR.

返回一个PEER_ACCEPTOR的引用。

A portion of ACE_Acceptor::open() is shown below:

1 template <class SVC_HANDLER, class PEER_ACCEPTOR> 2 int ACE_Acceptor<SVC_HANDLER, PEER_ACCEPTOR>::open 3     (const ACE_TYPENAME PEER_ACCEPTOR::PEER_ADDR &addr, 4      ACE_Reactor * = ACE_Reactor::instance (), 5      int flags = 0, 6      /* ... Other parameters omitted ... */) 7 { /* ... */ } 

Line 3 To designate the proper type of IPC addressing class, a PEER_ACCEPTOR template parameter must define a PEER_ADDR trait. Sidebar 5 in Chapter 3 in C++NPv1 illustrates how the ACE_SOCK_Acceptor class meets this criteria.

第三行,指定一个合适类型的IPC地址类,一个PEER_ACCEPTOR模板参数必须定义一个PEER_ADDR trait。C++NPv1 Chapter 3 Sidebar 5 解释了ACE_SOCK_Acceptor类符合这个标准。

Line 4 By default, the open() method uses the singleton ACE_Reactor to register the acceptor to handle ACCEPT events. This reactor can be changed on a per-instance basis, which is useful when a process uses multiple reactors, for example, one per thread.

第四行,缺省的open()方法使用ACE_Reactor单例注册acceptor来处理ACCEPT事件。

Line 5 The flags parameter indicates whether a service handler's IPC endpoint initialized by the acceptor should start in blocking mode (the default) or in nonblocking mode (ACE_NONBLOCK).

第伍行,flags参数指定service handler的IPC端点被acceptor初始化成阻塞模式或者异步模式。

2. Connection establishment and service handler initialization methods. The following ACE_Acceptor methods can be used to establish connections passively and initialize their associated service handlers:

连接建立和service handler初始化方法。下面ACE_Acceptor方法可以被用来建立被动连接和初始化他们相关的service handlers:

Method

Description

handle_input()

This template method is called by a reactor when a connection request arrives from a peer connector. It can use the three methods outlined below to automate the steps necessary to connect an IPC endpoint passively, and to create and activate its associated service handler.

这个模板方法被reactor调用当连接请求从对端connector发起。他可以使用3中下面的方法执行连接IPC端点必须的步骤,和创建和激活他相关的service handler。

make_svc_handler()

This factory method creates a service handler to process data requests emanating from its peer service handler via its connected IPC endpoint.

这个工厂方法创建一个service handler来处理由对端service handler通过连接的IPC端点发起的数据请求。

accept_svc_handler()

This hook method uses the acceptor's passive-mode IPC endpoint to create a connected IPC endpoint and encapsulate the endpoint with an I/O handle that's associated with the service handler.

这个hook方法使用acceptor的被动模式的IPC端点来创建连接的IPC端点,和封装和service handler相关联的I/O句柄。

activate_svc_handler()

This hook method invokes the service handler's open() hook method, which allows the service handler to finish initializing itself.

这个hook方法调用service handler的初始化他自己的open() hook方法。

Figure 7.5 (page 220) shows the default steps that an ACE_Acceptor performs in its handle_input() template method:

Figure 7.5. Steps in ACE_Acceptor Connection Acceptance

  1. It calls the make_svc_handler() factory method to create a service handler dynamically.

    调用make_svc_handler()工厂方法创建动态service handler。

  2. It calls the accept_svc_handler() hook method to accept a connection and store it in the service handler.

    调用accept_svc_handler() hook方法接收连接和将他存储在service handler中。

  3. It calls the activate_svc_handler() hook method to allow the service handler to finish initializing itself.

    调用activate_svc_handler() hook方法允许service handler初始化他自己。

Sidebar 47 (page 209) explains why the ACE_Acceptor::handle_input() template method decouples service handler creation from activation.

Sidebar 47(209页)解释了为什么ACE_Acceptor::handle_input()模板方法将创建从激活中decouple出来。

ACE_Acceptor::handle_input() uses the Template Method pattern [GoF] to allow application designers to change the behavior of any of the three steps outlined above. The default behaviors of make_svc_handler(), accept_svc_handler(), and activate_svc_handler() can therefore be overridden by subclasses. This design allows a range of behavior modification and customization to support many use cases. The three primary variation points in ACE_Acceptor::handle_input() are described and illustrated in more detail below.

ACE_Acceptor::handle_input()使用Template Method pattern来允许应用设计者改变上面三种步骤中的任何一个的行为。make_svc_handler(),accept_svc_handler(),和activate_svc_handler()的缺省的行为可以被子类重载。这个设计允许修改和自定义一定范围的行为以支持许多用例。三种主要变化指出ACE_Acceptor::handle_input()在下面详细的解释。

1. Service handler creation. The ACE_Acceptor::handle_input() template method calls the make_svc_handler() factory method to create a new service handler. The default implementation of make_svc_handler() is shown below:

Service handler创建。ACE_Acceptor::handle_input()模板方法调用make_svc_handler()工厂方法创建一个新的service handler。缺省的实现如下:

1 template <class SVC_HANDLER, class PEER_ACCEPTOR> int 2 ACE_Acceptor<SVC_HANDLER, PEER_ACCEPTOR>::make_svc_handler 3     (SVC_HANDLER *&sh) { 4   ACE_NEW_RETURN (sh,SVC_HANDLER, -1); 5   sh->reactor (reactor ()); 6   return 0; 7} 

Line 4 Allocate an instance of SVC_HANDLER dynamically. The SVC_HANDLER constructor should initialize any pointer data members to NULL to avoid subtle run-time problems that can otherwise arise if failures are detected in ACE_Acceptor::handle_input() template method and the SVC_HANDLER must be closed.

第四行,动态分配一个SVC_HANDLER的实例。SVC_HANDLER构造器应该初始化任何一个指针为NULL来避免敏感的运行时问题,如果在ACE_Acceptor::handle_input()模板方法发生失败,SVC_HANDLER必须关闭。

Line 5 Set the reactor of the newly created service handler to the same reactor associated with the acceptor.

第五行,设置新创建的service handler的reactor。

Subclasses can override make_svc_handler() to create service handlers in any way that they like, such as:

子类可以用许多方法来重载make_svc_handler()以创建service handlers,例如:

  • Creating service handlers based on some criteria, such as the number of CPUs available, a stored configuration parameter, calculated historical load average, or the current host workload.

    按照一些标准创建service handlers,例如可用的CPU的个数,一个配置参数,历史平局负载,或者当前主机的负荷。

  • Always returning a singleton service handler (page 247) or

    始终返回一个service handler的单例。

  • Dynamically linking the handler from a DLL by using the ACE_Service_Config or ACE_DLL classes described in Chapter 5.

    在Chapter 5中描述,使用ACE_Service_Config或者ACE_DLL类从DLL动态连接handle。

2. Connection establishment. The ACE_Acceptor::handle_input() template method calls the accept_svc_handler() hook method to passively accept a new connection from a peer connector. The default implementation of this method delegates to the PEER_ACCEPTOR::accept() method, as shown below:

连接建立。ACE_Acceptor::handle_input()模板调用accept_svc_handler() hook方法来被动接收对端connector的新的连接。这个方法缺省的实现委托给PEER_ACCEPTOR::accept()方法,如下所示:

template <class SVC_HANDLER, class PEER_ACCEPTOR> int ACE_Acceptor<SVC_HANDLER, PEER_ACCEPTOR>::accept_svc_handler     (SVC_HANDLER *sh) {   if (acceptor ().accept (sh->peer ()) == -1)   { sh->close (0); return -1; }   return 0; } 

For this accept_svc_handler() implementation to compile, the PEER_ACCEPTOR template parameter must have a public accept() method. ACE_SOCK_Acceptor (Chapter 3 of C++NPv1) meets this requirement, as do most ACE IPC wrapper facades.

为了accept_svc_handler()方法能够编译,PEER_ACCEPTOR模板参数必须有一个公共的accept()方法。ACE_SOCK_Acceptor(C++NPv1 Chapter 3)符合这个条件,如许多ACE IPC wrapper facades。

Subclasses can override accept_svc_handler() to add extra processing required before or after the connection is accepted, but before it can be used. For example, this method can authenticate a new connection before activating the service. The authentication process could validate the peer's host and/or port number, perform a login sequence, or set up an SSL session on the new socket. The Example section on page 222 illustrates how to implement authentication by overriding the accept_svc_handler() hook method to perform SSL authentication before activating the service. Use caution, however, when performing exchanges with the peer in this situation. If activate_svc_handler() is called via a reactor callback, the application's entire event dispatching loop may block for an unacceptably long amount of time.

子类可以重载accept_svc_handler()来增加在连接接收之前或者之后的额外的处理。例如这个方法可以在认证一个新的连接之前激活服务。这个认证处理可以检测对端的主机和端口,执行登陆的步骤,或者在socket上设置SSL。222页的例子解释了通过重载accept_svc_handler()如何实现认证,在激活服务前执行SSL认证。使用注意,然而,这种情况当与对端执行交换。如果activate_svc_handler()通过reactor回调被调用,应用程序的整个事件分发循环可能阻塞不可接受的一段时间。

3. Service handler activation. The ACE_Acceptor::handle_input() template method calls the activate_svc_handler() hook method to activate a new service after it has been created and a new connection has been accepted on its behalf. The default behavior of this method is shown below:

Service handler激活。在他被创建和新的连接被接受之后,ACE_Acceptor::handle_input()模板方法调用activate_svc_handler() hook方法来激活新的服务。缺省的方法如下所示:

 1 template <class SVC_HANDLER, class PEER_ACCEPTOR> int  2 ACE_Acceptor<SVC_HANDLER, PEER_ACCEPTOR>::activate_svc_handler  3     (SVC_HANDLER *sh) {  4   int result = 0;  5   if (ACE_BIT_ENABLED (flags_, ACE_NONBLOCK)) {  6     if (sh->peer ().enable (ACE_NONBLOCK) == -1)  7       result = -1;  8   } else if (sh->peer ().disable (ACE_NONBLOCK) == -1)  9     result = -1; 10 11   if (result == 0 && sh->open (this) == -1) 12     result = -1; 13   if (result == -1) sh->close (0); 14   return result; 15 } 

Lines 5? The blocking/nonblocking status of a service handler is set to reflect the flags stored by the acceptor in its constructor. If the acceptor's flag_ designates nonblocking mode, we enable nonblocking I/O on the service handler's peer stream. Otherwise, the peer stream is set to blocking mode.

第五行,service handler的阻塞和非阻塞状态在他的构造器中设置,反映在被acceptor存储的flags上。

Lines 11?4 The service handler's open() hook method is called to activate the handler (see page 209 for an example). If service activation fails, the service handler's close() hook method is called to release any resources associated with the service handler.

第十一行,serivce handler的open() hook方法被调用来激活handler。如果激活失败,service handler close() hook 方法被调用来释放任何与service handler相关的资源。

Subclasses can override activate_svc_handler() to activate the service in some other way, such as associating it with a thread pool or spawning a new process or thread to process data sent by clients. Since the ACE_Acceptor::handle_input() method is virtual it's possible (though rare) to change the sequence of steps performed to accept a connection and initialize a service handler. Regardless of whether the default ACE_Acceptor steps are used or not, the functionality of the service handler itself is decoupled completely from the steps used to passively connect and initialize it. This design maintains the modularity and separation of concerns that are so important to minimize the cost of the service's future maintenance and development.

子类可以重载activate_svc_handler()来服务,例如将他与线程池关联,或者创建一个新的进程,线程来处理客户端发送的数据。因为ACE_Acceptor::handle_input()方法是虚的,他可能改变接受连接和初始化service handler的执行步骤。不管缺省的ACE_Acceptor的步骤有没有被使用,service handler的功能完全的从被动连接和初始化中分离。这个设计维护了模块性和和分离关系,对减少以后的维护开发非常重要。

Example

This example is another variant of our server logging daemon. It uses the ACE_Acceptor instantiated with an ACE_SOCK_Acceptor to listen on a passive-mode TCP socket handle defined by the "ace_logger" service entry in the system's services database, which is usually /etc/services. This revision of the server uses the thread-per-connection concurrency model to handle multiple clients simultaneously.

这个例子是我们的server logging daemon的另一个变化。他使用被ACE_SOCK_Acceptor初始化的ACE_Acceptor在被动模式的TCP socket句柄上侦听,被ace_logger 在系统服务数据库通常是/etc/services中的服务项目定义。这个修订使用thread-per-connection并发模型来处理多个客户端同时连接。

As shown in Figure 7.6, the main thread uses a reactor to wait for new connection requests from clients. When a connection arrives, the acceptor uses the OpenSSL [Ope01] authentication protocol outlined in Sidebar 51 (page 224) to ensure that the client logging daemon is permitted to connect with the server. If the client is legitimate, the acceptor dynamically creates a TPC_Logging_Handler from the Example part of Section 7.2 to handle the connection. The TPC_Logging_Handler::open() method (page 214) spawns a thread to process log records sent by the client over the connection.

如Figure 7.6所示,主线程使用reactor来等待从客户端来的新的连接请求。当一个新的连接到达,acceptor使用OpenSSL认证协议来保证client logging daemon是允许连接到服务器的。如果客户端是合法的,acceptor动态创建一个TPC_Logging_Handler来处理连接。这个TPC_Logging_Handler::open()方法(页214)创建一个线程来处理由客户端发送的log记录

Figure 7.6. Architecture of the Thread-per-Connection Logging Server

Since much of the code is reused from the ACE Acceptor-Connector framework and OpenSSL library, this example mostly extends, instantiates, and uses existing capabilities. We subclass ACE_Acceptor and override its open() method and accept_svc_handler() hook method to define the server end of its authentication protocol. The TPC_Logging_Acceptor class and its protected data members are declared as follows:

因为许多ACE_Acceptor-Connectork framework和OpenSSL库中的代码被重用,这个例子扩展,实例化,和使用存在的性能。我们必须子类化ACE_Acceptor和重载他的open()方法和accept_svc_handler() hook方法来定义一个server在认证协议结束后。TPC_Logging_Acceptor类和他的保护成员声明如下 :

#include "ace/SOCK_Acceptor.h" #include <openssl/ssl.h> class TPC_Logging_Acceptor   : public ACE_Acceptor<TPC_Logging_Handler, ACE_SOCK_Acceptor> { protected:   // The SSL ''context'' data structure.   SSL_CTX *ssl_ctx_;   // The SSL data structure corresponding to authenticated   // SSL connections.   SSL *ssl_; 

The ssl_ctx_ and ssl_ data members are passed to the OpenSSL API calls made by the following public methods in TPC_Logging_Acceptor.

public:   typedef ACE_Acceptor<TPC_Log ging_Handler, ACE_SOCK_Acceptor>           PARENT;   typedef ACE_SOCK_Acceptor::PEER_ADDR  PEER_ADDR;   TPC_Logging_Acceptor (ACE_Reactor *)     : PARENT (r), ssl_ctx_ (0), ssl_ (0) {}   // Destructor frees the SSL resources.   virtual TPC_Logging_Acceptor (void) {     SSL_free (ssl_);     SSL_CTX_free (ssl_ctx_);   }   // Initialize the acceptor instance.   virtual int open     (const ACE_SOCK_Acceptor::PEER_ADDR &local_addr,     ACE_Reactor *reactor = ACE_Reactor::instance (),     int flags = 0, int use_select = 1, int reuse_addr = 1);   // <ACE_Reactor> close hook method.   virtual int handle_close     (ACE_HANDLE = ACE_INVALID_HANDLE,     ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK);   // Connection establishment and authentication hook method.   virtual int accept_svc_handler (TPC_Logging_Handler *sh); }; 

Sidebar 51: An Overview of Authentication and Encryption Protocols

To protect against potential attacks or third-party discovery, many networked applications must authenticate the identities of their peers and encrypt sensitive data sent over a network. To provide these capabilities, various cryptography packages, such as OpenSSL [Ope01], and security protocols, such as Transport Layer Security (TLS) [DA99], have been developed. These packages and protocols provide library calls that ensure authentication, data integrity, and confidentiality between two communicating applications. For example, the TLS protocol can encrypt/decrypt data sent/received across a TCP/IP network. TLS is based on an earlier protocol named the Secure Sockets Layer (SSL), which was developed by Netscape.

The OpenSSL toolkit used by the examples in this chapter is based on the SSLeay library written by Eric Young and Tim Hudson. It is open source, under active development, and runs on multiple platforms, including most platforms ACE supports, such as Linux, FreeBSD, OpenBSD, NetBSD, Solaris, AIX, IRIX, HP-UX, OpenUNIX, DG/UX, ReliantUNIX, UnixWare, Cray T90 and T3E, SCO Unix, Microsoft Windows, and MacOS. OpenSSL is a highly successful open-source package, as evidenced by its extensive commercial and noncommerical user community.

TPC_Logging_Acceptor::open() (in TPC_Logging_Server.cpp) initializes itself using its base class implementation and establishes the server's identity as follows:

TPC_Logging_Acceptor:open()(在TPC_Logging_Server.cpp中)使用基类的实现初始化自己,按照如下建立服务器端的认证:

 1 #include "ace/OS.h"  2 #include "Reactor_Logging_Server_Adapter.h"  3 #include "TPC_Logging_Server.h"  4 #include "TPCLS_export.h"  5  6 #if !defined (TPC_CERTIFICATE_FILENAME)  7 # define TPC_CERTIFICATE_FILENAME "tpc-cert.pem"  8 #endif /* !TPC_CERTIFICATE_FILENAME */  9 #if !defined (TPC_KEY_FILENAME) 10 # define TPC_KEY_FILENAME "tpc-key.pem" 11 #endif /* !TPC_KEY_FILENAME */ 12 13 int TPC_Logging_Acceptor::open 14     (const ACE_SOCK_Acceptor::PEER_ADDR &local_addr, 15            ACE_Reactor *reactor, 16            int flags, int use_select, int reuse_addr) { 17   if (PARENT::open (local_addr, reactor, flags, 18                     use_select, reuse_addr) != 0) 19     return -1; 20   OpenSSL_add_ssl_algorithms (); 21   ssl_ctx_ = SSL_CTX_new (SSLv3_server_method ()); 22   if (ssl_ctx_ == 0) return -1; 23 24   if (SSL_CTX_use_certificate_file (ssl_ctx_, 25                                     TPC_CERTIFICATE_FILENAME, 26                                     SSL_FILETYPE_PEM) <= 0 27       || SSL_CTX_use_PrivateKey_file (ssl_ctx_, 28                                       TPC_KEY_FILENAME, 29                                       SSL_FILETYPE_PEM) <= 0 30       || !SSL_CTX_check_private_key (ssl_ctx_)) 31     return -1; 32   ssl_ = SSL_new (ssl_ctx_); 33   return ssl_ == 0 ? -1 : 0; 34 } 

Lines 6?1 Since our logging server doesn't have a user interface, its server certificate and accompanying key are assumed to exist in a default set of files. However, the application may override the default filenames by defining the specified preprocessor macros.

第六行,因为我们的logging server没有用户界面,他的服务器证书和密钥假定在默认的文件中。应用程序可以通过预处理宏重载默认的文件名。

Lines 17?8 Initialize the ACE_Acceptor using the default open() implementation.

第十七,十八行,使用默认open()初始化ACE_Acceptor。

Line 20 Initialize the OpenSSL library. For brevity, we place the OpenSSL_add_ssl_algorithms() call in TPC_Logging_Acceptor::open(). Although this function can be called safely multiple times per process, ideally this call should be made only once per process. Initialization must be synchronized if multiple threads can call the function, however, since this OpenSSL function isn't thread safe.

第二十行,初始化OpenSSL库。为了简单,我们在TPC_Logging_Acceptor::open()中调用OpenSSL_add_ssl_algorithms()。虽然这个函数可以在每个进程中多次安全的调用,但是这个调用应该在一个进程中只调用一次。因为这个OpenSSL函数并不线程安全,所以如果多个线程调用他,初始化必须同步。

Lines 21?2 Set up for SSL version 3connection and create the SSL structure corresponding connections to be authenticated.

第二十一,二十二行,设置SSL V3连接和建立与连接一致的SSL结构。

Lines 24?1 Set up the certificate and accompanying private key used to identify the server when establishing connections and then verify that the private key matches the correct certificate. This code assumes that the certificate and key are encoded in Privacy Enhanced Mail (PEM) format within the specified files.

第二十四到三十一行,设置证书和用于鉴定服务器的私钥,然后检查私钥是否匹配证书。假定证书和密钥用PEM格式编码。

Lines 32?3 Initialize a new SSL data structure, which is used in the TPC_Logging_Acceptor::accept_svc_handler() hook method when establishing SSL connections via the OpenSSL API, as follows:

第三十二到三十三,初始化一个新的SSL结构体,TPC_Logging_Acceptor::accept_svc_handler()钩子方法当通过OpenSSL API建立SSL连接时被使用。

 1 int TPC_Logging_Acceptor::accept_svc_handler  2     (TPC_Logging_Handler *sh) {  3   if (PARENT::accept_svc_handler (sh) == -1) return -1;  4   SSL_clear (ssl_); // Reset for new SSL connection.  5   SSL_set_fd  6     (ssl_, ACE_reinterpret_cast (int, sh->get_handle ()));  7  8   SSL_set_verify  9     (ssl_, 10     SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 11     0); 12   if (SSL_accept (ssl_) == -1 13       || SSL_shutdown (ssl_) == -1) return -1; 14   return 0; 15 } 

Line 3 Accept the TCP connection using the default accept_svc_handler() implementation.

第三行,使用默认的accept_svc_handler()实现接受TCP连接。

Lines 4? Reset the SSL data structures for use with a new SSL connection.

第四行,清空SSL结构体,为了使用新的SSL连接。

Lines 8?1 Configure the SSL data structures so that client authentication is performed and enforced when accepting an SSL connection.

第八到十一行,配置SSL结构体使客户端认证被执行和强迫当接受SSL连接时。

Line 12 Perform the actual SSL connection and negotiation. If authentication of the client fails, the SSL_accept() call will fail.

第十二行,执行实际的SSL连接和协商。如果认证失败,SSL_accept()调用会失败。

Line 13 Shut down the SSL connection if authentication succeeds. Since we don't actually encrypt the log record data we simply communicate via the TCP stream from here on. If data encryption were required, we could use the ACE wrapper facades for OpenSSL described in Sidebar 52.

第十三行,关闭SSL连接如果认证成功。因为我们实际不加密log记录,我们简单的通过TCP流通讯。如果数据加密需要,我们应该使用Sidebar52中描述的ACE wrapper facades 。

By overriding the open() and accept_svc_handler() hook methods, we added authentication to our server logging daemon without affecting any other part of its implementation. This extensibility illustrates the power of the Template Method pattern used in the ACE_Acceptor class design.

通过重载open()和accept_svc_handler()钩子方法,我们增加了认证没有影响任何其他实现的部分。这个扩展解释了Template Method模式的使用,在ACE_Acceptor类的设计中。

When our example service is shut down via the ACE Service Configurator framework, Reactor_Logging_Server_Adapter::fini() (page 123) will end up calling the following handle_close() method:

当我们的服务通过ACE Service Configurator框架关闭,Reactor_Logging_Server_Adapter::fini()(123页)会调用下面的handle_close()方法:

int TPC_Logging_Acceptor::handle_close (ACE_HANDLE h,                                         ACE_Reactor_Mask mask) {   PARENT::handle_close (h, mask);   delete this;   return 0; } 

Sidebar 52: ACE Wrapper Facades for OpenSSL

Although the OpenSSL API provides a useful set of functions, it suffers from the usual problems incurred by native OS APIs written in C (see Chapter 2 in C++NPv1). To address these problems, ACE provides classes that encapsulate OpenSSL using an API similar to the ACE C++ Socket wrapper facades. For example, the ACE_SOCK_Acceptor, ACE_SOCK_Connector, and ACE_SOCK_Stream classes described in Chapter 3 of C++NPv1 have their SSL-enabled counterparts: ACE_SSL_SOCK_Acceptor, ACE_SSL_SOCK_Connector, and ACE_SSL_SOCK_Stream.

The ACE SSL wrapper facades allow networked applications to ensure the integrity and confidentiality of data exchanged across a network. They also follow the same structure and APIs as their Socket API counterparts, which makes it easy to replace them wholesale using C++ parameterized types and the ACE_Svc_Handler template class. For example, to apply the ACE wrapper facades for OpenSSL to our networked logging server we can simply remove all the OpenSSL API code and instantiate the ACE_Acceptor, ACE_Connector, and ACE_Svc_Handler with the ACE_SSL_SOCK_Acceptor, ACE_SSL_SOCK_Connector, and ACE_SSL_SOCK_Stream, respectively.

This method calls ACE_Acceptor::handle_close() to close the listening acceptor socket and unregister it from the reactor framework. To avoid memory leaks, the method then deletes this object, which was allocated dynamically when the service was initialized.

这个方法调用ACE_Acceptor::handle_close()来关闭侦听的acceptor socket和从reactor框架中注销。为了避免内存泄漏,这个方法然后删除他自己,在服务初始化时动态分配的

We finally create the TPC_Logging_Server type definition:

最后我们创建TPC_Logging_Server类型定义:

typedef Reactor_Logging_Server_Adapter<TPC_Logging_Acceptor>         TPC_Logging_Server; ACE_FACTORY_DEFINE (TPCLS, TPC_Logging_Server) 

We also use the ACE_FACTORY_DEFINE macro described in Sidebar 32 (page 136) to automatically generate the _make_TPC_Logging_Server() factory function, which is used in the following svc.conf file:

 

dynamic TPC_Logging_Server Service_Object * TPCLS:_make_TPC_Logging_Server() "$TPC_LOGGING_SERVER_PORT" 

This file directs the ACE Service Configurator framework to configure the thread-perconnection logging server via the following steps:

  1. It dynamically links the TPCLS DLL into the address space of the process.

  2. It uses the ACE_DLL class to extract the _make_TPC_Logging_Server() factory function from the TPCLS DLL symbol table.

  3. This function is called to allocate a TPC_Logging_Server dynamically and return a pointer to it.

  4. The ACE Service Configurator framework then calls TPC_Logging_Server::init() through this pointer, passing as its argc/argv argument an expansion of the TPC_LOGGING_SERVER_PORT environment variable that designates the port number where the logging server listens for client connection requests. The port number is ultimately passed down to the Reactor_Logging_Server constructor (page 83).

  5. If init() succeeds, the TPC_Logging_Server pointer is stored in the ACE_Service_Repository under the name "TPC_Logging_Server".

The various *Logging_Acceptor* classes written by hand for our previous logging server examples are no longer needed. Their purpose has been subsumed by TPC_Logging_Acceptor, which inherits from ACE_Acceptor. The first template argument to the ACE_Acceptor base class is TPC_Logging_Handler, which derives from ACE_Svc_Handler.

In the TPC_Logging_Server service, the ACE Acceptor-Connector framework performs most of the basic work of authenticating a client connection, as well as initializing and operating a service handler. Since the ACE_Acceptor refactors the functionality of accepting connections, authenticating clients, and activating service handlers into well-defined steps in its handle_input() template method, the source code for our logging server daemon shrank considerably. In particular, ACE_Acceptor supplied all of the code we previously had to write manually to

  • Listen for and accept connections

  • Create and activate new service handlers

Our thread-per-connection logging server also reused classes from earlier solutions that provided the following capabilities:

  • Initialize the network listener address using the Reactor_Logging_Server_Adapter template defined in Section 5.2 (page 122).

  • Dynamically configure the logging server and run the ACE Reactor's event loop in the main() function.

Therefore, the only code of any consequence we had to write was the TPC_Logging_Handler class (page 213), which spawned a thread per connection to receive and process Zlog records, and the TPC_Logging_Acceptor::accept_svc_handler() method (page 222), which implemented the server end of the protocol that authenticates the identity of the client and server logging daemons. Once again, due to the flexibility offered by the ACE Service Configurator framework, we simply reuse the Configurable_Logging_Server main program from Chapter 5.

     Ru-BrdPrevious Section Next Section www.bingnuo.net
    原创粉丝点击