c extension troubles on windows

M

Michael Hale

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);
}
 
J

Jon A. Lambert

Michael Hale said:
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.
 
M

Michael Hale

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.
 
M

Michael Hale

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

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.
"OS X: because it was easier to make UNIX user-friendly than to fix
Windows"
 
P

Paul Brannan

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
 
M

Michael Hale

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


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"
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top