RubyInlineでSunRPCをたたいてみる

RubyコードにCコードを直接埋め込む RubyInline。
これを使って SunRPC サーバーを叩いてみました。

使用する RPCサーバーはこれ。

  • sample.x
struct samplearg {
  int a;
  int b;
};

struct sample {
  int sum;
  int diff;
};

program SAMPLEPROG {
  version SAMPLEVERSION {
    sample SAMPLE(samplearg) = 1;
  } = 1;
} = 0x20001001;
  • sample_server.c
#include <rpc/rpc.h>
#include "sample.h"

bool_t sample_1_svc(samplearg* arg, sample* result, struct svc_req* req)
{
  result->sum  = arg->a + arg->b;
  result->diff = arg->a - arg->b;

  return TRUE;
}

int sampleprog_1_freeresult(SVCXPRT* svc, xdrproc_t proc, caddr_t caddr)
{
  return 1;
}

クライアント側の Rubyコード

  • rubyrpc.rb
#!/usr/bin/env ruby

require 'rubygems'
require 'inline'

class SunRPC_sample
  inline(:C) {|builder|
    builder.include "<rpc/rpc.h>"
    builder.include "\"sample.h\""
    builder.add_compile_flags "sample_clnt.c sample_xdr.c -I #{File.dirname(__FILE__)}"
    builder.add_static "gClient", 0, "CLIENT*"
    builder.c <<-__C__
        int start(void)
        {
          if(gClient) return 0;
          gClient = clnt_create("localhost", SAMPLEPROG, SAMPLEVERSION, "tcp");
          if(gClient==NULL) {
            clnt_pcreateerror("localhost");
            return -1;
          }
          return 0;
        }
    __C__

    builder.c <<-__C__
        int sum(int a, int b)
        {
          if(!gClient) return 0;
          sample result;
          samplearg arg = {a, b};
          sample_1(&arg, &result, gClient);
          return result.sum;
        }
    __C__

    builder.c <<-__C__
        int diff(int a, int b)
        {
          if(!gClient) return 0;
          sample result;
          samplearg arg = {a, b};
          sample_1(&arg, &result, gClient);
          return result.diff;
        }
    __C__
  }
end


r = SunRPC_sample.new
r.start
puts r.sum(1, 2)
puts r.diff(1, 2)

サーバーを起動しておいて、

$ rpcgen -M sample.x
$ gcc -o sample sample_svc.c sample_server.c sample_xdr.c
$ ./sample

Rubyクライアントを実行。

$ ./rubyrpc.rb
3
-1

成功\(゚∀゚)/