Net-SCTP
view release on metacpan or search on metacpan
/*
Copyright (C) 2013 by Brandon Casey & Anthony Lucillo
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Required for XS file
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
// Required for module
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
MODULE = Net::SCTP PACKAGE = Net::SCTP
##-----------------------------------------------------------------------------
#/Start Subroutine : _socket
#
# Purpose : Create a socket
# Params : b_inet6, b_many
# Returns : 0 on success -1 on failure
# b_inet6 : determines what version of ip to use for the
# for the socket.
# b_many : determines whether to socket
# is using the new style one to many (if true) socket
# or the old style (if false)
int
_socket(b_inet6, b_many)
bool b_inet6
bool b_many
CODE:
// AF_INET for IPv4, b_inet6 = false
// AF_INET6 for IPv6, b_inet6 = true
// SOCK_SEQPACKET for one to many, b_many = true
// SOCK_STREAM for one to one, b_many = false
// Set our return value equal to the function
// call so we can return that to perl
RETVAL = socket(((b_inet6) ? AF_INET6 : AF_INET),
((b_many) ? SOCK_SEQPACKET : SOCK_STREAM) , IPPROTO_SCTP);
// RETVAL was a failure, print out the error to the user because
// Perl cannot do it.
if( RETVAL < 0 )
{
printf("After socket errno: %d\n", errno);
perror("Description: ");
}
OUTPUT:
RETVAL
#\End Subroutine : _socket
##-----------------------------------------------------------------------------
##-----------------------------------------------------------------------------
#/Start Subroutine : _bind
#
# Purpose : bind an address with a socket
# Returns : 0 on success -1 on failure
# i_sd : The socket descriptor to bind to.
# i_port : The port to bind to.
# sz_ip : The ip to bind to
# b_inet6 : Whether the connection is v6 or v4
int
_bind( i_sd, i_port, sz_ip, b_inet6)
int i_sd
int i_port
char* sz_ip
bool b_inet6
PREINIT:
// The structure that the addresses need to be inside of when passed to the
// actual sctp function.
struct sockaddr_in t_addr;
CODE:
// Zero out the memory of the structure
bzero( (void *)&t_addr, sizeof(struct sockaddr_in) );
// AF_INET for IPv4, b_inet is false
// AF_INET6 for IPv6, b_inet is true
// Build the structure to pass into the sctp function
t_addr.sin_family = ( (b_inet6) ? AF_INET6 : AF_INET );
t_addr.sin_port = htons(i_port);
t_addr.sin_addr.s_addr = inet_addr(sz_ip);
// Set our return value equal to the function
// call so we can return that to perl
RETVAL = bind(i_sd, (struct sockaddr *)&t_addr, sizeof(struct sockaddr_in));
// RETVAL was a failure, print out the error to the user because
// Perl cannot do it.
if( RETVAL < 0 )
{
printf("After bind errno: %d\n", errno);
perror("Description: ");
}
OUTPUT:
RETVAL
#\End Subroutine : _bind
##-----------------------------------------------------------------------------
##-----------------------------------------------------------------------------
#/Start Subroutine : _setsockopt
#
# Purpose : Set socket options given a socket and the options to set
# Returns :
# i_sd : The socket descriptor to set options on
# hash : The hash of options that has a hash of options inside.
# Note : Example
# my %SCTP_EVENTS = (sctp_association_event => 1,);
# my %hash_to_try = (SCTP_EVENTS => \%SCTP_EVENTS,);
# Also note that not all options are currently supported.
#
#void
#_setsockopt( i_sd, hash )
# int i_sd
# HV* hash
# CODE:
#
# int val_length;
# int numHashes = hv_iterinit(hash);
# int a = 0;
# for( a = 0; a < numHashes; a++ ) // outer hash
# {
# HE* outer_iter = hv_iternext(hash);
# //if( !outer_iter ) break;
#
# SV* outer_key = hv_iterkeysv( outer_iter );
# char* struct_key = SvPV(outer_key, val_length);
# HV* outer_entry = (HV*)hv_iterval(hash, outer_iter );
# HV* inner_hash = (HV*)SvRV(outer_entry);
#
# struct SockOptInfo sockopt_struct = BuildStruct( inner_hash, struct_key );
# int res = setsockopt( i_sd, IPPROTO_SCTP, sockopt_struct.sockOption, sockopt_struct.data, sizeof(struct sctp_event_subscribe) );
#
# //if( res < 0 )
# {
# printf("After setsockopt errno: %d\nSocket Option: %s\n", errno, struct_key);
# perror("Description: ");
sz_ip = (char*)(inet_ntoa(t_addr.sin_addr));
if( RETVAL < 0 )
{
printf("After getpeername errno: %d\n", errno);
perror("Description: ");
}
OUTPUT:
sz_ip
RETVAL
#\End Subroutine : _getpeername
##-----------------------------------------------------------------------------
##-----------------------------------------------------------------------------
#/Start Subroutine : _getsockname
#
# Purpose : Get the socket of a peer on a one to one style socket
# i_sd : The socket descriptor of the peer
# sz_ip : The ip address that will be filled out on return
# i_len : The size of the ip address that is returned
# Note : Does not work on one to many style sockets
int
_getsockname(i_sd, sz_ip)
int i_sd
char* sz_ip
PREINIT:
struct sockaddr_in t_addr = {0};
int i_len;
CODE:
getsockname( i_sd, &t_addr, &i_len );
RETVAL = i_len;
sz_ip = (char*)(inet_ntoa(t_addr.sin_addr));
if( RETVAL < 0 )
{
printf("After getsockname errno: %d\n", errno);
perror("Description: ");
}
OUTPUT:
sz_ip
RETVAL
#\End Subroutine : _getsockname
##-----------------------------------------------------------------------------
##-----------------------------------------------------------------------------
#/Start Subroutine : _sctp_sendmsg
#
# Purpose : send a message to someone over sctp
# i_sd : The socket descriptor of the sender
# sz_msg : The message to be sent
# i_port : The port to send the message over
# sz_ip : The ip address to send the message to
# b_inet6 : ipv6 is true, ipv4 is false
# i_ppid : NYI
# i_flags : NYI
# i_stream : NYI
# i_pr_value : NYI
# i_context : NYI
int
_sctp_sendmsg( i_sd, sz_msg, i_msg_len, i_port, sz_ip, b_inet6, i_ppid = 0, i_flags = 0, i_stream = 0, i_pr_value = 0, i_pr_value = 0, i_context = 0 )
int i_sd
char* sz_msg
int i_msg_len
int i_port
char* sz_ip
bool b_inet6
int i_ppid
int i_flags
int i_stream
int i_pr_value
int i_context
PREINIT:
struct sockaddr_in t_addr = {0};
CODE:
// AF_INET for IPv4
// AF_INET6 for IPv6
t_addr.sin_family = ( (b_inet6) ? AF_INET6 : AF_INET );
t_addr.sin_port = htons(i_port);
t_addr.sin_addr.s_addr = inet_addr( sz_ip );
RETVAL = sctp_sendmsg( i_sd, (const void *)sz_msg, i_msg_len, (struct sockaddr *)&t_addr, sizeof(struct sockaddr_in), htonl(i_ppid), i_flags, i_stream /*stream 0*/, i_pr_value, i_context);
if( RETVAL < 0 )
{
printf("After sctp_sendmsg errno: %d\n", errno);
perror("Description: ");
}
OUTPUT:
RETVAL
#\End Subroutine : _sctp_sendmsg
##-----------------------------------------------------------------------------
##-----------------------------------------------------------------------------
#/Start Subroutine : _sctp_recvmsg
#
# Purpose : send a message to someone over sctp
# i_sd : The socket descriptor to listen on
# sz_msg : The message to be received
# i_port : The port to listen on
# sz_addr : The size of the message
# i_flags : NYI
int
_sctp_recvmsg( i_sd, sz_msg, i_buffer_size, i_port, sz_addr, i_flags = 0 )
int i_sd
SV* sz_msg
int i_buffer_size
int i_port
char* sz_addr
int i_flags
PREINIT:
struct sockaddr_in t_addr = {0};
struct sctp_sndrcvinfo t_sinfo = {0};
int new_len;
socklen_t i_addr_len = (socklen_t)sizeof(struct sockaddr_in);
int i_in_len = i_buffer_size + 1;
char sz_in_msg[i_in_len];
int len = 0;
CODE:
len = sctp_recvmsg( i_sd, (void*)sz_in_msg, i_buffer_size, (struct sockaddr *)&t_addr, &i_addr_len, &t_sinfo, &i_flags );
if( -1 == len )
{
printf("After sctp_recvmsg errno: %d\n", errno);
perror("Description: ");
}
sv_setpvn(sz_msg, sz_in_msg, len);
i_port = ntohs(t_addr.sin_port);
sz_addr = inet_ntoa(t_addr.sin_addr);
RETVAL = len;
OUTPUT:
sz_msg
i_port
sz_addr
RETVAL
#\End Subroutine : _sctp_recvmsg
##-----------------------------------------------------------------------------
##-----------------------------------------------------------------------------
#/Start Subroutine : _connect
#
# Purpose : send a message to someone over sctp
# i_sd : The socket descriptor of the client who is connecting
# i_port : The port to connect to
# sz_ip : The ip address to connect to
# b_inet6 : The version of ip we are using, true for v6 false for v4
int
_connect( i_sd, i_port, sz_ip, b_inet6 )
int i_sd
int i_port
char* sz_ip
bool b_inet6
PREINIT:
struct sockaddr_in servaddr;
CODE:
bzero( (void *)&servaddr, sizeof(struct sockaddr_in) );
// AF_INET for IPv4
// AF_INET6 for IPv6
servaddr.sin_family = ( (b_inet6) ? AF_INET6 : AF_INET );
servaddr.sin_port = htons(i_port);
servaddr.sin_addr.s_addr = inet_addr( sz_ip );
RETVAL=connect( i_sd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in) );
if( RETVAL )
{
printf("After connect errno: %d\n", errno);
perror("Description: ");
}
OUTPUT:
RETVAL
#\End Subroutine : _connect
##-----------------------------------------------------------------------------
##-----------------------------------------------------------------------------
#/Start Subroutine : _accept
#
# Purpose : accept a connection in one to one style
# Returns : Returns the socket desriptor of the person
# that is connecting
# i_sd : The socket descriptor of the server
int
_accept( i_sd )
int i_sd
CODE:
RETVAL = accept( i_sd, (struct sockaddr *)NULL, (socklen_t *)NULL );
if( RETVAL < 0 )
{
printf("After accept errno: %d\n", errno);
perror("Description: ");
}
OUTPUT:
RETVAL
#\End Subroutine : _accept
##-----------------------------------------------------------------------------
##-----------------------------------------------------------------------------
#/Start Subroutine : _sctp_bindx
#
# Purpose : Bind the server ti multiple connections
# Returns : Success(0) or failure(-1)
# i_sd : The socket descriptor of the server
# i_port : The port of the server
# av_sz_ip : The array of ips to bind to
# av_b_inet6 : The array of ip versions created for the user in perl
# i_flags : 1 is add these addresses 2 is remove them
int
_sctp_bindx(i_sd, i_port, av_sz_ip, av_b_inet6, i_flags)
int i_sd
int i_port
SV* av_sz_ip
SV* av_b_inet6
int i_flags
PREINIT:
int i = 0;
int i_addr_cnt;
CODE:
AV* array_length = (AV *) SvRV (av_b_inet6);
i_addr_cnt = av_len(array_length);
struct sockaddr_in t_addrs[i_addr_cnt];
while(i <= i_addr_cnt)
{
SV** item2 = av_fetch(array_length, i, 0);
bool temp_int = (bool)SvIV(*item2);
AV* array = (AV *) SvRV (av_sz_ip);
SV** item = av_fetch(array, i, 0);
char* temp_str = SvPVX(*item);
t_addrs[i].sin_family = ((temp_int) ? AF_INET6 : AF_INET );
t_addrs[i].sin_port = htons(i_port);
t_addrs[i].sin_addr.s_addr = inet_addr(temp_str);
++i;
}
RETVAL = sctp_bindx( i_sd, (struct sockaddr *)&t_addrs, i_addr_cnt + 1, i_flags );
if( RETVAL < 0 )
{
printf("After bindx errno: %d\n", errno);
perror("Description: ");
}
OUTPUT:
RETVAL
#\End Subroutine : _sctp_bindx
##-----------------------------------------------------------------------------
##-----------------------------------------------------------------------------
#/Start Subroutine : _sctp_connectx
#
# Purpose : Attempts to connect to a server using multiple addresses
# Returns : Success(0) or failure(-1)
# i_sd : The socket descriptor of the client
# i_port : The port of the server
# av_sz_ip : The array of ips to connect to
# av_b_inet6 : The array of ip versions created for the user in perl
# i_id : The association id to give the association that is
# being set up
int
_sctp_connectx(i_sd, i_port, av_sz_ip, av_b_inet6, i_id = 0)
int i_sd
int i_port
SV* av_sz_ip
SV* av_b_inet6
int i_id;
PREINIT:
int i = 0;
int i_addr_cnt;
CODE:
AV* array_length = (AV *) SvRV (av_b_inet6);
i_addr_cnt = av_len(array_length);
struct sockaddr_in t_addrs[i_addr_cnt];
while(i <= i_addr_cnt)
{
SV** item2 = av_fetch(array_length, i, 0);
int temp_int = (int)SvIV(*item2);
AV* array = (AV *) SvRV (av_sz_ip);
SV** item = av_fetch(array, i, 0);
char* temp_str = SvPVX(*item);
t_addrs[i].sin_family = ((temp_int) ? AF_INET6 : AF_INET );
t_addrs[i].sin_port = htons(i_port);
t_addrs[i].sin_addr.s_addr = inet_addr(temp_str);
++i;
}
RETVAL = sctp_connectx( i_sd, (struct sockaddr *)&t_addrs, i_addr_cnt + 1);
if( RETVAL < 0 )
{
printf("After connectx errno: %d\n", errno);
perror("Description: ");
}
OUTPUT:
RETVAL
#\End Subroutine : _sctp_connectx
##-----------------------------------------------------------------------------
##-----------------------------------------------------------------------------
#/Start Subroutine : _sctp_peeloff
#
# Purpose : Take an association and separate it to another
# Returns : Returns the association id of the new association
# i_sd : The socket descriptor of the server
# i_assoc_id : The association id to change to another one
# Note : Currently untested
int
_sctp_peeloff(i_sd, i_assoc_id)
int i_sd
int i_assoc_id
CODE:
RETVAL = sctp_peeloff(i_sd, i_assoc_id);
if( RETVAL < 0 )
{
printf("After peeloff errno: %d\n", errno);
perror("Description: ");
}
OUTPUT:
RETVAL
#\End Subroutine : _sctp_peeloff
##-----------------------------------------------------------------------------
##-----------------------------------------------------------------------------
#/Start Subroutine : _sctp_getpaddrs
#
# Purpose : Returns all peer addresses in an association
# Returns : Fills out the arrays passed with peer addresses
# i_sd : The socket descriptor of the client
# i_port : The port to be filled
# av_sz_ip : The array of ips to to be filled
# av_b_inet6 : The array of ip versions to be filled
# i_id : The association id to get the addresses from
# : Automatically calls sctp_freepaddrs
int
_sctp_getpaddrs(i_sd, i_id, av_sz_ip,av_i_port, av_b_inet6)
int i_sd
int i_id
SV* av_sz_ip
SV* av_i_port
SV* av_b_inet6
PREINIT:
struct sockaddr_in * t_addrs;
int i = 0;
AV* array_ip = (AV *) SvRV (av_sz_ip);
AV* array_port = (AV *) SvRV (av_i_port);
AV* array_inet6 = (AV *) SvRV (av_b_inet6);
CODE:
RETVAL = sctp_getladdrs(i_sd, i_id, (struct sockaddr **)&t_addrs);
while(i < RETVAL)
{
char* temp_c_ip = (char*)inet_ntoa(*(struct in_addr *)&t_addrs[i].sin_addr.s_addr);
SV* temp_ip = newSVpvn(temp_c_ip, strlen(temp_c_ip));
av_push(array_ip, temp_ip);
SV* temp_port = newSViv(t_addrs[i].sin_port);
av_push(array_port, temp_port);
SV* temp_family = newSViv(t_addrs[i].sin_family);
av_push(array_inet6, temp_family);
++i;
}
sctp_freepaddrs((struct sockaddr *)&t_addrs);
if( RETVAL < 0 )
{
printf("After getpaddrs errno: %d\n", errno);
perror("Description: ");
}
OUTPUT:
RETVAL
#\End Subroutine : _sctp_getpaddrs
##-----------------------------------------------------------------------------
##-----------------------------------------------------------------------------
#/Start Subroutine : _sctp_getladdrs
#
# Purpose : Returns all local addresses in an association
# Returns : Fills out the arrays passed with local addresses
# i_sd : The socket descriptor of the client
# i_port : The port to be filled
# av_sz_ip : The array of ips to to be filled
# av_b_inet6 : The array of ip versions to be filled
# i_id : The association id to get the addresses from
# Automatically calls sctp_freeladdrs
int
_sctp_getladdrs(i_sd, i_id, av_sz_ip, av_i_port, av_b_inet6)
int i_sd
int i_id
SV* av_sz_ip
SV* av_i_port
SV* av_b_inet6
PREINIT:
struct sockaddr_in * t_addrs;
int i = 0;
AV* array_ip = (AV *) SvRV (av_sz_ip);
AV* array_port = (AV *) SvRV (av_i_port);
AV* array_inet6 = (AV *) SvRV (av_b_inet6);
CODE:
RETVAL = sctp_getladdrs(i_sd, i_id, (struct sockaddr **)&t_addrs);
while(i < RETVAL)
{
char* temp_c_ip = (char*)inet_ntoa(*(struct in_addr *)&t_addrs[i].sin_addr.s_addr);
SV* temp_ip = newSVpvn(temp_c_ip, strlen(temp_c_ip));
av_push(array_ip, temp_ip);
SV* temp_port = newSViv(t_addrs[i].sin_port);
av_push(array_port, temp_port);
SV* temp_family = newSViv(t_addrs[i].sin_family);
av_push(array_inet6, temp_family);
++i;
}
sctp_freeladdrs((struct sockaddr *)&t_addrs);
if( RETVAL < 0 )
{
printf("After getladdrs errno: %d\n", errno);
perror("Description: ");
}
OUTPUT:
RETVAL
#\End Subroutine : _sctp_getladdrs
##-----------------------------------------------------------------------------
## Not Supported Stuff:
#
# SCTP_SENDX
#
# i_ppid -- message_id so chunks can be put together (OPTIONAL)
# i_stream -- 0 = out | 1 = input | 2 = error
#int
#_sctp_sendx( i_sd, sz_msg, i_port, av_sz_ip, av_b_inet6, i_flags = 0)
# int i_sd
# char* sz_msg
# int i_port
# SV* av_sz_ip
# SV* av_b_inet6
# int i_flags
# PREINIT:
# int i_addr_cnt = 0;
# int i = 0;
# CODE:
# AV* array_length = (AV *) SvRV (av_b_inet6);
# i_addr_cnt = av_len(array_length);
# struct sockaddr_in t_addrs[i_addr_cnt];
#
#
# while(i <= i_addr_cnt)
# {
# SV** item2 = av_fetch(array_length, i, 0);
# bool temp_int = (bool)SvIV(*item2);
#
#
# AV* array = (AV *) SvRV (av_sz_ip);
# SV** item = av_fetch(array, i, 0);
# char* temp_str = SvPVX(*item);
#
# t_addrs[i].sin_family = ((temp_int) ? AF_INET6 : AF_INET );
# printf("Family:%d\n", temp_int);
# t_addrs[i].sin_port = i_port;
# t_addrs[i].sin_addr.s_addr = inet_addr(temp_str);
# printf("IP:%s\n", temp_str);
# ++i;
# }
#
#
# RETVAL = sctp_sendx( i_sd, (const void *)sz_msg, strlen(sz_msg), (struct sockaddr *)&t_addrs, (struct sctp_sndrcvinfo *) NULL, i_flags);
#
# //if( RETVAL < 0 )
# {
# printf("After sctp_sendx errno: %d\n", errno);
# perror("Description: ");
# }
# OUTPUT:
# RETVAL
#
#
#
# SENDV
# ssize_t sctp_sendv(int sd, const struct iovec *iov, int iovcnt, struct sockaddr *addrs, int addrcnt, void *info, socklen_t infolen, unsigned int infotype, int flags);
# Free all the stuff that we allocated in GETLADDRS
#ssize_t
#_sctp_sendv(i_sd, t_iov, i_iov_len, sz_addrs, i_addrcnt, info, i_info_len, i_infotype, i_flags)
# int i_sd
# AV* t_iov
# int i_iov_len
# char* sz_addrs
# int i_addrcnt
# void* info
# int i_info_len
# unsigned int i_infotype
# int i_flags
#
# CODE:
#
#
# RETVAL = sctp_sendv(i_sd, (struct iovec *) t_iov, i_iov_len, sz_addrs, i_addrcnt, info,i_info_len, i_infotype, i_flags);
#
# // if( RETVAL < 0 )
# {
# printf("After sendv errno: %d\n", errno);
# perror("Description: ");
# }
( run in 0.745 second using v1.01-cache-2.11-cpan-39bf76dae61 )