YAMAGUCHI::weblog

海水パンツとゴーグルで、巨万の富を築きました。カリブの怪物、フリーアルバイター瞳です。

MICO CORBAでCOMM_FAILUREで落ちる

動機

昨日からCORBAのテストアプリケーションを動かしているが,localhostではうまくいくのに,サーバ/クライアントを別マシンにするとエラーが出て落ちる..

調査

下記のエラーが出て落ちる

uncaught MICO exception: IDL:omg.org/CORBA/COMM_FAILURE:1.0 (0, not-completed)

原因を見つけるために `netstat -c` で監視しつつ,例外メッセージを調べていたらなんとなく原因が分かってきた.どうもCORBAではリスナーポートにアクセスしてきた元のポートにそのままデータを返すみたい.これはJavaだけど,このような例外らしい.

netstat -cで確認をしたところ

Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 hoge:44532           hoge:5005            ESTABLISHED
tcp        0      0 hoge:5005            hoge:44532           ESTABLISHED
tcp        0      0 hoge:5005            fuga:3901              ESTABLISHED

この直後に3番目の通信が切れ,test_client.shが上記の例外を吐いて落ちる.おそらくclientがNameServerにたどり着いた後,NameServerがfugaの3901番ポートにアクセスしようとして,ポートの接続制限によって通信が切断されるためではないかと思われる.
ためしにNameServer, test_server, test_clientをすべてhoge上で行ったときは,

Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 localhost.localdo:42688 localhost.localdo:60095 ESTABLISHED
tcp        0      0 hoge:44724           hoge:5005            ESTABLISHED
tcp        0      0 localhost.localdo:60095 localhost.localdo:42688
ESTABLISHED
tcp        0      0 hoge:44725           hoge:5005            ESTABLISHED
tcp        0      0 hoge:5005            hoge:44725           ESTABLISHED
tcp        0      0 hoge:5005            hoge:44724           ESTABLISHED

hoge上の44724番ポートから5005番にアクセスしているのがserverで,44725番から5005番にアクセスしているのがclient.NameServerは5005番からserverとclient,両方のポートにアクセスできています.またlocalhost.localdo:42688と60095が何をしているのかがよくわからないけど,とりあえずポート周りであろうと分かった.

テストコード

test_server.idl
interface TestServer
{
    long display_message(in string msg);
    long get_message(out string msg);
    void destroy();
};

interface TestServerFactory
{
    TestServer create();
};
test_server_impl.h
class TestServer_impl
    : virtual public POA_TestServer
{
public:
    TestServer_impl();
    ~TestServer_impl();

    CORBA::Long display_message(const char* msg);
    CORBA::Long get_message(CORBA::String_out msg);
    void destroy();
};

class TestServerFactory_impl
    : virtual public POA_TestServerFactory
{
public:
    TestServerFactory_impl();
    ~TestServerFactory_impl();

    TestServer_ptr create();
};
test_server_impl.cc
#include "test_server_impl.h"

#include <iostream>
using namespace std;

TestServer_impl::TestServer_impl()
{
}

TestServer_impl::~TestServer_impl()
{
}

CORBA::Long TestServer_impl::display_message(const char* msg)
{
    cerr << msg << endl;
    return 0;
}

CORBA::Long TestServer_impl::get_message(CORBA::String_out msg)
{
    msg = CORBA::string_dup("I am TestServer");
    return 0;
}

void TestServer_impl::destroy()
{
    PortableServer::POA_var poa = _default_POA();
    PortableServer::ObjectId_var id = poa->servant_to_id(this);
    poa->deactivate_object(id);
}

TestServer_ptr TestServerFactory_impl::create()
{
    TestServer_impl* test = new TestServer_impl;
    TestServer_ptr tref = test->_this();
    if(CORBA::is_nil(tref))
    {
        cerr << "TestServerFactory: failed to create TestServer object" << endl;
    }
    return tref;
}

TestServerFactory_impl::TestServerFactory_impl()
{
}

TestServerFactory_impl::~TestServerFactory_impl()
{
    PortableServer::POA_var poa = _default_POA();
    PortableServer::ObjectId_var id = poa->servant_to_id(this);
    poa->deactivate_object(id);
}
test_client.cc
#include <coss/CosNaming.h>
#include <test_server.h>
#include <iostream>
using namespace std;

int main(int argc, char** argv)
{
    CORBA::ORB_var orb = CORBA::ORB_init (argc, argv);

    /*
     * Acquire a reference to the Naming Service
     */
    CORBA::Object_var nsobj;
    CosNaming::NamingContext_var nc;
    try
    {
        nsobj = orb->resolve_initial_references ("NameService");
        nc = CosNaming::NamingContext::_narrow (nsobj);
    }
    catch(CORBA::Exception& ex)
    {
        cerr << "client: error at connecting to NameService" << endl;
        return 1;
    }
    if (CORBA::is_nil (nc))
    {
        cerr << "client: I cannot access the Naming Service!" << endl;
        return 1;
    }

    CosNaming::Name name;
    name.length (1);
    name[0].id = CORBA::string_dup ("TestServer");
    name[0].kind = CORBA::string_dup ("");

    /*
     * try to find that node in the Naming Service tree
     */
    CORBA::Object_var obj;
    try
    {
        obj = nc->resolve(name);
    }
    catch(CORBA::Exception& ex)
    {
        cerr << "client: cannot connect to TestServerFactory" << endl;
        return 1;
    }
    cerr << "client: connected to TestServerFactory" << endl;

    /*
     * The Naming Service returns a generic reference as a CORBA::Object
     * We need to narrow this to the desired type
     */
    cerr << "creating TestServerFactory object" << endl;
    TestServerFactory_var fact = TestServerFactory::_narrow (obj);

    TestServer_var test = fact->create();

    if (CORBA::is_nil(test))
    {
        cerr  << "client: cannot create TestServer" << endl;
        return 1;
    }

    test->display_message("Hello!");

    CORBA::String_var msg;
    test->get_message(msg);
    cout << (const char*)msg << endl;

    test->destroy();

    return 0;
}
起動時の各オプション
# nsd -ORBIIOPAddr inet:hoge:5005
# ./server.exe -ORBInitRef NameService=corbaloc::hoge:5005/NameServer
# ./client.exe -ORBInitRef NameService=corbaloc::hoge:5005/NameServer
テスト動作(成功時)
  • server側
# ./server.exe -ORBInitRef NameService=corbaloc::hoge:5005/NameServer
TestServer: binding in the Naming Service ... done.
TestServer: ready
Hello!
  • client側
# ./client.exe -ORBInitRef NameService=corbaloc::hoge:5005/NameServer
client: connected to TestServerFactory
I am TestServer
テスト動作(エラー時)
  • client側
# ./client.exe -ORBInitRef NameService=corbaloc::hoge:5005/NameServer
client: connected to TestServerFactory
creating TestServerFactory object
uncaught MICO exception: IDL:omg.org/CORBA/COMM_FAILURE:1.0 (0, not-completed)

まとめ

クライアントの使用ポートを指定する方法はないのかなぁ?それができればポートの開放とかも楽になるんだけど.是非ご教授願いたい.