2005-04-03 04:32:37 +00:00
/*
Unix SMB / CIFS implementation .
low level socket handling for nbt dgram requests ( UDP138 )
Copyright ( C ) Andrew Tridgell 2005
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
2007-07-10 02:07:03 +00:00
the Free Software Foundation ; either version 3 of the License , or
2005-04-03 04:32:37 +00:00
( 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
2007-07-10 02:07:03 +00:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2005-04-03 04:32:37 +00:00
*/
# include "includes.h"
# include "lib/events/events.h"
2008-10-11 21:31:42 +02:00
# include "../lib/util/dlinklist.h"
2005-04-03 04:32:37 +00:00
# include "libcli/dgram/libdgram.h"
# include "lib/socket/socket.h"
2006-03-16 00:23:11 +00:00
# include "librpc/gen_ndr/ndr_nbt.h"
2005-04-03 04:32:37 +00:00
/*
handle recv events on a nbt dgram socket
*/
2005-04-05 08:35:02 +00:00
static void dgm_socket_recv ( struct nbt_dgram_socket * dgmsock )
2005-04-03 04:32:37 +00:00
{
2005-04-05 08:35:02 +00:00
TALLOC_CTX * tmp_ctx = talloc_new ( dgmsock ) ;
2005-04-03 04:32:37 +00:00
NTSTATUS status ;
2006-01-09 22:12:53 +00:00
struct socket_address * src ;
2005-04-03 04:32:37 +00:00
DATA_BLOB blob ;
2005-06-03 13:31:27 +00:00
size_t nread , dsize ;
2005-04-03 04:32:37 +00:00
struct nbt_dgram_packet * packet ;
2005-04-05 08:35:02 +00:00
const char * mailslot_name ;
2007-11-09 19:24:51 +01:00
enum ndr_err_code ndr_err ;
2005-04-03 04:32:37 +00:00
2005-06-03 13:31:27 +00:00
status = socket_pending ( dgmsock - > sock , & dsize ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( tmp_ctx ) ;
return ;
}
blob = data_blob_talloc ( tmp_ctx , NULL , dsize ) ;
2013-09-19 11:18:32 -07:00
if ( ( dsize ! = 0 ) & & ( blob . data = = NULL ) ) {
2005-04-03 04:32:37 +00:00
talloc_free ( tmp_ctx ) ;
return ;
}
2006-04-30 05:58:31 +00:00
status = socket_recvfrom ( dgmsock - > sock , blob . data , blob . length , & nread ,
2006-01-09 22:12:53 +00:00
tmp_ctx , & src ) ;
2005-04-03 04:32:37 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( tmp_ctx ) ;
return ;
}
blob . length = nread ;
2010-11-08 16:02:21 +11:00
DEBUG ( 5 , ( " Received dgram packet of length %d from %s:%d \n " ,
2006-01-09 22:12:53 +00:00
( int ) blob . length , src - > addr , src - > port ) ) ;
2005-04-03 04:32:37 +00:00
packet = talloc ( tmp_ctx , struct nbt_dgram_packet ) ;
if ( packet = = NULL ) {
talloc_free ( tmp_ctx ) ;
return ;
}
/* parse the request */
2010-05-09 17:20:01 +02:00
ndr_err = ndr_pull_struct_blob ( & blob , packet , packet ,
2005-04-03 04:32:37 +00:00
( ndr_pull_flags_fn_t ) ndr_pull_nbt_dgram_packet ) ;
2007-11-09 19:24:51 +01:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
status = ndr_map_error2ntstatus ( ndr_err ) ;
2005-04-03 04:32:37 +00:00
DEBUG ( 2 , ( " Failed to parse incoming NBT DGRAM packet - %s \n " ,
nt_errstr ( status ) ) ) ;
talloc_free ( tmp_ctx ) ;
return ;
}
2005-04-05 08:35:02 +00:00
/* if this is a mailslot message, then see if we can dispatch it to a handler */
mailslot_name = dgram_mailslot_name ( packet ) ;
if ( mailslot_name ) {
struct dgram_mailslot_handler * dgmslot ;
dgmslot = dgram_mailslot_find ( dgmsock , mailslot_name ) ;
if ( dgmslot ) {
2008-05-20 11:54:50 +10:00
dgmslot - > handler ( dgmslot , packet , src ) ;
2005-04-05 08:35:02 +00:00
} else {
DEBUG ( 2 , ( " No mailslot handler for '%s' \n " , mailslot_name ) ) ;
}
} else {
/* dispatch if there is a general handler */
if ( dgmsock - > incoming . handler ) {
2006-01-09 22:12:53 +00:00
dgmsock - > incoming . handler ( dgmsock , packet , src ) ;
2005-04-05 08:35:02 +00:00
}
}
2005-04-03 04:32:37 +00:00
talloc_free ( tmp_ctx ) ;
}
2005-04-05 08:35:02 +00:00
/*
handle send events on a nbt dgram socket
*/
static void dgm_socket_send ( struct nbt_dgram_socket * dgmsock )
{
struct nbt_dgram_request * req ;
NTSTATUS status ;
while ( ( req = dgmsock - > send_queue ) ) {
size_t len ;
len = req - > encoded . length ;
2006-04-30 05:58:31 +00:00
status = socket_sendto ( dgmsock - > sock , & req - > encoded , & len ,
2006-01-09 22:12:53 +00:00
req - > dest ) ;
2005-04-05 08:35:02 +00:00
if ( NT_STATUS_IS_ERR ( status ) ) {
2005-10-27 14:33:12 +00:00
DEBUG ( 3 , ( " Failed to send datagram of length %u to %s:%d: %s \n " ,
2006-01-09 22:12:53 +00:00
( unsigned ) req - > encoded . length , req - > dest - > addr , req - > dest - > port ,
2005-10-27 14:33:12 +00:00
nt_errstr ( status ) ) ) ;
2005-04-05 08:35:02 +00:00
DLIST_REMOVE ( dgmsock - > send_queue , req ) ;
talloc_free ( req ) ;
continue ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) return ;
DLIST_REMOVE ( dgmsock - > send_queue , req ) ;
talloc_free ( req ) ;
}
2010-05-25 15:26:42 -04:00
TEVENT_FD_NOT_WRITEABLE ( dgmsock - > fde ) ;
2005-04-05 08:35:02 +00:00
return ;
}
2005-04-03 04:32:37 +00:00
/*
handle fd events on a nbt_dgram_socket
*/
2008-12-29 20:24:57 +01:00
static void dgm_socket_handler ( struct tevent_context * ev , struct tevent_fd * fde ,
2009-02-02 08:24:00 +01:00
uint16_t flags , void * private_data )
2005-04-03 04:32:37 +00:00
{
2009-02-02 08:24:00 +01:00
struct nbt_dgram_socket * dgmsock = talloc_get_type ( private_data ,
2005-04-03 04:32:37 +00:00
struct nbt_dgram_socket ) ;
2010-05-25 15:26:42 -04:00
if ( flags & TEVENT_FD_WRITE ) {
2005-04-05 08:35:02 +00:00
dgm_socket_send ( dgmsock ) ;
2005-06-11 03:53:39 +00:00
}
2010-05-25 15:26:42 -04:00
if ( flags & TEVENT_FD_READ ) {
2005-04-03 04:32:37 +00:00
dgm_socket_recv ( dgmsock ) ;
}
}
/*
initialise a nbt_dgram_socket . The event_ctx is optional , if provided
then operations will use that event context
*/
struct nbt_dgram_socket * nbt_dgram_socket_init ( TALLOC_CTX * mem_ctx ,
2010-05-09 17:20:01 +02:00
struct tevent_context * event_ctx )
2005-04-03 04:32:37 +00:00
{
struct nbt_dgram_socket * dgmsock ;
NTSTATUS status ;
dgmsock = talloc ( mem_ctx , struct nbt_dgram_socket ) ;
if ( dgmsock = = NULL ) goto failed ;
2009-08-07 17:14:13 +10:00
dgmsock - > event_ctx = event_ctx ;
2005-04-03 04:32:37 +00:00
if ( dgmsock - > event_ctx = = NULL ) goto failed ;
2018-02-15 16:43:59 +01:00
status = socket_create ( dgmsock , " ip " , SOCKET_TYPE_DGRAM ,
& dgmsock - > sock , 0 ) ;
2005-04-03 04:32:37 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) goto failed ;
socket_set_option ( dgmsock - > sock , " SO_BROADCAST " , " 1 " ) ;
2010-05-25 15:26:42 -04:00
dgmsock - > fde = tevent_add_fd ( dgmsock - > event_ctx , dgmsock ,
2005-04-03 04:32:37 +00:00
socket_get_fd ( dgmsock - > sock ) , 0 ,
dgm_socket_handler , dgmsock ) ;
2005-04-05 08:35:02 +00:00
dgmsock - > send_queue = NULL ;
dgmsock - > incoming . handler = NULL ;
dgmsock - > mailslot_handlers = NULL ;
2005-04-03 04:32:37 +00:00
return dgmsock ;
failed :
talloc_free ( dgmsock ) ;
return NULL ;
}
/*
2005-04-05 08:35:02 +00:00
setup a handler for generic incoming requests
2005-04-03 04:32:37 +00:00
*/
NTSTATUS dgram_set_incoming_handler ( struct nbt_dgram_socket * dgmsock ,
void ( * handler ) ( struct nbt_dgram_socket * ,
struct nbt_dgram_packet * ,
2006-01-09 22:12:53 +00:00
struct socket_address * ) ,
2009-02-02 08:24:00 +01:00
void * private_data )
2005-04-03 04:32:37 +00:00
{
dgmsock - > incoming . handler = handler ;
2009-02-02 09:55:58 +01:00
dgmsock - > incoming . private_data = private_data ;
2010-05-25 15:26:42 -04:00
TEVENT_FD_READABLE ( dgmsock - > fde ) ;
2005-04-03 04:32:37 +00:00
return NT_STATUS_OK ;
}
2005-04-05 08:35:02 +00:00
/*
queue a datagram for send
*/
NTSTATUS nbt_dgram_send ( struct nbt_dgram_socket * dgmsock ,
struct nbt_dgram_packet * packet ,
2006-01-09 22:12:53 +00:00
struct socket_address * dest )
2005-04-05 08:35:02 +00:00
{
struct nbt_dgram_request * req ;
NTSTATUS status = NT_STATUS_NO_MEMORY ;
2007-11-09 19:24:51 +01:00
enum ndr_err_code ndr_err ;
2005-04-05 08:35:02 +00:00
req = talloc ( dgmsock , struct nbt_dgram_request ) ;
if ( req = = NULL ) goto failed ;
2006-01-09 22:12:53 +00:00
req - > dest = dest ;
if ( talloc_reference ( req , dest ) = = NULL ) goto failed ;
2005-04-05 08:35:02 +00:00
2010-05-09 17:20:01 +02:00
ndr_err = ndr_push_struct_blob ( & req - > encoded , req , packet ,
2005-04-05 08:35:02 +00:00
( ndr_push_flags_fn_t ) ndr_push_nbt_dgram_packet ) ;
2007-11-09 19:24:51 +01:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
status = ndr_map_error2ntstatus ( ndr_err ) ;
goto failed ;
}
2005-04-05 08:35:02 +00:00
2016-02-05 11:32:18 +01:00
DLIST_ADD_END ( dgmsock - > send_queue , req ) ;
2005-04-05 08:35:02 +00:00
2010-05-25 15:26:42 -04:00
TEVENT_FD_WRITEABLE ( dgmsock - > fde ) ;
2005-04-05 08:35:02 +00:00
return NT_STATUS_OK ;
failed :
talloc_free ( req ) ;
return status ;
}