「gSOAP, Pthreads-Win32, OpenSSL を使った
SOAP C/Sアプリ開発」
ボーランド株式会社
Developer Tools Group高橋智宏

Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

第３回 ボーランド デベロッパー キャンプ

講師紹介





高橋智宏
1973年生まれ、京都大学 法学部卒
学生の時購入したTurboC++2ndからの熱狂的なボーランドファン
参加しているメーリングリストやコミュニティ
 JBuilder ML,C++Builder ML,Delphi ML,C# ML,CORBA ML 等…
 ミクシィ http://mixi.jp/show_friend.pl?id=208738

 「Java読書会」を運営
 http://www.javareading.com/bof/

2
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

1第３回 ボーランド デベロッパー キャンプ

アジェンダ
 SOAPのおさらい






 プロトコル, WSDL, スタブ/スケルトン
IDL2WSDLコマンド
 IDLからWSDLを生成してみよう
gSOAP + Webサーバ
 とりあえずCGI形式で実装
 SOAPクライアントの作成
gSOAP + Pthreads-Win32
 CGIからマルチスレッドで動作する単体サーバに書き換える
gSOAP + Pthreads-Win32 + OpenSSL
 さらに SOAP over SSL を導入する
 DelphiクライアントからSSLで接続する
3
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

SOAPのおさらい

Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

2

第３回 ボーランド デベロッパー キャンプ

C/Sの形態

GUIアプリBDE etc…

 その1

TCP/IP

ドライバ

RDBMS

 その2 - 今回作成します
いろいろ

SOAP

GUIアプリTCP/IP

SOAP
over
HTTP

SOAPサーバ

TCP/IP

ドライバ

RDBMS

5
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

第３回 ボーランド デベロッパー キャンプ

一般的なSOAPのプロトコル
 XML形式のデータをHTTP上で送受信する
引数 X

クライアントHTTPリクエスト

サーバコードreturn Y;

Y = obj.Foo(X);

スタブ

スケルトン
戻り値 Y
HTTPレスポンス

SOAPライブラリ

SOAPライブラリ

6
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

3第３回 ボーランド デベロッパー キャンプ

WSDL
 Webサービス記述言語（Web Services Description Language）
 提供するWebサービスのインターフェース（メソッド等）を規定する
 WSDLファイルから、クライアント/サーバ各用のスタブ/スケルトンコードを生成する
WSDLファイル

クライアントY = obj.Foo(X);

スタブ

……
……
…..

サーバコードreturn Y;

SOAPライブラリ(A)SOAPライブラリ(B)

生成

生成

スケルトン

SOAPライブラリ(A)SOAPライブラリ(B)7Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

第３回 ボーランド デベロッパー キャンプ

一般的なSOAPサーバの形態
 Apache + CGIApacheCGITomcatxxx.class
Axis

IIS

アセンブリ
.NET

 Tomcat + Apache Axis(サーブレット) +実装クラス

 IIS + ASP.NET + 実装クラス

4

ASP.NET

Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

8

IDL2WSDLコマンド

Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

第３回 ボーランド デベロッパー キャンプ

WSDLの生成方法
 WSDLファイルの中身はXML形式。WSDLを直接手書きすることは無理 一般的にWSDLを生成するには、先に特定の実装言語でメソッド等を記述して、それをWSDLに変換する必要がある。時には配布＆実行まで必要な場合も…
Demo.wsdl<?xml version="1.0" encoding="UTF-8"?><wsdl:definitions targetNamespace="http://tempuri.org" xmlns:impl="http://tempuri.org" xmlns:intf="http://tempuri.org"
xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns1="http://CORBA.omg.org"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"><wsdl:types><schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://tempuri.org"><import namespace="http://CORBA.omg.org"/><import namespace="http://schemas.xmlsoap.org/soap/encoding/"/><complexType name="Employee"><sequence><element name="id" type="xsd:int"/><element name="data" nillable="true" type="soapenc:string"/></sequence></complexType><complexType name="NoSuchEmployee"><complexContent><extension base="tns1:UserException"><sequence><element name="reason" nillable="true" type="soapenc:string"/></sequence></extension></complexContent></complexType></schema><schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://CORBA.omg.org"><import namespace="http://tempuri.org"/><import namespace="http://schemas.xmlsoap.org/soap/encoding/"/><complexType abstract="true" name="UserException"><sequence/></complexType></schema></wsdl:types><wsdl:message name="findByPrimaryKeyRequest"><wsdl:part name="in0" type="xsd:int"/></wsdl:message><wsdl:message name="findByPrimaryKeyResponse"><wsdl:part name="findByPrimaryKeyReturn" type="impl:Employee"/></wsdl:message><wsdl:message name="NoSuchEmployee"><wsdl:part name="fault" type="impl:NoSuchEmployee"/></wsdl:message><wsdl:portType name="EmployeeManager"><wsdl:operation name="findByPrimaryKey" parameterOrder="in0">…
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

510

第３回 ボーランド デベロッパー キャンプ

そこで IDLファイルが使えないものかと…
 IDL – Interface Definition Language
 インターフェース(メソッド等)を定義するプラットフォーム非依存の言語
 前回の「第２回デベロッパーキャンプ」の資料を参考にしてください 先にIDLでインターフェースを記述しておいて、後でWSDLファイルに変換できないものか？
Demo.idl
社員番号から社員データを検索するインターフェース

module Demo {struct Employee {long id;
wstring data;};
exception NoSuchEmployee {wstring reason;
引数: 社員番号};interface EmployeeManager {Employee findByPrimaryKey(in long id) raises(NoSuchEmployee);};};
戻り値: 社員データ
11
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

第３回 ボーランド デベロッパー キャンプ

IDLからWSDLを生成するには

Borland VisiBroker 7.0 には IDLからWSDLファイル等を生成するコマンドが用意されているが…

 今回は、無償のもので代用します 用意するもの
 JDK（Java Development Kit）
 Apache Axis（特にその中の Java2WSDL コマンド） Web Services Description Language for Java Toolkit（WSDL4J）

 JavaMail API （※Apache Axisに必要） JavaBeans Activation Framework（JAF） （※Apache Axisに必要）

12
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

6

第３回 ボーランド デベロッパー キャンプ

IDLからWSDLを生成するには（続き）
 変換処理の流れ…

IDLファイル
idljコマンド.javaファイルjavacコマンド.classファイル
Java2WSDLクラス

WSDLファイル

13
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

第３回 ボーランド デベロッパー キャンプ

IDLからWSDLを生成する手順
 JDKをダウンロードしてインストール
 http://java.sun.com/j2se/1.4.2/download.html
 idljコマンド, javacコマンド, javaコマンドを使用します Apache Axis 1.4 をダウンロードして展開 http://ftp.kddilabs.jp/infosystems/apache/ws/axis/1_4/axis-bin-1_4.zip libフォルダ内のすべての.jarファイルを使用します JavaMail API 1.4 をダウンロードして展開 http://java.sun.com/products/javamail/downloads/index.html
 付属の mail.jar のみを使用します JavaBeans Activation Framework 1.0.2 をダウンロードして展開 http://java.sun.com/products/archive/javabeans/jaf102.html
 付属の activation.jar のみを使用します

14
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

7

第３回 ボーランド デベロッパー キャンプ

IDLからWSDLを生成する手順（続き）
 JDKのbinフォルダにPATHが通っていることを確認
 IDLファイル（先に紹介した Demo.idl ）を用意する
 idljコマンドで、Demo.idlファイルから、対応するJavaソースコードを生成 c:¥…>idlj Demo.idl
 findByPrimaryKey(int id) というメソッドを含んだ“Demo.EmployeeManagerOperations インターフェース” が生成される
 Demo¥EmployeeManagerOperations.java をコンパイルする c:¥…>javac Demo¥EmployeeManagerOperations.java
 Demo¥EmployeeManagerOperations.class 等が生成される

15
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

第３回 ボーランド デベロッパー キャンプ

IDLからWSDLを生成する手順（続き）
 Apache Axis の Java2WSDLクラス を利用するために、環境変数CLASSPATHを設定する
 カレントディレクトリ + Axisのlibフォルダにある全jarファイル + JavaMail API + JAF c:¥…>set CLASSPATH=.;C:¥axis-1_4¥lib¥axis.jar;C:¥axis-1_4¥lib¥axisant.jar;C:¥axis-1_4¥lib¥commons-discovery-0.2.jar;C:¥axis1_4¥lib¥commons-logging-1.0.4.jar;C:¥axis-1_4¥lib¥jaxrpc.jar;C:¥axis1_4¥lib¥log4j-1.2.8.jar;C:¥axis-1_4¥lib¥saaj.jar;C:¥axis-1_4¥lib¥wsdl4j1.5.1.jar;C:¥axis-1_4¥lib¥mail.jar;C:¥axis-1_4¥lib¥activation.jar

 Java2WSDLクラスを使って、Javaのクラス（今回はインターフェース）からWSDLファ
イルを生成する c:¥…>java org.apache.axis.wsdl.Java2WSDL -o Demo.wsdl -n
http://tempuri.org -l https://localhost:18081 -s EmployeeManager -b
EmployeeManagerSoapBinding -P EmployeeManager
Demo.EmployeeManagerOperations

16
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

8

第３回 ボーランド デベロッパー キャンプ

IDLからWSDLを生成する手順（続き）
 Java2WSDLクラスに必要なオプション

-o − 生成されるWSDLファイル名（例: Demo.wsdl ）-n − WSDL内で使用するXMLのnamespace （例: http://tempuri.org ）-l − WebサービスにアクセスするためのURL （例: https://localhost:18081 ）引数− WSDLに変換されるJavaクラス（例: Demo.EmployeeManagerOperations ）17
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

gSOAP（CGI形式） + Webサーバ

Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

9

第３回 ボーランド デベロッパー キャンプ

gSOAPって？
 WSDLも手に入って、いよいよWebサービスを作成してみます gSOAP 5年以上の歴史を持つのC/C++向け汎用SOAPライブラリ オープンソース、ライセンスはMPL1.1がベース
 Windows,各種UNIX,MacOSX、各種コンパイラに対応している
 構築に必要なファイルは、stdsoap2.cpp,stdsoap2.h のたった２個!!
 URL: http://www.cs.fsu.edu/~engelen/soap.html

 WSDLファイルを読み込んで、C/C++用のスタブ/スケルトンを生成するツールが付属 CGI形式、単独実行形式のサーバ、SSL（OpenSSL）をサポート
19
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

第３回 ボーランド デベロッパー キャンプ

gSOAP と 無償で使えるC++開発環境 を準備
 SourceForgeから最新の gSOAP 2.7.9 をダウンロードして展開 http://jaist.dl.sourceforge.net/sourceforge/gsoap2/gsoap_
win32_2.7.9.zip 日本語を含む文字列を char*（デフォルト）ではなく std::wstring として処理するため、設定ファイル <gSOAP_Dir>¥typemap.dat を編集する
コメントアウト# xsd__string = | char* | char*
xsd__string = | std::wstring | std::wstring
SOAP_ENC__string = | std::wstring | std::wstring

２行追加

 Turbo C++ Explorer版をダウンロードしてインストール
 http://www.borland.com/downloads/download_turbo.html
20
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

10

第３回 ボーランド デベロッパー キャンプCGIを作成する コンソールアプリケーションを新規作成する
 VCL は使わない マルチスレッド を使う（後の改良に備えて）
 gSOAPの「wsdl2hコマンド」を使って、WSDLファイル（Demo.wsdl）から、C言語のヘッダファイル
風な中間ファイル（Demo.h）を生成する
 c:¥…>wsdl2h -t <gSOAP_Dir>¥typemap.dat -o Demo.h Demo.wsdl
 gSOAPの「soapcpp2コマンド」を使って、中間ファイル（Demo.h）から、スケルトン（.cpp,.h等）
を生成する…
 c:¥…>soapcpp2 -S -L -I <gSOAP_Dir>¥import Demo.h
WSDLファイル
 soapC.cpp
 soapServer.cpp
 soapH.h EmployeeManagerSoapBinding.nsmap

wsdl2h (昔は無かった)
中間ファイルsoapcpp2

 プロジェクトに以下のファイルを追加

スケルトン

 soapC.cpp − スケルトン
 soapServer.cpp − スケルトン
 stdsoap2.cpp − gSOAP付属のSOAPライブラリ

SOAPライブラリ

CGI(.EXE)
21

Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

第３回 ボーランド デベロッパー キャンプCGIを作成する（続き）
 main関数と、Webサービスのサーバメソッドを実装#include "soapH.h"#include "EmployeeManagerSoapBinding.nsmap"
int main(int argc, char* argv[]){
struct soap* soap = soap̲new();soap̲serve(soap);
return 0;}

スケルトン用ヘッダ

CGI処理用（gSOAPのライブラリを使用）

SOAP̲FMAC5 int SOAP̲FMAC6 ns1̲̲findByPrimaryKey(struct soap* soap,
引数: 社員番号
int ̲in0,
struct ns1̲̲findByPrimaryKeyResponse &̲param̲1){
ns1̲̲Employee* employee = soap̲new̲ns1̲̲Employee(soap, -1);
戻り値保持用の構造体
try {
employee->id = ̲in0;
employee->data = L"たかはし";
戻り値: 社員データ構造体は専用の関数を使って new する}
delete はスケルトンが自動的に行う
catch(...) {soap̲delete̲ns1̲̲Employee(soap, employee);return soap̲sender̲fault(soap, "Error!!", NULL);}
̲param̲1.̲findByPrimaryKeyReturn = employee;
return SOAP̲OK;}
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

1122

第３回 ボーランド デベロッパー キャンプ

CGIを配布する
 Apache2.0.x をインストールし、CGIが利用できるよう設定変更し、起動する
 ビルドしたCGI（CPPServer.exe）を <Apache_Dir>¥cgi-bin 等に配布する
 他には、Cランタイム（cc3270mt.dll）が必要
 IE等のWebブラウザで、とりあえずWebサービスにアクセスしてみる もちろん、エラーを示すSOAPレスポンスが返るが、起動自体は成功！

23
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

SOAPクライアント（gSOAP）の作成

Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

12

第３回 ボーランド デベロッパー キャンプ

スタブおよびクライアントの生成 コンソールアプリケーションを新規作成する
 VCL は使わない

 gSOAPの「wsdl2hコマンド」を使って、WSDLファイル（Demo.wsdl）から、C言語のヘッダファイル

風な中間ファイル（Demo.h）を生成する
 c:¥…>wsdl2h -t <gSOAP_Dir>¥typemap.dat -o Demo.h Demo.wsdl
 gSOAPの「soapcpp2コマンド」を使って、中間ファイル（Demo.h）から、スタブ（.cpp,.h等）を生成する c:¥…>soapcpp2 -C -L -I <gSOAP_Dir>¥import Demo.h…
WSDLファイル

 soapC.cpp
 soapClient.cpp
 soapEmployeeManagerSoapBindingProxy.h EmployeeManagerSoapBinding.nsmap

wsdl2h (昔は無かった)
中間ファイル プロジェクトに以下のファイルを追加

soapcpp2

 soapC.cpp − スタブ soapClient.cpp − スタブ stdsoap2.cpp − gSOAP付属のSOAPライブラリ

スタブ

SOAPライブラリ

クライアント25
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

第３回 ボーランド デベロッパー キャンプ

クライアントコードを実装する
 main関数内に、Webサービスへのアクセスコードを実装…
#include "soapEmployeeManagerSoapBindingProxy.h"#include "EmployeeManagerSoapBinding.nsmap"

スタブ用ヘッダ

Webサービスアクセス用オブジェクト
int main(int argc, char* argv[]){
EmployeeManagerSoapBinding* service = new EmployeeManagerSoapBinding();

service->endpoint = "http://localhost/cgi-bin/CPPServer.exe";
引数: 社員番号
int id = 99;
ns1̲̲findByPrimaryKeyResponse resp;

戻り値保持用の構造体

int soap̲ret = service->ns1̲̲findByPrimaryKey(id, resp);
Webサービスのメソッドを呼び出す
if( soap̲ret == SOAP̲OK ){戻り値: 社員データの社員番号(99)を表示
cout << resp.̲findByPrimaryKeyReturn->id << endl;}
delete service;
return 0;}
26
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

13

第３回 ボーランド デベロッパー キャンプ

クライアントコードを実行する
 プロジェクトをビルドして実行する

 注意するポイント 通常、WebサービスへのアクセスポイントはWSDLファイル内で定義済み
 スタブのヘッダファイル「soapEmployeeManagerSoapBindingProxy.h」に自動的に埋め込まれる Webサービスへのアクセスポイントを独自に変更することも可能
例: service->endpoint = "http://localhost/cgi-bin/CPPServer.exe"; 社員データ(ns1__Employee型)内の std::wstring型メンバは、コンソールに正しく出力できないので、社員番号(int型)のみ出力しています 後ほどDelphi/BCBのGUIクライアントでWideString型として出力します27
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

POSIX Threads を使った単独サーバ

Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

14

第３回 ボーランド デベロッパー キャンプ

gSOAPの単独SOAPサーバとしての機能
 gSOAPはCGI形式をサポートしますが、SOAPサーバとしてApache等のWebサーバを別途必要とします gSOAPは、.exe単体でSOAPサーバの機能も提供しています 単独サーバのためのコードはとても簡単
 ただし、処理をマルチスレッド化する部分は直接は用意されていない
 デフォルトでは、同時に1リクエストしか処理できない！
 スレッドの生成、起動、破棄は自前で行う必要がある！！

 スレッドライブラリ Windowsでは、Win32 API を使うのが一般的
 CreateThreadや_beginthreadなど

 UNIXでは、POSIX Threads（Pthreads） を使うのが一般的 pthread_createなど
29
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

第３回 ボーランド デベロッパー キャンプ

Windowsで POSIX Threads（Pthreads） を使う
 Win32 API をそのまま使って、マルチスレッド化を実現しても良いが…
 gSOAPは、汎用的なC/C++用ライブラリだし…
 自分でWin32 APIを直接使うよりも、既存のライブラリを使ったほうが…

 そこで、POSIX Threads を Win32 API で実装したものを利用 Pthreads-Win32
 http://sourceware.org/pthreads-win32/
 オープンソース
 ライセンスは LGPL

30
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

15

第３回 ボーランド デベロッパー キャンプ

Pthreads-Win32 のセットアップ
 最新版 2.7.0 をダウンロードする ftp://sources.redhat.com/pub/pthreads-win32/pthreads-w32-2-7-0-release.exe c:¥pthreads2.7.0 等にインストールする ボーランドのインラインアセンブラ（TASM32）の機能を使うので、
c:¥pthreads2.7.0¥pthreads.2¥config.h を以下のように書き換える/*#undef HAVE̲TASM32*/#define HAVE̲TASM32

 c:¥pthreads2.7.0¥pthreads.2 に移動して、
 c:¥…>make -fBmakefile 必要があれば、ボーランド用のメイクファイル（Bmakefile）を編集する
 c:¥pthreads2.7.0¥pthreads.2 に DLLとインポートライブラリが生成される
 pthreadBC2.dll
 pthreadBC2.lib
31
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

第３回 ボーランド デベロッパー キャンプ

CGIを単独SOAPサーバへ変更する
main関数部...
#include <pthread.h>...
int main(int argc, char* argv[]){
localhostの80番ポートで起動する
struct soap soap;
soap̲init(&soap);
serversock = soap̲bind(&soap, "localhost", 80, 100);if( serversock < 0 ){soap̲print̲fault(&soap, stderr);
return -1;}
クライアントを受け付ける
for(;;) {int s = soap̲accept(&soap);
if( s < 0 )break;
SOAP用の構造体を複製
struct soap *tsoap = soap̲copy(&soap);
pthread̲t tid;
pthread̲create(&tid, NULL, process̲request, (void*)tsoap);}
soap̲end(&soap);
soap̲done(&soap);
return 0;

スレッドを起動し、スレッドにSOAP用の構造体を渡す}

32
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

16

第３回 ボーランド デベロッパー キャンプ

CGIを単独SOAPサーバへ変更する（続き）
スレッド実装部...
#include <pthread.h>...
static void *process̲request(void *tsoap){
pthread̲detach(pthread̲self());

スレッドのエントリポイント

struct soap* soap = (struct soap*)tsoap;
soap̲serve(soap);
ns1__findByPrimaryKeyメソッドを呼び出し
soap̲destroy(soap);
soap̲end(soap);
soap̲free(soap);
SOAP用の構造体を破棄

return NULL;}

 プロジェクトのインクルードディレクトリに「c:¥pthreads2.7.0¥pthreads.2」を追加する
 プロジェクトに、インポートライブラリ（pthreadBC2.lib）を追加してビルドする
33
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

第３回 ボーランド デベロッパー キャンプ

SOAPサーバ と SOAPクライアントを試す
 マルチスレッド版SOAPサーバ（CPPServer.exe）を起動する
 Cランタイム（cc3270mt.dll）が必要
 Pthreads-Win32のDLL（pthreadBC2.dll）も必要

 クライアントはアクセスするWebサービスのURLを変更してビルドするだけ 例: service->endpoint = "http://localhost/"; クライアントを起動する
 gSOAPサーバの注意点
 SOAPサーバをシャットダウンする処理は省きました soap_bind関数の戻り値（サーバソケット）をクローズします スレッドプールの機能は実装していません
34
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

17

さらに、SSL（OpenSSL）を使ったSOAPサーバへ

Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

第３回 ボーランド デベロッパー キャンプ

gSOAP と SSL（OpenSSL）
 gSOAPのライブラリファイル stdsoap2.cpp, stdsoap2.h は、SSL（OpenSSL）を使ったSOAP通信をサポートしている#ifdef WITH_OPENSSL…
#endif

 コンパイル時に WITH_OPENSSL の定義（define）が必要
 もちろん、OpenSSL のヘッダやライブラリ群も必要
 OpenSSL
 オープンソース
 http://www.openssl.org/
 ライセンスは Apache（BSD）スタイル
36
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

18

第３回 ボーランド デベロッパー キャンプ

OpenSSLのセットアップ
 最新の OpenSSL をダウンロードし、展開する
 http://www.openssl.org/source/openssl-0.9.8d.tar.gz

 makeファイルを生成するために Perl が必要なので、予めインストール
しておく OpenSSLのインストールディレクトリに移動し、makeファイルを生成し、ビルドする c:¥…>ms¥bcb4.bat c:¥…>make –fbcb.mak ヘッダファイル(.h)は、<OpenSSL_dir>¥inc32 に生成される
 各種コマンド(.exe)やスタティックライブラリ(.lib)は、<OpenSSL_dir>¥out32 に生成される
37
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

第３回 ボーランド デベロッパー キャンプ

SOAPサーバへの変更
main関数部
前半部...
int CRYPTO̲thread̲setup();
OpenSSLの初期化&クリーンアップ用の自作関数
void CRYPTO̲thread̲cleanup();...
int main(int argc, char* argv[]){soap̲ssl̲init();
OpenSSL関連の初期化
CRYPTO̲thread̲setup();struct soap soap;
soap̲init(&soap);
if( soap̲ssl̲server̲context(&soap,
SOAP̲SSL̲REQUIRE̲SERVER̲AUTHENTICATION,“server.pem”, // サーバ証明書と秘密鍵“password”, // パスワード
NULL,
NULL,
“dh512.pem”, // 鍵交換に DHE を使う（RSAではなく）
NULL,“sslserver”)) // SSLセッションの管理に使用するID{
soap̲print̲fault(&soap, stderr);
return -1;}
serversock = soap̲bind(&soap, "localhost", 18081, 100);if( serversock < 0 ){SSLは18081番ポートを使用
soap̲print̲fault(&soap, stderr);
return -1;}
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

19

SSLサーバのセットアップ

38

第３回 ボーランド デベロッパー キャンプ

SOAPサーバへの変更（続き）
main関数部
後半部

...
...
for(;;){
int s = soap̲accept(&soap);
if( s < 0 )break;
struct soap *tsoap = soap̲copy(&soap);
if( soap̲ssl̲accept(tsoap) ){SSLによるクライアントの受け付け処理
soap̲print̲fault(tsoap, stderr);soap̲end(tsoap);
soap̲free(tsoap);
continue;}
pthread̲t tid;
pthread̲create(&tid, NULL, process̲request, (void*)tsoap);

スレッドの起動に関する処理などはそのまま}
soap̲end(&soap);
soap̲done(&soap);
CRYPTO̲thread̲cleanup();

OpenSSL関連のクリーンアップ

return 0;}

39
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

第３回 ボーランド デベロッパー キャンプ

SOAPサーバへの変更（続き）
 OpenSSLは、マルチスレッド環境下での利用を想定しているものの、「スレッドの識別」「排他制御（ロック）」に関しては、利用者側が提供することを期待している 一定個数のロックオブジェクトを事前に生成する
 動的なロックのため、ロックオブジェクトを含んだ構造体を定義する
 OpenSSLに、ロック処理を実装した自作関数（５個）のアドレスを登録する

 OpenSSLの書籍やgSOAP付属のサンプルでは、排他制御（ロック）に関するコードを実装する際に「マクロ」を使っています#if defined(WIN32)# define MUTEX̲TYPE
HANDLE# define MUTEX̲SETUP(x)(x) = CreateMutex(NULL, FALSE, NULL)# define MUTEX̲CLEANUP(x) CloseHandle(x)# define MUTEX̲LOCK(x)WaitForSingleObject((x), INFINITE)# define MUTEX̲UNLOCK(x) ReleaseMutex(x)# define THREAD̲ID
GetCurrentThreadId()#else# define MUTEX̲TYPE
pthread̲mutex̲t# define MUTEX̲SETUP(x)pthread̲mutex̲init(&(x), NULL)# define MUTEX̲CLEANUP(x) pthread̲mutex̲destroy(&(x))# define MUTEX̲LOCK(x)pthread̲mutex̲lock(&(x))# define MUTEX̲UNLOCK(x) pthread̲mutex̲unlock(&(x))# define THREAD̲ID
pthread̲self()#endif

Windowsでは、Win32 API を使う

Win32用のPThreadsを手に入れたので、PThreadsに統一します
UNIXでは、PThreads を使う

40
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

20

第３回 ボーランド デベロッパー キャンプ

SOAPサーバへの変更（続き）
static pthread̲mutex̲t* mutex̲buf = NULL;OpenSSL関連のコード
前半部

static void locking̲function(int mode, int n, const char *file, int line){
if( mode & CRYPTO̲LOCK )pthread̲mutex̲lock(&(mutex̲buf[n]));else
pthread̲mutex̲unlock(&(mutex̲buf[n]));}struct CRYPTO̲dynlock̲value {pthread̲mutex̲t mutex;};
static CRYPTO̲dynlock̲value* dyn̲create̲function(const char *file, int line){
CRYPTO̲dynlock̲value* retval = (CRYPTO̲dynlock̲value*)malloc(sizeof(CRYPTO̲dynlock̲value));if( retval )pthread̲mutex̲init(&(retval->mutex), NULL);
return retval;}
static void dyn̲lock̲function(int mode, CRYPTO̲dynlock̲value* l, const char *file, int line){
if( mode & CRYPTO̲LOCK )pthread̲mutex̲lock(&(l->mutex));else
pthread̲mutex̲unlock(&(l->mutex));}static void dyn̲destroy̲function(CRYPTO̲dynlock̲value* l, const char *file, int line){
pthread̲mutex̲destroy(&(l->mutex));free(l);}41

Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

第３回 ボーランド デベロッパー キャンプ

SOAPサーバへの変更（続き）
OpenSSL関連のコード
後半部

static unsigned long id̲function(){#ifdef WIN32
return (unsigned long)GetCurrentThreadId();#else
return (unsigned long)pthread̲self();#endif}

Win32用PThreads実装では、pthead_selfの戻り値が、整数ではなく構造体として定義されているため、やむなくWin32 APIを使いました

int CRYPTO̲thread̲setup() {mutex̲buf = (pthread̲mutex̲t*)malloc(CRYPTO̲num̲locks() * sizeof(pthread̲mutex̲t));if( !mutex̲buf )return SOAP̲EOM;
for(int i = 0; i < CRYPTO̲num̲locks(); i++) {pthread̲mutex̲init(&(mutex̲buf[i]), NULL);}CRYPTO̲set̲id̲callback(id̲function);
CRYPTO̲set̲locking̲callback(locking̲function);
CRYPTO̲set̲dynlock̲create̲callback(dyn̲create̲function);
CRYPTO̲set̲dynlock̲lock̲callback(dyn̲lock̲function);
CRYPTO̲set̲dynlock̲destroy̲callback(dyn̲destroy̲function);
return SOAP̲OK;}
void CRYPTO̲thread̲cleanup() {if( !mutex̲buf )return;CRYPTO̲set̲id̲callback(NULL);CRYPTO̲set̲locking̲callback(NULL);CRYPTO̲set̲dynlock̲create̲callback(NULL);CRYPTO̲set̲dynlock̲lock̲callback(NULL);CRYPTO̲set̲dynlock̲destroy̲callback(NULL);
for(int i = 0; i < CRYPTO̲num̲locks(); i++) {pthread̲mutex̲destroy(&(mutex̲buf[i]));}free(mutex̲buf);
mutex̲buf = NULL;}
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

21

42

第３回 ボーランド デベロッパー キャンプ

サーバの証明書などを準備
 SSLに使用する証明書（server.pem）を作成
 opensslコマンドを使用し、ルート証明書とプライベートキーをPEM形式で格納c:¥...>openssl req -x509 -newkey rsa:1024 -out cacert.pem -outform PEM -config <OpenSSL>¥apps¥openssl.cnf
Loading 'screen' into random state - done
Generating a 1024 bit RSA private key.++++++........++++++
writing new private key to 'privkey.pem'
Enter PEM pass phrase:password
Verifying - Enter PEM pass phrase:password----You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
----Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Tokyo
Locality Name (eg, city) []:Shinjuku
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Borland
Organizational Unit Name (eg, section) []:DevCo
Common Name (eg, YOUR name) []:localhost
Email Address []:ttakahashi@borland.com
43c:¥...>cat cacert.pem privkey.pem > server.pem
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

第３回 ボーランド デベロッパー キャンプ

サーバの証明書などを準備（続き）
 SSLの鍵交換アルゴリズムに使用するパラメータ（dh512.pem）を作成する
c:¥...>openssl dhparam -2 512 -out dh512.pem
Loading 'screen' into random state - done
Generating DH parameters, 512 bit long safe prime, generator 2This is going to take a long time...........+........+....+.....................................................
.........++*++*++*++*++*++*

 gSOAPの soap_ssl_server_context 関数の引数に、“dh512.pem” ではなく
NULL を渡せば、鍵交換アルゴリズムに DHE ではなく RSA が使用されます

44
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

22

第３回 ボーランド デベロッパー キャンプ

SOAPサーバを実行する
 プロジェクトに、「WITH_OPENSSL」の定義を追加する
 プロジェクトのインクルードディレクトリに「<OpenSSL>¥inc32」を追加
する
 プロジェクトに、OpenSSLのライブラリを追加してビルドする libeay32.lib
 ssleay32.lib

 便宜上、SOAPサーバの実行ファイル（.exe）と同じフォルダに次のファ
イルを置く
 server.pem − サーバ証明書＋プライベートキー dh512.pem − 鍵交換用DHEパラメータ45
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

第３回 ボーランド デベロッパー キャンプ

SOAPサーバを実行する（続き）
 マルチスレッド & SSL対応版のSOAPサーバ（CPPServer.exe）を起動する
 Cランタイム（cc3270mt.dll）が必要
 Pthreads-Win32のDLL（pthreadBC2.dll）も必要
 OpenSSLのモジュールは、実行ファイル（.EXE）に含まれています IE等のWebブラウザで、とりあえずWebサービスにアクセスしてみる アクセスするURLの例：https://localhost:18081/
 信頼されない証明書であることを示す警告が出ますが…
 エラーを示すSOAPレスポンスが返るが、SOAPサーバへのアクセスは成功！

46
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

23

SSL（OpenSSL）を使ったSOAPクライアントへ

Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

第３回 ボーランド デベロッパー キャンプ

SOAPクライアントへの変更
main関数部…
int main(int argc, char* argv[]){soap̲ssl̲init();
OpenSSL関連の初期化
CRYPTO̲thread̲setup();
EmployeeManagerSoapBinding* service = new EmployeeManagerSoapBinding();
service->endpoint = "https://localhost:18081/";if( soap̲ssl̲client̲context(service->soap,
SOAP̲SSL̲REQUIRE̲SERVER̲AUTHENTICATION,
NULL,
NULL,
“cacert.pem”, // 信頼できるルート証明書
NULL,
NULL)){
soap̲print̲fault(service->soap, stderr);
return -1;}
int id = 99;
ns1̲̲findByPrimaryKeyResponse resp;
int soap̲ret = service->ns1̲̲findByPrimaryKey(id, resp);
if( soap̲ret == SOAP̲OK ){cout << resp.̲findByPrimaryKeyReturn->id << endl;}
delete service;
OpenSSL関連のクリーンアップ
CRYPTO̲thread̲cleanup();return 0;}

Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

24

SSLクライアントのセットアップ48

第３回 ボーランド デベロッパー キャンプ

SOAPクライアントへの変更（続き）
 OpenSSL関連のコード（初期化、ロック、クリーンアップなど）は、SOAPサーバとまったく同じです クライアントはアクセスするWebサービスのURLをSSL用に変更する必要があります 例: service->endpoint = "https://localhost:18081/"; プロジェクトに、「WITH_OPENSSL」の定義を追加する
 プロジェクトのインクルードディレクトリに「<OpenSSL>¥inc32」を追加する
 プロジェクトに、OpenSSLのライブラリを追加してビルドする libeay32.lib
 ssleay32.lib
 SOAPサーバを信頼するために、信頼できるルート証明書を使用します SOAPサーバセットアップ時に生成した cacert.pem を使用します 便宜上、 SOAPクライアントの実行ファイル（.exe）と同じフォルダに次のファイル
を置く

49
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

第３回 ボーランド デベロッパー キャンプ

SOAPクライアントの起動
 OpenSSLのモジュールは、実行ファイル（.EXE）に含まれています パケットモニタ（Ethereal）で、SSL通信を覗いてみました

暗号スイートは、TLS_DHE_RSA_WITH_AES_256_CBC_SHA

50
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

25

第３回 ボーランド デベロッパー キャンプ

gSOAP、OpenSSL 利用時の注意点（その１） gSOAPのsoapcpp2コマンドが、スタブ/スケルトン用のファイルとして生成する soapC.cpp では、そのままではコンパイルエラーが発生する場合がある
 Webサービスのメソッド名と同一名の構造体が混在しているため、ボーランドのC++コンパイ
ラが混乱するようです 修正例その1
 変更前：{ cp->ptr = (void*)new struct ns1̲̲findByPrimaryKey;
 変更後：{ cp->ptr = (void*)new (struct ns1̲̲findByPrimaryKey); 修正例その2
 変更前：{ cp->ptr = (void*)new struct ns1̲̲findByPrimaryKey[n]; 変更後：{ cp->ptr = (void*)new (struct ns1̲̲findByPrimaryKey[n]);51
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

第３回 ボーランド デベロッパー キャンプ

gSOAP、OpenSSL 利用時の注意点（その２） gSOAPに付属している stdsoap2.cpp は、最近のバージョンの OpenSSL とともに利用すると、コンパイルエラーが発生する場合がある
 最近のOpenSSLの一部のメソッドで、引数の型が変更されているためです 修正前：#if (OPENSSL̲VERSION̲NUMBER > 0x00907000L)...
ext̲data = ASN1̲item̲d2i(NULL, &data, ext‑>value‑>length, ASN1̲ITEM̲ptr(meth‑>it));...
ext̲data = meth‑>d2i(NULL, &data, ext‑>value‑>length);
...
#else

 修正後：#if (OPENSSL̲VERSION̲NUMBER > 0x00907000L)...
ext̲data = ASN1̲item̲d2i(NULL, (const unsigned char**)&data, ext‑>value‑>length,
ASN1̲ITEM̲ptr(meth‑>it));...
ext̲data = meth‑>d2i(NULL, (const unsigned char**)&data, ext‑>value‑>length);
...
#else
52
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

26

DelphiのVCL製SOAPクライアントから
gSOAPサーバ（SSL）にアクセスする

Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

第３回 ボーランド デベロッパー キャンプデモ
 SOAPサーバの証明書が自己署名の場合には、Delphi（VCL）の
SOAPコンポーネントからのアクセスは失敗する
 QualityCentralの#10823を参照
 http://qc.borland.com/wc/qcmain.aspx?d=10823

 IEを利用して、信頼されるルート証明機関として cacert.pem をイ
ンポートすればOK

54
Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

27

Thank you

Copyright (C) 2006, Borland Software Corporation. 本文書の一部または全部の転載を禁止します。

28