Hostent extension problem - returning the ip address


(Berger, Daniel) #1

Hi all,

Ruby 1.6.7 on Solaris 8

I’m writing an extension that simply returns the hostname or ip addresses
for a given host. I’m having a problem with core dumps, however, and I
think it’s because I’m not wrapping the return value from hptr->h_addr_list
(a pointer to an array of pointers that contain in_addr{}). I’ve tried a
few things and though it will compile, it continues to core dump/seg fault.
Any ideas? Here’s my source (including extconf.rb source in comments):

/* my extconf.rb:
require ‘mkmf’

Solaris needs the socket lib to work

if RUBY_PLATFORM =~ /solaris/
have_library(‘socket’)
have_library(‘nsl’)
end

create_makefile(‘sys/host’)
*/

#include “ruby.h”
#include <unistd.h>
#include <netdb.h>
#include <arpa/inet.h>

#ifdef __cplusplus
extern “C”
{
#endif

#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 256
#endif

VALUE cHost;

static void host_free(void* p)
{
free§;
}

static VALUE host_hostname()
{
char h[MAXHOSTNAMELEN];
int rv;
rv = gethostname(h,sizeof(h));
if(rv != 0){
rb_exit(INT2NUM(rv));
}
return rb_str_new2(h);
}

static VALUE host_ip_addr()
{
char h[MAXHOSTNAMELEN];
char str[INET_ADDRSTRLEN];
char *pptr;
struct hostent
hp;
int rv;

Data_Wrap_Struct(cHost,0,host_free,hp);

rv = gethostname(h,sizeof(h));
if(rv != 0){
rb_exit(INT2NUM(rv));
}

hp = gethostbyname(h);
pptr = hp->h_addr_list;
Data_Wrap_Struct(cHost,0,host_free,pptr); /* problem here? */

if( rb_block_given() ){

rb_yield(rb_str_new2(inet_ntop(hp->h_addrtype,*pptr,str,sizeof(str))));
}
else{
VALUE results = rb_ary_new();
for( ; *pptr != NULL; pptr++){

rb_ary_push(results,rb_str_new2(inet_ntop(hp->h_addrtype,*pptr,str,sizeof(st
r))));
}
return results;
}
}

void Init_host()
{

VALUE sys_mSys;

sys_mSys = rb_define_module(“Sys”);
cHost = rb_define_class_under(sys_mSys, “Host”, rb_cObject);

rb_define_singleton_method(cHost, “hostname”, host_hostname, 0);
rb_define_singleton_method(cHost, “ip_addr”, host_ip_addr, 0);
}

#ifdef __cplusplus
}
#endif

···

==============

Here’s some equivalent C source code (that works, btw):

#include <stdio.h>
#include <netdb.h>
#include <arpa/inet.h>

/* Compile with -lsocket option to gcc on Solaris or it will fail */

int main(){
long addr;
char *ptr, **pptr;
char str[INET_ADDRSTRLEN];

struct hostent* hp;

hp = gethostbyname(“v55host11.interprise.com”);

printf(“Address length: %i\n”, hp->h_length);
printf(“Name: %s\n”, hp->h_name);

pptr = hp->h_addr_list;
for( ; *pptr != NULL; pptr++){
printf(“Address: %s\n”, inet_ntop(hp->h_addrtype, *pptr, str,
sizeof(str)));
}

return 1;
}


(ts) #2

   Data_Wrap_Struct(cHost,0,host_free,hp);

[...]

   hp = gethostbyname(h);
   pptr = hp->h_addr_list;
   Data_Wrap_Struct(cHost,0,host_free,pptr); /* problem here? */

Why do you use Data_Wrap_Struct() ?

On Solaris 8, for gethostbyname(3)

     The functions gethostbyname(), gethostbyaddr(), and gethos-
     tent() use static storage that is reused in each call, mak-
                 ^^^^^^^^^^^^^^
     ing these functions unsafe for use in multi-threaded appli-
     cations.

Guy Decoux


(Yukihiro Matsumoto) #3

Hi,

···

In message “hostent extension problem - returning the ip address” on 02/06/11, “Mr. Sunblade” djberge@qwest.com writes:

I’m writing an extension that simply returns the hostname or ip addresses
for a given host. I’m having a problem with core dumps, however, and I
think it’s because I’m not wrapping the return value from hptr->h_addr_list
(a pointer to an array of pointers that contain in_addr{}). I’ve tried a
few things and though it will compile, it continues to core dump/seg fault.
Any ideas? Here’s my source (including extconf.rb source in comments):

You are freeing struct hostent given by gethostname(3).
gethostname(3) returns a pointer to static data, not to be freed.

						matz.