2004-09-13 14:17:41 +00:00
/*
Unix SMB / CIFS implementation .
Socket functions
2006-04-30 01:32:59 +00:00
Copyright ( C ) Andrew Tridgell 1992 - 1998
Copyright ( C ) Tim Potter 2000 - 2001
2004-09-13 14:17:41 +00:00
Copyright ( C ) Stefan Metzmacher 2004
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 2 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 , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
2005-02-10 06:59:29 +00:00
# include "lib/socket/socket.h"
2005-02-10 05:09:35 +00:00
# include "system/filesys.h"
2006-04-30 01:32:59 +00:00
# include "system/network.h"
2004-09-13 14:17:41 +00:00
2004-09-26 03:05:04 +00:00
/*
auto - close sockets on free
*/
static int socket_destructor ( void * ptr )
{
struct socket_context * sock = ptr ;
2004-11-02 02:01:04 +00:00
if ( sock - > ops - > fn_close ) {
sock - > ops - > fn_close ( sock ) ;
2004-09-26 03:05:04 +00:00
}
return 0 ;
}
2005-01-19 03:20:20 +00:00
static NTSTATUS socket_create_with_ops ( TALLOC_CTX * mem_ctx , const struct socket_ops * ops ,
struct socket_context * * new_sock ,
enum socket_type type , uint32_t flags )
2004-09-13 14:17:41 +00:00
{
NTSTATUS status ;
2005-01-11 15:19:32 +00:00
( * new_sock ) = talloc ( mem_ctx , struct socket_context ) ;
2004-09-13 14:17:41 +00:00
if ( ! ( * new_sock ) ) {
return NT_STATUS_NO_MEMORY ;
}
2005-01-19 03:20:20 +00:00
( * new_sock ) - > type = type ;
2004-09-13 14:17:41 +00:00
( * new_sock ) - > state = SOCKET_STATE_UNDEFINED ;
( * new_sock ) - > flags = flags ;
( * new_sock ) - > fd = - 1 ;
( * new_sock ) - > private_data = NULL ;
2005-01-11 15:19:32 +00:00
( * new_sock ) - > ops = ops ;
2005-08-28 02:37:49 +00:00
( * new_sock ) - > backend_name = NULL ;
2004-09-13 14:17:41 +00:00
2004-11-02 02:01:04 +00:00
status = ( * new_sock ) - > ops - > fn_init ( ( * new_sock ) ) ;
2004-09-13 14:17:41 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2004-09-26 03:05:04 +00:00
talloc_free ( * new_sock ) ;
2004-09-13 14:17:41 +00:00
return status ;
}
2004-10-28 07:55:33 +00:00
/* by enabling "testnonblock" mode, all socket receive and
send calls on non - blocking sockets will randomly recv / send
less data than requested */
if ( ! ( flags & SOCKET_FLAG_BLOCK ) & &
2005-01-19 03:20:20 +00:00
type = = SOCKET_TYPE_STREAM & &
2004-10-28 07:55:33 +00:00
lp_parm_bool ( - 1 , " socket " , " testnonblock " , False ) ) {
( * new_sock ) - > flags | = SOCKET_FLAG_TESTNONBLOCK ;
}
2005-06-11 02:26:53 +00:00
/* we don't do a connect() on dgram sockets, so need to set
non - blocking at socket create time */
if ( ! ( flags & SOCKET_FLAG_BLOCK ) & & type = = SOCKET_TYPE_DGRAM ) {
set_blocking ( socket_get_fd ( * new_sock ) , False ) ;
}
2004-09-26 03:05:04 +00:00
talloc_set_destructor ( * new_sock , socket_destructor ) ;
2004-09-13 14:17:41 +00:00
return NT_STATUS_OK ;
}
2006-03-07 16:28:39 +00:00
_PUBLIC_ NTSTATUS socket_create ( const char * name , enum socket_type type ,
struct socket_context * * new_sock , uint32_t flags )
2005-01-11 15:19:32 +00:00
{
const struct socket_ops * ops ;
ops = socket_getops_byname ( name , type ) ;
if ( ! ops ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2005-01-19 03:20:20 +00:00
return socket_create_with_ops ( NULL , ops , new_sock , type , flags ) ;
2005-01-11 15:19:32 +00:00
}
2006-03-07 16:28:39 +00:00
_PUBLIC_ NTSTATUS socket_connect ( struct socket_context * sock ,
const struct socket_address * my_address ,
const struct socket_address * server_address ,
uint32_t flags )
2004-09-13 14:17:41 +00:00
{
2005-07-13 03:25:36 +00:00
if ( sock = = NULL ) {
return NT_STATUS_CONNECTION_DISCONNECTED ;
}
2004-09-13 14:17:41 +00:00
if ( sock - > state ! = SOCKET_STATE_UNDEFINED ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2004-11-02 02:01:04 +00:00
if ( ! sock - > ops - > fn_connect ) {
2004-09-13 14:17:41 +00:00
return NT_STATUS_NOT_IMPLEMENTED ;
}
2006-01-09 22:12:53 +00:00
return sock - > ops - > fn_connect ( sock , my_address , server_address , flags ) ;
2004-09-13 14:17:41 +00:00
}
2006-03-07 16:28:39 +00:00
_PUBLIC_ NTSTATUS socket_connect_complete ( struct socket_context * sock , uint32_t flags )
2005-01-15 10:28:08 +00:00
{
if ( ! sock - > ops - > fn_connect_complete ) {
return NT_STATUS_NOT_IMPLEMENTED ;
}
return sock - > ops - > fn_connect_complete ( sock , flags ) ;
}
2006-03-07 16:28:39 +00:00
_PUBLIC_ NTSTATUS socket_listen ( struct socket_context * sock ,
const struct socket_address * my_address ,
int queue_size , uint32_t flags )
2004-09-13 14:17:41 +00:00
{
2005-07-13 03:25:36 +00:00
if ( sock = = NULL ) {
return NT_STATUS_CONNECTION_DISCONNECTED ;
}
2004-09-13 14:17:41 +00:00
if ( sock - > state ! = SOCKET_STATE_UNDEFINED ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2004-11-02 02:01:04 +00:00
if ( ! sock - > ops - > fn_listen ) {
2004-09-13 14:17:41 +00:00
return NT_STATUS_NOT_IMPLEMENTED ;
}
2006-01-09 22:12:53 +00:00
return sock - > ops - > fn_listen ( sock , my_address , queue_size , flags ) ;
2004-09-13 14:17:41 +00:00
}
2006-03-07 16:28:39 +00:00
_PUBLIC_ NTSTATUS socket_accept ( struct socket_context * sock , struct socket_context * * new_sock )
2004-09-13 14:17:41 +00:00
{
2004-09-26 03:05:04 +00:00
NTSTATUS status ;
2005-07-13 03:25:36 +00:00
if ( sock = = NULL ) {
return NT_STATUS_CONNECTION_DISCONNECTED ;
}
2004-09-13 14:17:41 +00:00
if ( sock - > type ! = SOCKET_TYPE_STREAM ) {
return NT_STATUS_INVALID_PARAMETER ;
}
if ( sock - > state ! = SOCKET_STATE_SERVER_LISTEN ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2004-11-02 02:01:04 +00:00
if ( ! sock - > ops - > fn_accept ) {
2004-09-13 14:17:41 +00:00
return NT_STATUS_NOT_IMPLEMENTED ;
}
2004-11-02 02:01:04 +00:00
status = sock - > ops - > fn_accept ( sock , new_sock ) ;
2004-09-26 03:05:04 +00:00
if ( NT_STATUS_IS_OK ( status ) ) {
talloc_set_destructor ( * new_sock , socket_destructor ) ;
}
return status ;
2004-09-13 14:17:41 +00:00
}
2006-03-07 16:28:39 +00:00
_PUBLIC_ NTSTATUS socket_recv ( struct socket_context * sock , void * buf ,
2006-04-30 05:58:31 +00:00
size_t wantlen , size_t * nread )
2004-09-13 14:17:41 +00:00
{
2005-07-13 03:25:36 +00:00
if ( sock = = NULL ) {
return NT_STATUS_CONNECTION_DISCONNECTED ;
}
2004-09-20 09:13:17 +00:00
if ( sock - > state ! = SOCKET_STATE_CLIENT_CONNECTED & &
2005-05-01 18:49:43 +00:00
sock - > state ! = SOCKET_STATE_SERVER_CONNECTED & &
sock - > type ! = SOCKET_TYPE_DGRAM ) {
2004-09-13 14:17:41 +00:00
return NT_STATUS_INVALID_PARAMETER ;
}
2004-11-02 02:01:04 +00:00
if ( ! sock - > ops - > fn_recv ) {
2004-09-13 14:17:41 +00:00
return NT_STATUS_NOT_IMPLEMENTED ;
}
2004-10-28 07:55:33 +00:00
if ( ( sock - > flags & SOCKET_FLAG_TESTNONBLOCK ) & & wantlen > 1 ) {
2004-10-28 11:57:20 +00:00
if ( random ( ) % 10 = = 0 ) {
* nread = 0 ;
return STATUS_MORE_ENTRIES ;
}
2006-04-30 05:58:31 +00:00
return sock - > ops - > fn_recv ( sock , buf , 1 + ( random ( ) % wantlen ) , nread ) ;
2004-10-28 07:55:33 +00:00
}
2006-04-30 05:58:31 +00:00
return sock - > ops - > fn_recv ( sock , buf , wantlen , nread ) ;
2004-09-13 14:17:41 +00:00
}
2006-03-07 16:28:39 +00:00
_PUBLIC_ NTSTATUS socket_recvfrom ( struct socket_context * sock , void * buf ,
2006-04-30 05:58:31 +00:00
size_t wantlen , size_t * nread ,
2006-03-07 16:28:39 +00:00
TALLOC_CTX * mem_ctx , struct socket_address * * src_addr )
2004-09-13 14:17:41 +00:00
{
2005-07-13 03:25:36 +00:00
if ( sock = = NULL ) {
return NT_STATUS_CONNECTION_DISCONNECTED ;
}
2005-01-19 03:20:20 +00:00
if ( sock - > type ! = SOCKET_TYPE_DGRAM ) {
2004-09-13 14:17:41 +00:00
return NT_STATUS_INVALID_PARAMETER ;
}
2005-01-19 03:20:20 +00:00
if ( ! sock - > ops - > fn_recvfrom ) {
return NT_STATUS_NOT_IMPLEMENTED ;
}
2006-04-30 05:58:31 +00:00
return sock - > ops - > fn_recvfrom ( sock , buf , wantlen , nread ,
2006-01-09 22:12:53 +00:00
mem_ctx , src_addr ) ;
2005-01-19 03:20:20 +00:00
}
2006-03-07 16:28:39 +00:00
_PUBLIC_ NTSTATUS socket_send ( struct socket_context * sock ,
2006-04-30 05:58:31 +00:00
const DATA_BLOB * blob , size_t * sendlen )
2005-01-19 03:20:20 +00:00
{
2005-07-13 03:25:36 +00:00
if ( sock = = NULL ) {
return NT_STATUS_CONNECTION_DISCONNECTED ;
}
2004-09-20 09:13:17 +00:00
if ( sock - > state ! = SOCKET_STATE_CLIENT_CONNECTED & &
2004-09-13 14:17:41 +00:00
sock - > state ! = SOCKET_STATE_SERVER_CONNECTED ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2004-11-02 02:01:04 +00:00
if ( ! sock - > ops - > fn_send ) {
2004-09-13 14:17:41 +00:00
return NT_STATUS_NOT_IMPLEMENTED ;
}
2004-10-28 07:55:33 +00:00
if ( ( sock - > flags & SOCKET_FLAG_TESTNONBLOCK ) & & blob - > length > 1 ) {
DATA_BLOB blob2 = * blob ;
2004-10-28 11:57:20 +00:00
if ( random ( ) % 10 = = 0 ) {
* sendlen = 0 ;
return STATUS_MORE_ENTRIES ;
}
blob2 . length = 1 + ( random ( ) % blob2 . length ) ;
2006-04-30 05:58:31 +00:00
return sock - > ops - > fn_send ( sock , & blob2 , sendlen ) ;
2004-10-28 07:55:33 +00:00
}
2006-04-30 05:58:31 +00:00
return sock - > ops - > fn_send ( sock , blob , sendlen ) ;
2004-09-13 14:17:41 +00:00
}
2005-01-19 03:20:20 +00:00
2006-03-07 16:28:39 +00:00
_PUBLIC_ NTSTATUS socket_sendto ( struct socket_context * sock ,
2006-04-30 05:58:31 +00:00
const DATA_BLOB * blob , size_t * sendlen ,
2006-03-07 16:28:39 +00:00
const struct socket_address * dest_addr )
2005-01-19 03:20:20 +00:00
{
2005-07-13 03:25:36 +00:00
if ( sock = = NULL ) {
return NT_STATUS_CONNECTION_DISCONNECTED ;
}
2005-01-19 03:20:20 +00:00
if ( sock - > type ! = SOCKET_TYPE_DGRAM ) {
return NT_STATUS_INVALID_PARAMETER ;
}
if ( sock - > state = = SOCKET_STATE_CLIENT_CONNECTED | |
sock - > state = = SOCKET_STATE_SERVER_CONNECTED ) {
return NT_STATUS_INVALID_PARAMETER ;
}
if ( ! sock - > ops - > fn_sendto ) {
return NT_STATUS_NOT_IMPLEMENTED ;
}
2006-04-30 05:58:31 +00:00
return sock - > ops - > fn_sendto ( sock , blob , sendlen , dest_addr ) ;
2005-01-19 03:20:20 +00:00
}
2005-06-03 13:20:08 +00:00
/*
2005-06-16 05:39:40 +00:00
ask for the number of bytes in a pending incoming packet
2005-06-03 13:20:08 +00:00
*/
2006-03-07 16:28:39 +00:00
_PUBLIC_ NTSTATUS socket_pending ( struct socket_context * sock , size_t * npending )
2005-06-03 13:20:08 +00:00
{
2005-07-13 03:25:36 +00:00
if ( sock = = NULL ) {
return NT_STATUS_CONNECTION_DISCONNECTED ;
}
2005-06-03 13:20:08 +00:00
if ( ! sock - > ops - > fn_pending ) {
return NT_STATUS_NOT_IMPLEMENTED ;
}
return sock - > ops - > fn_pending ( sock , npending ) ;
}
2006-03-07 16:28:39 +00:00
_PUBLIC_ NTSTATUS socket_set_option ( struct socket_context * sock , const char * option , const char * val )
2004-09-13 14:17:41 +00:00
{
2005-07-13 03:25:36 +00:00
if ( sock = = NULL ) {
return NT_STATUS_CONNECTION_DISCONNECTED ;
}
2004-11-02 02:01:04 +00:00
if ( ! sock - > ops - > fn_set_option ) {
2004-09-13 14:17:41 +00:00
return NT_STATUS_NOT_IMPLEMENTED ;
}
2004-11-02 02:01:04 +00:00
return sock - > ops - > fn_set_option ( sock , option , val ) ;
2004-09-13 14:17:41 +00:00
}
2006-03-07 16:28:39 +00:00
_PUBLIC_ char * socket_get_peer_name ( struct socket_context * sock , TALLOC_CTX * mem_ctx )
2004-09-24 03:34:55 +00:00
{
2004-11-02 02:01:04 +00:00
if ( ! sock - > ops - > fn_get_peer_name ) {
2004-09-24 03:34:55 +00:00
return NULL ;
}
2004-11-02 02:01:04 +00:00
return sock - > ops - > fn_get_peer_name ( sock , mem_ctx ) ;
2004-09-24 03:34:55 +00:00
}
2006-03-07 16:28:39 +00:00
_PUBLIC_ struct socket_address * socket_get_peer_addr ( struct socket_context * sock , TALLOC_CTX * mem_ctx )
2004-09-13 14:17:41 +00:00
{
2004-11-02 02:01:04 +00:00
if ( ! sock - > ops - > fn_get_peer_addr ) {
2004-09-13 14:17:41 +00:00
return NULL ;
}
2004-11-02 02:01:04 +00:00
return sock - > ops - > fn_get_peer_addr ( sock , mem_ctx ) ;
2004-09-13 14:17:41 +00:00
}
2006-03-07 16:28:39 +00:00
_PUBLIC_ struct socket_address * socket_get_my_addr ( struct socket_context * sock , TALLOC_CTX * mem_ctx )
2004-09-13 14:17:41 +00:00
{
2004-11-02 02:01:04 +00:00
if ( ! sock - > ops - > fn_get_my_addr ) {
2004-09-13 14:17:41 +00:00
return NULL ;
}
2004-11-02 02:01:04 +00:00
return sock - > ops - > fn_get_my_addr ( sock , mem_ctx ) ;
2004-09-13 14:17:41 +00:00
}
2006-03-07 16:28:39 +00:00
_PUBLIC_ int socket_get_fd ( struct socket_context * sock )
2004-09-13 14:17:41 +00:00
{
2004-11-02 02:01:04 +00:00
if ( ! sock - > ops - > fn_get_fd ) {
2004-09-13 14:17:41 +00:00
return - 1 ;
}
2004-11-02 02:01:04 +00:00
return sock - > ops - > fn_get_fd ( sock ) ;
2004-09-13 14:17:41 +00:00
}
2004-10-29 07:00:14 +00:00
/*
call dup ( ) on a socket , and close the old fd . This is used to change
the fd to the lowest available number , to make select ( ) more
efficient ( select speed depends on the maxiumum fd number passed to
it )
*/
2006-03-07 16:28:39 +00:00
_PUBLIC_ NTSTATUS socket_dup ( struct socket_context * sock )
2004-10-29 07:00:14 +00:00
{
int fd ;
if ( sock - > fd = = - 1 ) {
return NT_STATUS_INVALID_HANDLE ;
}
fd = dup ( sock - > fd ) ;
if ( fd = = - 1 ) {
return map_nt_error_from_unix ( errno ) ;
}
close ( sock - > fd ) ;
sock - > fd = fd ;
return NT_STATUS_OK ;
}
2006-01-09 22:12:53 +00:00
/* Create a new socket_address. The type must match the socket type.
* The host parameter may be an IP or a hostname
*/
2006-03-07 16:28:39 +00:00
_PUBLIC_ struct socket_address * socket_address_from_strings ( TALLOC_CTX * mem_ctx ,
const char * family ,
const char * host ,
int port )
2006-01-09 22:12:53 +00:00
{
struct socket_address * addr = talloc ( mem_ctx , struct socket_address ) ;
if ( ! addr ) {
return NULL ;
}
addr - > family = family ;
addr - > addr = talloc_strdup ( addr , host ) ;
if ( ! addr - > addr ) {
talloc_free ( addr ) ;
return NULL ;
}
addr - > port = port ;
addr - > sockaddr = NULL ;
addr - > sockaddrlen = 0 ;
return addr ;
}
/* Create a new socket_address. Copy the struct sockaddr into the new
* structure . Used for hooks in the kerberos libraries , where they
* supply only a struct sockaddr */
2006-03-07 16:28:39 +00:00
_PUBLIC_ struct socket_address * socket_address_from_sockaddr ( TALLOC_CTX * mem_ctx ,
struct sockaddr * sockaddr ,
size_t sockaddrlen )
2006-01-09 22:12:53 +00:00
{
struct socket_address * addr = talloc ( mem_ctx , struct socket_address ) ;
if ( ! addr ) {
return NULL ;
}
addr - > family = NULL ;
addr - > addr = NULL ;
addr - > port = 0 ;
addr - > sockaddr = talloc_memdup ( addr , sockaddr , sockaddrlen ) ;
if ( ! addr - > sockaddr ) {
talloc_free ( addr ) ;
return NULL ;
}
addr - > sockaddrlen = sockaddrlen ;
return addr ;
}
2006-03-07 16:28:39 +00:00
_PUBLIC_ const struct socket_ops * socket_getops_byname ( const char * family , enum socket_type type )
2004-09-13 14:17:41 +00:00
{
2006-03-07 16:28:39 +00:00
extern const struct socket_ops * socket_ipv4_ops ( enum socket_type ) ;
extern const struct socket_ops * socket_ipv6_ops ( enum socket_type ) ;
extern const struct socket_ops * socket_unixdom_ops ( enum socket_type ) ;
2005-02-10 06:59:29 +00:00
2006-01-09 22:12:53 +00:00
if ( strcmp ( " ip " , family ) = = 0 | |
strcmp ( " ipv4 " , family ) = = 0 ) {
2005-01-19 03:20:20 +00:00
return socket_ipv4_ops ( type ) ;
2004-09-13 14:17:41 +00:00
}
2004-10-28 21:36:27 +00:00
# if HAVE_SOCKET_IPV6
2006-01-09 22:12:53 +00:00
if ( strcmp ( " ipv6 " , family ) = = 0 ) {
2004-10-28 21:41:21 +00:00
if ( lp_parm_bool ( - 1 , " socket " , " noipv6 " , False ) ) {
DEBUG ( 3 , ( " IPv6 support was disabled in smb.conf " ) ) ;
return NULL ;
}
2005-01-19 03:20:20 +00:00
return socket_ipv6_ops ( type ) ;
2004-10-28 18:57:48 +00:00
}
2004-10-28 21:36:27 +00:00
# endif
2004-10-28 18:57:48 +00:00
2006-01-09 22:12:53 +00:00
if ( strcmp ( " unix " , family ) = = 0 ) {
2005-01-19 03:20:20 +00:00
return socket_unixdom_ops ( type ) ;
2004-10-17 05:07:07 +00:00
}
2004-09-13 14:17:41 +00:00
return NULL ;
}
2006-04-30 01:32:59 +00:00
enum SOCK_OPT_TYPES { OPT_BOOL , OPT_INT , OPT_ON } ;
static const struct {
const char * name ;
int level ;
int option ;
int value ;
int opttype ;
} socket_options [ ] = {
{ " SO_KEEPALIVE " , SOL_SOCKET , SO_KEEPALIVE , 0 , OPT_BOOL } ,
{ " SO_REUSEADDR " , SOL_SOCKET , SO_REUSEADDR , 0 , OPT_BOOL } ,
{ " SO_BROADCAST " , SOL_SOCKET , SO_BROADCAST , 0 , OPT_BOOL } ,
# ifdef TCP_NODELAY
{ " TCP_NODELAY " , IPPROTO_TCP , TCP_NODELAY , 0 , OPT_BOOL } ,
# endif
# ifdef IPTOS_LOWDELAY
{ " IPTOS_LOWDELAY " , IPPROTO_IP , IP_TOS , IPTOS_LOWDELAY , OPT_ON } ,
# endif
# ifdef IPTOS_THROUGHPUT
{ " IPTOS_THROUGHPUT " , IPPROTO_IP , IP_TOS , IPTOS_THROUGHPUT , OPT_ON } ,
# endif
# ifdef SO_REUSEPORT
{ " SO_REUSEPORT " , SOL_SOCKET , SO_REUSEPORT , 0 , OPT_BOOL } ,
# endif
# ifdef SO_SNDBUF
{ " SO_SNDBUF " , SOL_SOCKET , SO_SNDBUF , 0 , OPT_INT } ,
# endif
# ifdef SO_RCVBUF
{ " SO_RCVBUF " , SOL_SOCKET , SO_RCVBUF , 0 , OPT_INT } ,
# endif
# ifdef SO_SNDLOWAT
{ " SO_SNDLOWAT " , SOL_SOCKET , SO_SNDLOWAT , 0 , OPT_INT } ,
# endif
# ifdef SO_RCVLOWAT
{ " SO_RCVLOWAT " , SOL_SOCKET , SO_RCVLOWAT , 0 , OPT_INT } ,
# endif
# ifdef SO_SNDTIMEO
{ " SO_SNDTIMEO " , SOL_SOCKET , SO_SNDTIMEO , 0 , OPT_INT } ,
# endif
# ifdef SO_RCVTIMEO
{ " SO_RCVTIMEO " , SOL_SOCKET , SO_RCVTIMEO , 0 , OPT_INT } ,
# endif
{ NULL , 0 , 0 , 0 , 0 } } ;
/**
Set user socket options .
* */
_PUBLIC_ void set_socket_options ( int fd , const char * options )
{
const char * * options_list = str_list_make ( NULL , options , " \t , " ) ;
int j ;
if ( ! options_list )
return ;
for ( j = 0 ; options_list [ j ] ; j + + ) {
const char * tok = options_list [ j ] ;
int ret = 0 , i ;
int value = 1 ;
char * p ;
BOOL got_value = False ;
if ( ( p = strchr ( tok , ' = ' ) ) ) {
* p = 0 ;
value = atoi ( p + 1 ) ;
got_value = True ;
}
for ( i = 0 ; socket_options [ i ] . name ; i + + )
if ( strequal ( socket_options [ i ] . name , tok ) )
break ;
if ( ! socket_options [ i ] . name ) {
DEBUG ( 0 , ( " Unknown socket option %s \n " , tok ) ) ;
continue ;
}
switch ( socket_options [ i ] . opttype ) {
case OPT_BOOL :
case OPT_INT :
ret = setsockopt ( fd , socket_options [ i ] . level ,
socket_options [ i ] . option , ( char * ) & value , sizeof ( int ) ) ;
break ;
case OPT_ON :
if ( got_value )
DEBUG ( 0 , ( " syntax error - %s does not take a value \n " , tok ) ) ;
{
int on = socket_options [ i ] . value ;
ret = setsockopt ( fd , socket_options [ i ] . level ,
socket_options [ i ] . option , ( char * ) & on , sizeof ( int ) ) ;
}
break ;
}
if ( ret ! = 0 )
DEBUG ( 0 , ( " Failed to set socket option %s (Error %s) \n " , tok , strerror ( errno ) ) ) ;
}
talloc_free ( options_list ) ;
}