プロが教えるわが家の防犯対策術!

ご存知であればお知恵を拝借させてください。
OpenSSLを使用したCプログラムの勉強をしていますが、SSL_write()でデータ送信を行う際に、ネットワーク切断などで送信に失敗した場合はタイムアウトさせたいと考えています。
ところが、SSL_write()ではselect()が上手く使えないと言う情報があって別のやり方を考えています。
一般的に、SSL_write()をタイムアウトさせようとした場合は、どのような方法を使うのでしょうか?
ご存知のかたがおられましたらご教授ください。

このQ&Aに関連する最新のQ&A

A 回答 (1件)

使ったことはありませんが…



SSL_set_timeout()というAPIがあるようです。
コレがSSL_write()にも効くのかどうかは不明ですが…。
ほかにも何種類かset_timeout()があります。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
set_timeout()を使ってみたのですが、セッションのタイムアウトのためようでこれでは検出できないみたいでした。
SSL_write()でブロックしてしまいます。

お礼日時:2008/11/29 08:35

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Q初級者の質問――time_tについて

私はC言語の初級者です。

time関数というのは現在時刻をtime_t型で返すものですよね。
でも、私はこの意味がよくわかりません。

time_t型とは何でしょうか。

単なる整数なのでしょうか。
確か、time_t型というのは整数で、
1970年1月1日0時からの秒数(世界標準時)だと聞いた気がします。

しかし、(いくつか見てみましたが)大抵のC言語の本では、そういう説明はしていません。
「プログラミング言語C」(カーニハン、リッチー)という本では、
「timeは現在のカレンダー時間を返す。」
と説明しています。
「じゃあ、カレンダー時間って何?」と思いますが、「カレンダー時間」というものの説明は見当たりません。

time_tというのは整数と考えてよいのでしょうか。
time_tで変数宣言すると、プログラムを読む人が「あ、これは時間を表すんだな」とわかり易いから、time_tというものがあるのでしょうか。

それとも、
time_tが秒数を表すかどうかは処理系に依存するのでしょうか。

もし、1970年1月1日からの秒数を表すなら、time関数の戻り値を1年間の秒数で割って1970に足せば今何年かわかるプログラムになりそうですよね。(うるう年や時差は考慮する)
それとも、それは処理系によっては正しく動かないプログラムになるのでしょうか。
(あくまでも考え方です。確か、time_tを渡せば年月日時分秒を返す関数があると思います。)



ちなみに、おとといプログラムを作ってtime関数の戻り値を10進数で表示すると次のようになりました。(VC++)


==============プログラム==============

#include <stdio.h>
#include <time.h>

int main(void)
{
time_t a;
a=time(NULL);
printf("%d\n",a);

return(0);
}

================結果===============

1005300371

私はC言語の初級者です。

time関数というのは現在時刻をtime_t型で返すものですよね。
でも、私はこの意味がよくわかりません。

time_t型とは何でしょうか。

単なる整数なのでしょうか。
確か、time_t型というのは整数で、
1970年1月1日0時からの秒数(世界標準時)だと聞いた気がします。

しかし、(いくつか見てみましたが)大抵のC言語の本では、そういう説明はしていません。
「プログラミング言語C」(カーニハン、リッチー)という本では、
「timeは現在のカレンダー時間を返す。」
と...続きを読む

Aベストアンサー

> C99とは、ISOの規格で比較的新しいものと思います。

そうです。
正式にはISO/IEC 9899:1999です。

> (C98というのは知りませんでした。)
失礼しました。
C89の間違いです。
同様にISO/IEC 9899:1989です。

> しかし、時間の起点が2000年1月1日であっても、秒数でなくて日数であっても、かまわないのでしょうか
時間の起点(というか、時間の管理方法)は time()の管轄であり、型であるtime_tは「time()が返す値を表現できること」が要求されているに過ぎません。
また、「1970年1月1日0時0分0秒からの経過秒数」というのは慣例に過ぎません。

とはいえ、UNIXを起源とする『time_tはlong』と『time()は1970年1月1日0時0分0秒からの経過秒数』という約束事は変えられる事は無いでしょう。
C98/C89との互換性を保ちながら新規格を作ることが予想されるからです(そうでなければlong longなどという型は作らないはず)。
その意味でyoushirさんのおっしゃるとおりだと思います。

> C99とは、ISOの規格で比較的新しいものと思います。

そうです。
正式にはISO/IEC 9899:1999です。

> (C98というのは知りませんでした。)
失礼しました。
C89の間違いです。
同様にISO/IEC 9899:1989です。

> しかし、時間の起点が2000年1月1日であっても、秒数でなくて日数であっても、かまわないのでしょうか
時間の起点(というか、時間の管理方法)は time()の管轄であり、型であるtime_tは「time()が返す値を表現できること」が要求されているに過ぎません。
また、「1970年1月1日0...続きを読む

QLinuxのgccのインクルードパス?

Linuxのgccで、インクルードファイルやライブラリのパスを設定する方法が知りたいのですが、gccについて詳しい書籍やサイトがありましたら、教えてください。

gccとccの違いも知りたいです。

例)
#include "example.h"

このままだと、example.hが無いと表示されます。

Aベストアンサー

標準ライブラリのパスは、gccのインストール時に指定して、Cプリプロセッサの中に組み込まれます。

#include "example.h"
は、まずカレントディレクトリを探し、次に gccコマンドラインの -I オプションで指定したディレクトリを探し、最後に標準ライブラリが探されます。

#include <example.h>
は、カレントディレクトリを探さない点が異なります。

ccも基本的には同じですが、Unixの種類によって機能が異なる可能性があります。Linuxの場合はcc=gccです。

Qアプリケーション終了時例外エラー(アクセス違反)の調査方法について

大変困っています。

アプリケーションが終了するときに「アクセス違反」がワトソン博士によって取得されています。
当方アプリケーションなどに弱く、解決策の想像が付きません。どなたかご教授お願いいたします。

<解決策例>
・どういったスキルを持った人にどの様な調査を進めさせれば良いのか。。。
・以前同様な事があり原因は○○だった
・恐らく○○だろう
 など、お願いいたします。

<ユーザ報告>
処理終了し、画面が消えたところでワトソン博士のメッセージが表示された

<ログ抜粋>
例外番号c0000005(アクセス違反)

ファンクション:RtlDestroyHeap
~略~
フォールト → 77f6d672 8908 mov [eax],ecx ds:09000001=00000000

<備考>
開発環境:MSVC6.0
動作環境:Windows NT4.0 SP6a
発生頻度:2回/年
使用頻度:2~3回/(平日)

以上、よろしくお願いします。

Aベストアンサー

発生頻度が年2回というのはなかなか厳しい条件ですね。

さて・・・

「私であれば、次の手順で調査を行います。」という書き始めで延々とデバッグ方法を書いていたのですが、書き終わってからちょっとGoogleで検索したら、ひょっとするとちょうど質問者さんのトラブルと同じかもしれない現象がMicrosoftのKBにありました。

場所はここです: http://support.microsoft.com/kb/168006/ja

要点をかいつまんで書くと、MSVCRT/MFCのDLLのバージョン不整合でエラーが発生することがある、という内容です。KB自体は特定のアプリケーションについて書かれていますが、記述されている現象と原因の関係から考えるに、他のアプリケーションでも同様の現象が発生すると思われます。

さてさて。

せっかく書いた文章を捨てるのがもったいないので(貧乏性)、邪魔かもしれませんが下に続けることにします。もし上のKBの内容がそれらしいようであれば、読み飛ばしてください。

========

私であれば、次の手順で調査を行います。

1. MAPファイル、CODファイル作成

「ワトソン博士のログを取得した際に実行していたEXEファイル」をビルドした際、一緒にMAPファイルやCODファイル(リスティングファイル)を作成していれば、そのファイルを用意しておきます。

もし作成していない場合は、「ワトソン博士のログを取得したEXEファイル」と、バイナリレベルで全く同じEXEファイル(バイト単位で比較すると、ファイルに埋め込まれたタイムスタンプ・チェックサム以外は一致する)が作成可能かどうか調べます。(ビルドに必要なソースファイルやビルドオプションに変更を加えていなければ作成可能です。)

作成可能であれば、コンパイルオプションに「リスティングファイルタイプ:マシン語コードとソースを含む」、リンクオプションに「MAPファイル作成」を追加してEXEを再作成してください。これで、「ワトソン博士のログを取得した際に実行していたEXEファイル」に対応するMAPファイルとCODファイルが得られます。

2. エラー発生行を特定

ワトソン博士のログがどれだけ取れているかにもよりますが、スタックダンプが含まれていればたいていエラー発生行を特定できます。

まず「フォールト->」が含まれる逆アセンブルリストを探します。次に、その下にある「スタックバックトレース」を探します。

スタックバックトレースを上から下に順にたどっていくと、そのうち「ReturnAd」(リターンアドレス)がアプリケーションのアドレス範囲(VC++6の標準オプション設定を変更していなければ0x00400000~)に入るところが出てきます。見つかったら、そのアドレスの直前にあるcall命令が例外を発生させたAPIを直接呼び出している場所です。

さて、仮にリターンアドレスが0x00401234だったとします。そうしたら、次はMAPファイルを見てこのアドレスがどの関数に属しているか探します。ちょうど0x00401234というアドレスは見つからないでしょうけれども、これに近いアドレスは見つかるはずです。そのアドレスに対応する関数名もMAPファイルにあります。

次はその関数名をCODファイルから探します。見つかったら、MAPファイルにあるアドレスがCODファイルにあるマシン語コードの先頭アドレスになるので、そこからリターンアドレス0x00401234に対応するはずの場所まで順番にアドレスを辿っていきます。関数の先頭アドレスが0x00401200であれば、0x34バイト先を探すわけです。

そうすると、その探した場所にある命令の直前の命令がcall命令になっているはずです。CODファイルには、その場所のC++ソースでの行番号とソース文もコメントとして入っているはずなので、あとは対応するソースをよーく見てエラーの見当をつけてください。

アセンブラの知識があれば、そこでcallを使った(他の関数を呼び出した)ときの引数の内容もある程度分かります。(ポインタ渡しだと、そのポインタの先の内容までは分かりませんが。)

3. 置き換え用EXEファイルと対応するMAPファイル作成

これ以降は将来への備えです。

コンパイルオプションでデバッグ情報を「プログラムデータベースを使用」、リスティングファイルタイプを「マシン語コードとソースを含む」、リンクオプションで「MAPファイルを作成する」、デバッグ情報「他の種類」を追加してビルドし、出来たEXEファイルを本番用として使用します。同時に作成されるMAPファイル、CODファイル、PDBファイルは保管しておきます。

MAPファイル、CODファイルの使い方は上記2.のとおりです。PDBファイルは、もし完全なクラッシュダンプが取得できればWinDbgを使って事後ソースレベルデバッグが可能になりデバッグ作業が非常に楽になるので、念のため取っておきます。

4. ワトソン博士のオプション変更

drwtsn32.exeを起動し、「クラッシュダンプファイルの作成」をチェックします。(デフォルトは、チェックが入っています。)

クラッシュダンプファイルとEXEとPDBがあればWinDbgで事後ソースレベルデバッグができます。(いわゆるポストモーテムデバッグです。UNIX系でコアダンプしたコアをデバッガで読み込んでデバッグするのと同じ種類のものです。)


普段何とも思わずに行っていることでも、文章にすると長いですね・・・

えーと、「どういうスキルを持った人に調査させればいいか」については、上記の内容を読んで『なるほど!』と言える人でしょうか。

参考URL:http://support.microsoft.com/kb/168006/ja

発生頻度が年2回というのはなかなか厳しい条件ですね。

さて・・・

「私であれば、次の手順で調査を行います。」という書き始めで延々とデバッグ方法を書いていたのですが、書き終わってからちょっとGoogleで検索したら、ひょっとするとちょうど質問者さんのトラブルと同じかもしれない現象がMicrosoftのKBにありました。

場所はここです: http://support.microsoft.com/kb/168006/ja

要点をかいつまんで書くと、MSVCRT/MFCのDLLのバージョン不整合でエラーが発生することがある、という内容です。KB...続きを読む

QDWORDの実際の型は何でしょうか

VC++.NETの環境です。
DOWRD dw1 = 1;
int i = 2; と定義し
ここで
if ( i > dw1 ){
何かの処理;
}
とコーディングすると
warning C4018: '>' : signed と unsigned の数値を比較しようとしました。
のワーニングがでます。
これは、DWORDがint型でなくunsigned int型のようにも見えます。
ある本によれば(VC++.V.NET逆引き大全500の極意)
DWORD はint型であると記述されています。
もし、int型ならこのワーニングはでないはずなのですが、
なぜでるのでしょうか。又、DWORDの実際の型は何なのでしょうか。ご存じのかたおりましたら、教えていただけませんでしょうか。

Aベストアンサー

型定義が知りたいのならば、宣言ファイルを見れば疑問を挟む余地もありません。
DWORD型はwindef.hで
"typedef unsigned long DWORD;"
と宣言されています。

Visual Studioを使っているのならば、知りたい型の上にマウスポインタを置いて右クリック、ポップアップメニューの「定義へ移動」または「宣言へ移動」で簡単に知ることが出来ます。

QLinux バイナリ実行できない "cannot execute binary file”

表記ですが、Linuxサーバーに対して、Windowsクライアントから
XWin環境にてユーザー"hoge"でログインを行い、
そのサーバー上でターミナルを立ち上げ
/usr/local/gcc_work
というフォルダを作り、その中で

---ここからーーー
#include <stdio.h>
int main(void)
{
printf("Hello,world\n");
return 1;
}
ーーーここまでーーー

のような、hello.cを作成し、

$ gcc -c hello.c -o hello
でバイナリを作成し

$ ./hello
とすると
bash: ./hello: cannot execute binary file

とのメッセージが出ます。
パーミッションの問題かと思いましたが、
[hoge@localhost gcc_work]$ ls -l
合計 8
-rwxrwxr-x 1 hoge hoge 876 5月 6 18:14 hello
-rwxrwxr-x 1 hoge hoge 83 5月 6 18:13 hello.c

のようになっていて、問題なく感じています。
スーパーユーザになって再度コンパイルしても同じでした。
くだらないところで躓いているのかもしれませんが、お気づきあらば
教授願います。

表記ですが、Linuxサーバーに対して、Windowsクライアントから
XWin環境にてユーザー"hoge"でログインを行い、
そのサーバー上でターミナルを立ち上げ
/usr/local/gcc_work
というフォルダを作り、その中で

---ここからーーー
#include <stdio.h>
int main(void)
{
printf("Hello,world\n");
return 1;
}
ーーーここまでーーー

のような、hello.cを作成し、

$ gcc -c hello.c -o hello
でバイナリを作成し

$ ./hello
とすると
bash: ./hello: cannot execute binary file

と...続きを読む

Aベストアンサー

> $ gcc -c hello.c -o hello

-c オプションをつけたときは実行ファイルまでは作らずに、オブジェクトファイル
(通常は .oの拡張子を持つもの)を作るだけですよ。
それは実行可能形式のファイルじゃありません。

file hello

とかしてみてください。
素直に -c オプションをつけずに

$ gcc hello.c -o hello

で実行可能な hello ができると思いますよ。

QSSL_connect(ssl)

お世話になっています。
VC++2005、MFC、Win7、openssl で作業しています。

Gメールから、POP3S 接続でメールを受け取りたいと考えています。
メールヘッダーの受信後に、本文を取り出す前に接続が切れます。

最初に、接続の部分ですが、問題点がありましたら、アドバイスをください。

void CSQMailBoxTreeView::GmailMailDL(){
int nReturnCode;
WSADATA wsaData;
CFileException fileExpection;
#define MAJOR_VERSION_REQUIRED 1
#define MINOR_VERSION_REQUIRED 1

struct sockaddr_in server;


std::string req; // リクエスト
std::string res; // レスポンス
std::string host_url = "pop.googlemail.com";


strcpy_s(gszGmailServerName,(LPCTSTR)oc_Gmailpop3servername);
if(strlen(gszGmailServerName)==0){
MessageBox("設定 - Gmail POP3サーバー から、\n受信メール(POP3)サーバを\n入力して下さい。","POP Server", MB_OK);
}
strcpy_s(gszGmailUserId, (LPCTSTR)oc_Gmailpop3userid);
if(strlen(gszGmailUserId)==0){
MessageBox("設定 - Gmail POP3サーバー から、\nメールサーバのユーザ名を\n入力してください。","POP User ID", MB_OK);
}
strcpy_s(gszGmailPassword, (LPCTSTR)oc_Gmailpop3password);
if(strlen(gszGmailPassword)==0){
MessageBox("設定 - Gmail POP3サーバー から、\nパスワードを入力してください。","警告 PassWord", MB_OK);
}
strcpy_s(gszGmailPOP3Port, (LPCTSTR)oc_Gmailpop3port);
if(strlen(gszGmailPassword)==0){
MessageBox("設定 - Gmail POP3サーバー から、\nポート番号を入力してください。","POP3 PortNumber", MB_OK);
}

// Prepare version for WSAStartup()
WORD wVersionRequired = MAKEWORD(MAJOR_VERSION_REQUIRED, MINOR_VERSION_REQUIRED);
// Initialize the WinSock DLL
nReturnCode = WSAStartup(wVersionRequired, &wsaData);
if (nReturnCode != 0 ){
MessageBox("Error on WSAStartup()","CheckGMail", MB_OK);
return ;
}
// Confirm that the version requested is available.
if (wsaData.wVersion != wVersionRequired){
// Version needed is not available.
MessageBox("Wrong WinSock Version","CheckGMail", MB_OK);
WSACleanup();
return ;
}

sock = socket(AF_INET, SOCK_STREAM, 0);

server.sin_family = AF_INET;
server.sin_port = htons(995);

server.sin_addr.S_un.S_addr = inet_addr(host_url.c_str());
if (server.sin_addr.S_un.S_addr == 0xffffffff) {
struct hostent *host;
unsigned int **addrptr;

host = gethostbyname(host_url.c_str());
if (host == NULL) {
return ;
}

addrptr = (unsigned int **)host->h_addr_list;
while (*addrptr != NULL) {
server.sin_addr.S_un.S_addr = *(*addrptr);
if (connect(sock, (struct sockaddr *)&server, sizeof(server)) == 0) {
break;
}
}
if (*addrptr == NULL) {
sprintf_s(outbuf3, "Fatal error: unable to connect to the server.\n");
MessageBox(outbuf3,"Error", MB_OK);
WSACleanup();
return;// -1;
}
}
else {
if (connect(sock, (struct sockaddr *)&server, sizeof(server)) != 0){
return ;
}
}

SSL_load_error_strings();
SSL_library_init();
ctx = SSL_CTX_new(TLSv1_method());
if (ctx == NULL) {
return;// 1;
}

ssl = SSL_new(ctx);
if (ssl == NULL) {
return;// 1;
}

if (SSL_set_fd(ssl, sock) == 0) {
return;// 1;
}

RAND_poll();

while (RAND_status() == 0) {
unsigned short rand_ret = rand() % 65536;
RAND_seed(&rand_ret, sizeof(rand_ret));
}

int ev = SSL_connect(ssl);
if ( ev != 1) {
int ret = SSL_get_error(ssl, ev);
if(ret <= 0){
ERR_print_errors_fp(stderr);
return;// 1;
}
}

if (WSAAsyncSelect(sock, *this, SM_GASYNC3,
FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE) == SOCKET_ERROR){
MessageBox("WSAAsyncSelect() failed","Error", MB_OK);
closesocket(sock);
sock = INVALID_SOCKET;
return;
}

gnAppState = STATE_CONNECTING;
}

お世話になっています。
VC++2005、MFC、Win7、openssl で作業しています。

Gメールから、POP3S 接続でメールを受け取りたいと考えています。
メールヘッダーの受信後に、本文を取り出す前に接続が切れます。

最初に、接続の部分ですが、問題点がありましたら、アドバイスをください。

void CSQMailBoxTreeView::GmailMailDL(){
int nReturnCode;
WSADATA wsaData;
CFileException fileExpection;
#define MAJOR_VERSION_REQUIRED 1
#define MINOR_VERSION_REQUIRED 1

struct sockaddr_in server;


...続きを読む

Aベストアンサー

RETRコマンドで読み取り完了したら、そのメールを削除して、QUITコマンドで切断していますから1通しか読み込めないのは想定内の動作のハズですけど、そこらヘンはどうなんですかね?

CSQMailBoxTreeView::GmailProcessData()の呼び出し方次第ではココも正常動作が期待できませんが…。

前回の回答でも指摘しましたが普通のPOP3で正しく動作するもの作ってからの方がいいと思われますが…。
その際、LAN内の別マシンにPOP3サーバを構築すればWireSharkなどでパケットの内容は確認できますし。
# GmailのPOP3って…bad commandで切断されるのね……

あと…MessageBox()でもろもろの通知を出すと「そこで処理が止まる」ので通信扱う場合だと問題が発生することもありますのでご注意を。
# 私ならTRACE()やその類使いますね。(Win32SDKなんでOutputDebugString()ですが…)

QPOP3S

VC++2005,openssl、Win7 で作業しています。

Gメールのサーバーに POP3S で接続して
メールを取り出したいと思っています。

とりあえず、サーバーからは

+OK Gpop ready for requset from ......

と返事が来ました。
POP3S での、サーバーとのやりとりについて
解説してある資料を探しています。

ご存知の方よろしくご指導下さい。
お願いいたします。

Aベストアンサー

SSL以前の問題ですね。

> while (1) {
> char buf[1024] = {0};
> if (SSL_read(ssl, buf, sizeof(buf)-1) <= 0)
> break;
> res += buf;
> }

よくこれでブロックしないですね。
SSL_readでタイムアウトして切断されるまで待たされて、タイムアウトした所でSSL_read < 0となってループを抜ける事になりそうですが。
このコードだと、POP3Sではなく普通にread/writeを使ってPOP3を話すプログラムを書いても動かないと思います。

もし、「ブロック???」と思うなら、次のページでも読んでみると良いでしょう。
http://msdn.microsoft.com/ja-jp/library/3tbz7kf5%28v=vs.80%29.aspx


まず、ブロッキングで書くとしたら、サーバーから返ってくる文字列をちゃんと確認して、CRLF (\r\n)が来ていた場合はループから抜けるようにしましょう。

例えばこんな感じ?
size_t crlf_pos;
while (1) {
char buf2[1024] = {0};
if ((crlf_pos = res.find("\r\n")) != string::npos || SSL_read(ssl, buf2, sizeof(buf2)-1) <= 0)
break;
res += buf2;
}
cout << res.substr(0, crlf_pos) << endl;
res.erase(0, crlf_pos + 2); // 2 = sizeof(CRLF)

あと、POP3の資料といえばこの2つですよね。
http://tools.ietf.org/html/rfc2595
http://tools.ietf.org/html/rfc1939

RFC2595はPOP3をどうやってSSLと一緒に使うかの解説で、#1さんの回答にあったSTLSが説明されています。RFC1939はPOP3そのものの解説です。


あと、SSLで安全な通信がしたかったら、certificateをセットして、CRLかOCSPかをチェックしてください。なりすまし対策がないSSLは見掛け倒しです。暗号化通信をしているかもしれませんが、誰と暗号化通信をしているかはわかりません。


#2の回答についてコメントです
> WSAAsyncSelect()でメッセージで通知して貰うようにして組んだことはありますが、
> FD_READで受信した後でSSL_read()しても何も読めない。という状況になったことはあります。

もしノンブロッキングなソケットが裏にあるとしたら、SSL_ERROR_WANT_READ / SSL_ERROR_WANT_WRITE をちゃんとハンドリングしないとダメですね。
http://www.openssl.org/docs/ssl/SSL_read.html

selectで読めると言われても、SSLのレベルでデータが読めるまでには何度も read/write を繰り返さないといけないことがありますので。

SSL以前の問題ですね。

> while (1) {
> char buf[1024] = {0};
> if (SSL_read(ssl, buf, sizeof(buf)-1) <= 0)
> break;
> res += buf;
> }

よくこれでブロックしないですね。
SSL_readでタイムアウトして切断されるまで待たされて、タイムアウトした所でSSL_read < 0となってループを抜ける事になりそうですが。
このコードだと、POP3Sではなく普通にread/writeを使ってPOP3を話すプログラムを書いても動かないと思います。

もし、「ブロック???」と思うなら、次のページでも読んでみると良いでしょう。
...続きを読む


人気Q&Aランキング