C extension troubles on windows

Hi ruby extension geeks, and thanks in advance for your help.

The short version of the issue that I am struggling with is that I have
a native library I created a ruby extension for. The extension works
on linux, but on windows it does not.

I have copies of the library I am extending for both windows and linux
from our vendor (Spirent). I am using gcc on linux and MSVC.NET on
windows. Everything compiles and links without complaining.

On both windows and linux I am able to successfully execute the method
"ETGetLibVersion" which gives me back the library version. I run into
trouble on windows when I try to call “ETSocketLink”. On linux this
call connects and returns as I would expect, however on windows it
connects and blocks. For example when I do a printf before and after
this call I only get output from the first printf and I have to kill
the process to get my cursor back.

Is this a problem with the way I am compiling on windows? A problem
with Spirent’s library? Or some other issue that a non-c programmer
like myself would be totally ignorant of.

Here is the relevant c and ruby code:

Ruby:
require "./smartlib.so"
include SmartLib
p eTGetLibVersion
p eTSocketLink(“192.168.1.244”, 16385)

C:
#include “ruby.h”
#include “et1000.h”

static VALUE smartlib_ETSocketLink(VALUE self, VALUE ip, VALUE port) {
int c_result;
printf(“before”);
c_result = ETSocketLink(STR2CSTR(ip), NUM2INT(port)); printf(“after”);
return Qnil;
}
static VALUE smartlib_ETGetLibVersion() {
char pszDescription[50];
char pszVersion[20];
int c_result = ETGetLibVersion(pszDescription, pszVersion);

VALUE result = rb_ary_new();
rb_ary_push(result, INT2NUM(c_result));
rb_ary_push(result, rb_str_new2(pszDescription));
rb_ary_push(result, rb_str_new2(pszVersion));
return result;

}

VALUE cSmartLib;
void Init_smartlib(){
cSmartLib=rb_define_module(“SmartLib”);
rb_define_method(cSmartLib, “eTSocketLink”, smartlib_ETSocketLink,
2); rb_define_method(cSmartLib, “eTGetLibVersion”,
smartlib_ETGetLibVersion, 0);
}

“Michael Hale” wrote:

On both windows and linux I am able to successfully execute the method
“ETGetLibVersion” which gives me back the library version. I run into
trouble on windows when I try to call “ETSocketLink”. On linux this
call connects and returns as I would expect, however on windows it
connects and blocks.

Do you call ioctlsocket() to set the socket to non-blocking?

Funny I just grepped the entire Ruby source and couldn’t find a call to
ioctlsocket either.

···


Tyche

Unfortunately I don’t have the source for the windows version of the
library I am using, so I can’t say what the code looks like.

I did create a simple C program that I compiled into a command line
.exe in MSVC, which works fine. Here is the pseudo code:
connect
get_hardware_version
disconnect

However, I still run into problems when trying to use ruby to interface
to my library on windows.
I am beginning to think that this could be a bug in ruby.

···

On Dec 5, 2003, at 1:01 AM, Jon A. Lambert wrote:

Do you call ioctlsocket() to set the socket to non-blocking?

I recently resurrected my code to try to get it working again. So far I have had no success.

Basically what I have got is a VC++ compiled .exe that works and a ruby extension that does not. They both try to make the same library calls. Here is the code.

Test.exe (standalone exe that works correctly):

···

====================================================================
#include <stdio.h>
#include "et1000.h"

int main() {
     char version[9];

  printf("NSUnLink Result: %d\n\n", NSUnLink());

  printf("before\n");
  printf("NSSocketLink Result: %d\n", NSSocketLink("192.168.1.244", 16385, 0));
  printf("after\n\n");

  printf("ETGetHardwareVersion Result: %d\n", ETGetHardwareVersion(version));
  printf("%s\n\n", version);

  printf("NSUnLink Result: %d\n", NSUnLink());

  return 0;
}

Which Produces:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
NSUnLink Result: -2

before
NSSocketLink Result: 1
after

ETGetHardwareVersion Result: 0
SMB-6000

NSUnLink Result: 0

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

smartlib_wrap.c (c extension source):

#include "ruby.h"
#include "et1000.h"
#include <stdio.h>

static VALUE
_wrap_NSSocketLink(int argc, VALUE *argv, VALUE self) {
     char *arg1 ;
     int arg2 ;
     int arg3 ;
     int result;
     VALUE vresult = Qnil;

     if ((argc < 3) || (argc > 3))
     rb_raise(rb_eArgError, "wrong # of arguments(%d for 3)",argc);
     arg1 = StringValuePtr(argv[0]);
     arg2 = NUM2INT(argv[1]);
     arg3 = NUM2INT(argv[2]);
  printf("before\n");
     result = (int)NSSocketLink(arg1,arg2,arg3);
  printf("after\n");

     vresult = INT2NUM(result);
     return vresult;
}

static VALUE
_wrap_NSUnLink(int argc, VALUE *argv, VALUE self) {
     int result;
     VALUE vresult = Qnil;

     if ((argc < 0) || (argc > 0))
     rb_raise(rb_eArgError, "wrong # of arguments(%d for 0)",argc);
     result = (int)NSUnLink();

     vresult = INT2NUM(result);
     return vresult;
}

static VALUE
_wrap_ETGetHardwareVersion(int argc, VALUE *argv, VALUE self) {
     char *arg1 ;
     int result;
     VALUE vresult = Qnil;

     if ((argc < 1) || (argc > 1))
     rb_raise(rb_eArgError, "wrong # of arguments(%d for 1)",argc);
     arg1 = StringValuePtr(argv[0]);
     result = (int)ETGetHardwareVersion(arg1);

     vresult = INT2NUM(result);
     return vresult;
}

VALUE mSmartlib;
void Init_smartlib(void) {
  mSmartlib = rb_define_module("Smartlib");
  rb_define_module_function(mSmartlib, "NSSocketLink", _wrap_NSSocketLink, -1);
  rb_define_module_function(mSmartlib, "NSUnLink", _wrap_NSUnLink, -1);
  rb_define_module_function(mSmartlib, "ETGetHardwareVersion", _wrap_ETGetHardwareVersion, -1);
}

test.rb (ruby file that uses c extension):

require 'smartlib'

include Smartlib

p NSUnLink()

p NSSocketLink("192.168.1.244", 16385, 0)

version = ' '
p ETGetHardwareVersion(version)
p version

p NSUnLink()

Which produces the following and hangs during the call to NSSocketLink (notice it never prints out "after").
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-2
before

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Any ideas? I am particuarly puzzled by the fact that the standalone C version works without a hitch, but the ruby extension version of my code hangs.

Thanks, Michael

On Jan 14, 2004, at 3:14 PM, Michael Hale wrote:

Unfortunately I don't have the source for the windows version of the library I am using, so I can't say what the code looks like.

I did create a simple C program that I compiled into a command line .exe in MSVC, which works fine. Here is the pseudo code:
  connect
  get_hardware_version
  disconnect

However, I still run into problems when trying to use ruby to interface to my library on windows.
I am beginning to think that this could be a bug in ruby.

On Dec 5, 2003, at 1:01 AM, Jon A. Lambert wrote:

Do you call ioctlsocket() to set the socket to non-blocking?

  "OS X: because it was easier to make UNIX user-friendly than to fix Windows"

static VALUE
_wrap_NSSocketLink(int argc, VALUE *argv, VALUE self) {

All identifiers that begin with an underscore are reserved for use by
the compiler. This probably isn't your problem, but you should remove
the leading underscore anyway.

    char *arg1 ;
    int arg2 ;
    int arg3 ;
    int result;
    VALUE vresult = Qnil;

    if ((argc < 3) || (argc > 3))
    rb_raise(rb_eArgError, "wrong # of arguments(%d for 3)",argc);
    arg1 = StringValuePtr(argv[0]);
    arg2 = NUM2INT(argv[1]);
    arg3 = NUM2INT(argv[2]);
  printf("before\n");
    result = (int)NSSocketLink(arg1,arg2,arg3);

This cast should be unnecessary. If your compiler is giving you
warnings, adding a cast here just hides the problem (namely that you may
have forgotten to include the header that declares NSSocketLink).

If this doesn't help, then perhaps there is something wrong with the
linking step?

Paul

···

On Wed, Aug 18, 2004 at 05:42:59AM +0900, Michael Hale wrote:

I updated my code to remove the initial underscores and removed the int cast. The only compiler warnings are about unsupported optimization options.

What could be wrong with the linking step? Here is my compile and link output:

Microsoft (R) Program Maintenance Utility Version 7.10.3077
Copyright (C) Microsoft Corporation. All rights reserved.

         cl -nologo -MD -Zi -O2b2xg- -G6 -I. -Ic:/ruby/lib/ruby/1.8/i386-mswin32 -Ic:/ruby/lib/ruby/1.8/i386-mswin32 -I. -IC:/Views/michaelh_ips3.0_priv/Software/tools/ciphero/com.cipheroptics.smartlib/win32/include -I. -I./.. -I./../missing -c -Tcsmartlib_wrap.c
cl : Command line warning D4029 : optimization is not available in the standard edition compiler
cl : Command line warning D4002 : ignoring unknown option '-Og-'
smartlib_wrap.c

         cl -nologo -LD -Fesmartlib.so smartlib_wrap.obj msvcrt-ruby18.lib smbw32vc.lib oldnames.lib user32.lib advapi32.lib wsock32.lib -link -incremental:no -debug -opt:ref -opt:icf -dll -libpath:"C:/Views/michaelh_ips3.0_priv/Software/tools/ciphero/com.cipheroptics.smartlib/win32/lib" -libpath:"c:/ruby/lib" -def:smartlib-i386-mswin32.def
    Creating library smartlib.lib and object smartlib.exp

···

On Aug 18, 2004, at 8:08 AM, Paul Brannan wrote:

On Wed, Aug 18, 2004 at 05:42:59AM +0900, Michael Hale wrote:

static VALUE
_wrap_NSSocketLink(int argc, VALUE *argv, VALUE self) {

All identifiers that begin with an underscore are reserved for use by
the compiler. This probably isn't your problem, but you should remove
the leading underscore anyway.

    char *arg1 ;
    int arg2 ;
    int arg3 ;
    int result;
    VALUE vresult = Qnil;

    if ((argc < 3) || (argc > 3))
    rb_raise(rb_eArgError, "wrong # of arguments(%d for 3)",argc);
    arg1 = StringValuePtr(argv[0]);
    arg2 = NUM2INT(argv[1]);
    arg3 = NUM2INT(argv[2]);
  printf("before\n");
    result = (int)NSSocketLink(arg1,arg2,arg3);

This cast should be unnecessary. If your compiler is giving you
warnings, adding a cast here just hides the problem (namely that you may
have forgotten to include the header that declares NSSocketLink).

If this doesn't help, then perhaps there is something wrong with the
linking step?

Paul

  "OS X: because it was easier to make UNIX user-friendly than to fix Windows"