[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Socket functions from octave
From: |
John Swensen |
Subject: |
Socket functions from octave |
Date: |
Tue, 02 May 2006 16:51:12 -0600 |
User-agent: |
Thunderbird 1.5.0.2 (Windows/20060308) |
I noticed on the projects page that there was a request for
implementation of the basic socket functions (e.g. socket, connect,
bind, listen, etc.). Attached is a first shot at it. So far I have all
the client functions implemented. I will work on the server ones next.
Is this what you were looking for?
* Only allows the sending of uint8 arrays or strings (This could be
changed to detect the size and perform endian swapping to network byte
order)
* Only receives data into a uint8 RowVector
* Needs more error checking for lost connections, etc.
Let me know what you think. Also, I am not sure how I go about getting
this accepted into the code base. Or, does this belong in octave-forge?
John Swensen
// C++ STL includes
#include <cstdio>
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;
// Octave Includes
#include <octave/oct.h>
#include <octave/parse.h>
#include <octave/toplev.h>
#include <octave/cmd-hist.h>
#include <octave/symtab.h>
#include <octave/variables.h>
#include <octave/ov-struct.h>
// System includes
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
template <class T>
std::string to_string(T t, std::ios_base & (*f)(std::ios_base&))
{
std::ostringstream oss;
oss << f << t;
return oss.str();
}
// Derive an octave_socket class from octave_base_value
class octave_socket : public octave_base_value
{
private:
/**
* Socket file descriptor
*/
int sock_fd;
public:
/**
* Default constructor. Must be defined, but never used.
*/
octave_socket();
/**
* Constructor used to create the socket.
*/
octave_socket( int domain, int type, int protocol );
/**
* Destructor.
*/
~octave_socket();
bool is_constant (void) const { return true; }
bool is_defined (void) const { return true; }
// Still undefined.
bool is_data_available() {};
/**
* Overloaded to print the fd as the socket id
*/
void print (ostream& os, bool pr_as_read_syntax = false) const;
/**
* Utility function for retrieving the socket fd.
*/
int get_sock_fd(void) { return sock_fd; };
private:
DECLARE_OCTAVE_ALLOCATOR
DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
};
DEFINE_OCTAVE_ALLOCATOR (octave_socket);
DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_socket, "octave_socket",
"octave_socket");
//////////////////////////////////////////////////////////////////////////////////////////
octave_socket::octave_socket()
{
}
//////////////////////////////////////////////////////////////////////////////////////////
octave_socket::octave_socket( int domain, int type, int protocol )
{
sock_fd = ::socket( domain, type, protocol );
if( sock_fd == -1 )
{
octave_stdout << "Error creating socket" << endl;
}
}
//////////////////////////////////////////////////////////////////////////////////////////
octave_socket::~octave_socket()
{
::close( sock_fd );
}
//////////////////////////////////////////////////////////////////////////////////////////
void octave_socket::print (ostream& os, bool pr_as_read_syntax ) const
{
os << to_string<int>(sock_fd,std::dec) << endl;
}
// Define the following functions for socket classes
/*
bind
listen
accept
*/
// Define the following functions for use otherwise
/*
getaddrinfo
others?
*/
// Function to create a socket
DEFUN_DLD(socket,args,nargout,"socket(string,string,string)\nSee the socket()
man pages")
{
int domain = PF_INET;
int type = SOCK_STREAM;
int protocol = 0;
// Convert the arguments to their #define'd value
if( args.length() > 0 )
{
string s_domain = args(0).string_value();
if( s_domain == "PF_UNIX" || s_domain == "PF_LOCAL" )
{
s_domain = PF_LOCAL;
}
else if( s_domain == "PF_INET" )
{
s_domain = PF_INET;
}
else if( s_domain == "PF_APPLETALK" )
{
s_domain = PF_APPLETALK;
}
else
{
// Error about invalid domain
octave_stdout << "Invalid socket domain: " << s_domain << endl;
}
}
if( args.length() > 1 )
{
string s_type = args(1).string_value();
if( s_type == "SOCK_STREAM" )
{
type = SOCK_STREAM;
}
else if( s_type == "SOCK_DGRAM" )
{
type = SOCK_DGRAM;
}
else if( s_type == "SOCK_SEQPACKET" )
{
type = SOCK_SEQPACKET;
}
else if( s_type == "SOCK_RAW" )
{
type = SOCK_RAW;
}
else if( s_type == "SOCK_RDM" )
{
type = SOCK_RDM;
}
else
{
// Error about invlid type
octave_stdout << "Invalid socket type: " << s_type << endl;
}
}
if( args.length() > 2 )
{
string s_protocol = args(2).string_value();
octave_stdout << "For now, protocol must always be 0 (zero)" << endl;
}
// Create the new socket
octave_socket* retval = new octave_socket( domain, type, protocol );
if ( nargout > 0 && retval->get_sock_fd() != -1 )
return octave_value(retval);
return octave_value();
}
// function to create an outgoing connection
DEFUN_DLD(connect,args,nargout, \
"connect(octave_socket,struct)\nSee the connect() man pages")
{
int retval = -1;
struct sockaddr_in serverInfo;
struct hostent* hostInfo;
if( args.length() < 2 )
{
octave_stdout << "You must specify 2 parameters" << endl;
retval = -2;
}
// Extract information about the server to connect to.
const octave_value& struct_serverInfo = args(1).get_rep();
octave_struct& addrInfo = ((octave_struct&)struct_serverInfo);
string addr = addrInfo.map_value().stringfield("addr");
int port = addrInfo.map_value().intfield("port");
// If the input parameters is a octave_socket object
if ( args(0).type_id() == octave_socket::static_type_id() )
{
// Determine the socket on which to operate
const octave_value& rep = args(0).get_rep();
octave_socket& s = ((octave_socket &)rep);
serverInfo.sin_family = AF_INET;
// Determine the host address by attempting a gethostbyname() operation
if( addr.length() > 0 )
{
hostInfo = gethostbyname( addr.c_str() );
if( hostInfo )
{
serverInfo.sin_addr.s_addr = *((long*)hostInfo->h_addr_list[0]);
}
else
{
retval = -3;
octave_stdout << "ERROR in gethostbyname()" << endl;
return octave_value(retval);
}
}
else
{
octave_stdout << "empty address" << endl;
retval = -4;
return octave_value(retval);
}
serverInfo.sin_port = htons(port);
retval = connect( s.get_sock_fd(), (struct sockaddr*)&serverInfo,
sizeof(struct sockaddr) );
}
// If using the fd integer value, look up the octave_socket object from a
list by fd
else
{
// TODO
}
return octave_value(retval);
}
// function to get a host number from a host name
DEFUN_DLD(gethostbyname,args,nargout, \
"gethostbyname(string)\nSee the gethostbyname() man pages")
{
struct hostent* hostInfo = NULL;
string_vector host_list;
if( args(0).is_string() )
{
string addr = args(0).string_value();
hostInfo = gethostbyname( addr.c_str() );
if( hostInfo )
{
for( int i = 0 ; i < hostInfo->h_length/4 ; i++ )
{
string temp_addr = string( inet_ntoa( *(struct
in_addr*)hostInfo->h_addr_list[i] ));
host_list.append( temp_addr );
}
}
}
return octave_value(host_list);
}
// function to send data over a socket
DEFUN_DLD(send,args,nargout, \
"send(octave_socket,octave_value)\nSee the send() man pages. This
will only allow the" \
" user to send uint8 arrays or strings")
{
int retval = 0;
int flags = 0;
if( args.length() < 2 )
{
octave_stdout << "You must specify 2 parameters" << endl;
retval = -1;
return octave_value(retval);
}
if( args.length() > 2 )
flags = args(2).int_value();
// TODO - allow the user to pass in the integer fd of the socket also
const octave_value& rep = args(0).get_rep();
octave_socket& s = ((octave_socket &)rep);
const octave_value& data = args(1).get_rep();
if( data.is_string() )
{
string buf = data.string_value();
retval = ::send( s.get_sock_fd(), buf.c_str(), buf.length(), flags );
}
else if( data.byte_size() == data.numel() )
{
octave_value_list data_list = data.list_value();
unsigned char* buf = new unsigned char[ data.byte_size() ];
for( int i = 0 ; i < data.byte_size() ; i++ )
buf[i] = data_list(i).int_value();
retval = ::send( s.get_sock_fd(), (const char*)buf, data.byte_size(), 0 );
delete buf;
}
else
{
octave_stdout << "You have specified an invalid data type to send. Please
format it prior to sending" << endl;
}
return octave_value(retval);
}
// function to receive data over a socket
DEFUN_DLD(recv,args,nargout, \
"recv(octave_socket,int)\nSee the send() man pages. This will only
allow the" \
" user to receive uint8 arrays or strings")
{
int retval = 0;
int flags = 0;
if( args.length() < 2 )
{
octave_stdout << "You must specify 2 parameters" << endl;
retval = -1;
}
if( args.length() > 2 )
flags = args(2).int_value();
// TODO - allow the user to pass in the integer fd of the socket also
const octave_value& rep = args(0).get_rep();
octave_socket& s = ((octave_socket &)rep);
long len = args(1).int_value();
unsigned char* buf = new unsigned char[ len ];
retval = ::recv( s.get_sock_fd(), buf, len, flags );
octave_stdout << "RECVD: " << buf << endl;
RowVector return_buf(retval);
octave_value_list return_list;
for( int i = 0 ; i < retval ; i++ )
return_buf(i) = buf[i];
return_list(0) = return_buf;
return_list(1) = retval;
return return_list;
}
- Socket functions from octave,
John Swensen <=