root/source4/libcli/dgram/dgramsocket.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dgm_socket_recv
  2. dgm_socket_send
  3. dgm_socket_handler
  4. nbt_dgram_socket_init
  5. dgram_set_incoming_handler
  6. nbt_dgram_send

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    low level socket handling for nbt dgram requests (UDP138)
   5 
   6    Copyright (C) Andrew Tridgell 2005
   7    
   8    This program is free software; you can redistribute it and/or modify
   9    it under the terms of the GNU General Public License as published by
  10    the Free Software Foundation; either version 3 of the License, or
  11    (at your option) any later version.
  12    
  13    This program is distributed in the hope that it will be useful,
  14    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16    GNU General Public License for more details.
  17    
  18    You should have received a copy of the GNU General Public License
  19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  20 */
  21 
  22 #include "includes.h"
  23 #include "lib/events/events.h"
  24 #include "../lib/util/dlinklist.h"
  25 #include "libcli/dgram/libdgram.h"
  26 #include "lib/socket/socket.h"
  27 #include "librpc/gen_ndr/ndr_nbt.h"
  28 
  29 
  30 /*
  31   handle recv events on a nbt dgram socket
  32 */
  33 static void dgm_socket_recv(struct nbt_dgram_socket *dgmsock)
     /* [<][>][^][v][top][bottom][index][help] */
  34 {
  35         TALLOC_CTX *tmp_ctx = talloc_new(dgmsock);
  36         NTSTATUS status;
  37         struct socket_address *src;
  38         DATA_BLOB blob;
  39         size_t nread, dsize;
  40         struct nbt_dgram_packet *packet;
  41         const char *mailslot_name;
  42         enum ndr_err_code ndr_err;
  43 
  44         status = socket_pending(dgmsock->sock, &dsize);
  45         if (!NT_STATUS_IS_OK(status)) {
  46                 talloc_free(tmp_ctx);
  47                 return;
  48         }
  49 
  50         blob = data_blob_talloc(tmp_ctx, NULL, dsize);
  51         if (blob.data == NULL) {
  52                 talloc_free(tmp_ctx);
  53                 return;
  54         }
  55 
  56         status = socket_recvfrom(dgmsock->sock, blob.data, blob.length, &nread,
  57                                  tmp_ctx, &src);
  58         if (!NT_STATUS_IS_OK(status)) {
  59                 talloc_free(tmp_ctx);
  60                 return;
  61         }
  62         blob.length = nread;
  63 
  64         DEBUG(2,("Received dgram packet of length %d from %s:%d\n", 
  65                  (int)blob.length, src->addr, src->port));
  66 
  67         packet = talloc(tmp_ctx, struct nbt_dgram_packet);
  68         if (packet == NULL) {
  69                 talloc_free(tmp_ctx);
  70                 return;
  71         }
  72 
  73         /* parse the request */
  74         ndr_err = ndr_pull_struct_blob(&blob, packet, dgmsock->iconv_convenience, packet,
  75                                       (ndr_pull_flags_fn_t)ndr_pull_nbt_dgram_packet);
  76         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
  77                 status = ndr_map_error2ntstatus(ndr_err);
  78                 DEBUG(2,("Failed to parse incoming NBT DGRAM packet - %s\n",
  79                          nt_errstr(status)));
  80                 talloc_free(tmp_ctx);
  81                 return;
  82         }
  83 
  84         /* if this is a mailslot message, then see if we can dispatch it to a handler */
  85         mailslot_name = dgram_mailslot_name(packet);
  86         if (mailslot_name) {
  87                 struct dgram_mailslot_handler *dgmslot;
  88                 dgmslot = dgram_mailslot_find(dgmsock, mailslot_name);
  89                 if (dgmslot) {
  90                         dgmslot->handler(dgmslot, packet, src);
  91                 } else {
  92                         DEBUG(2,("No mailslot handler for '%s'\n", mailslot_name));
  93                 }
  94         } else {
  95                 /* dispatch if there is a general handler */
  96                 if (dgmsock->incoming.handler) {
  97                         dgmsock->incoming.handler(dgmsock, packet, src);
  98                 }
  99         }
 100 
 101         talloc_free(tmp_ctx);
 102 }
 103 
 104 
 105 /*
 106   handle send events on a nbt dgram socket
 107 */
 108 static void dgm_socket_send(struct nbt_dgram_socket *dgmsock)
     /* [<][>][^][v][top][bottom][index][help] */
 109 {
 110         struct nbt_dgram_request *req;
 111         NTSTATUS status;
 112 
 113         while ((req = dgmsock->send_queue)) {
 114                 size_t len;
 115                 
 116                 len = req->encoded.length;
 117                 status = socket_sendto(dgmsock->sock, &req->encoded, &len,
 118                                        req->dest);
 119                 if (NT_STATUS_IS_ERR(status)) {
 120                         DEBUG(3,("Failed to send datagram of length %u to %s:%d: %s\n",
 121                                  (unsigned)req->encoded.length, req->dest->addr, req->dest->port, 
 122                                  nt_errstr(status)));
 123                         DLIST_REMOVE(dgmsock->send_queue, req);
 124                         talloc_free(req);
 125                         continue;
 126                 }
 127 
 128                 if (!NT_STATUS_IS_OK(status)) return;
 129 
 130                 DLIST_REMOVE(dgmsock->send_queue, req);
 131                 talloc_free(req);
 132         }
 133 
 134         EVENT_FD_NOT_WRITEABLE(dgmsock->fde);
 135         return;
 136 }
 137 
 138 
 139 /*
 140   handle fd events on a nbt_dgram_socket
 141 */
 142 static void dgm_socket_handler(struct tevent_context *ev, struct tevent_fd *fde,
     /* [<][>][^][v][top][bottom][index][help] */
 143                                uint16_t flags, void *private_data)
 144 {
 145         struct nbt_dgram_socket *dgmsock = talloc_get_type(private_data,
 146                                                            struct nbt_dgram_socket);
 147         if (flags & EVENT_FD_WRITE) {
 148                 dgm_socket_send(dgmsock);
 149         } 
 150         if (flags & EVENT_FD_READ) {
 151                 dgm_socket_recv(dgmsock);
 152         }
 153 }
 154 
 155 /*
 156   initialise a nbt_dgram_socket. The event_ctx is optional, if provided
 157   then operations will use that event context
 158 */
 159 struct nbt_dgram_socket *nbt_dgram_socket_init(TALLOC_CTX *mem_ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 160                                               struct tevent_context *event_ctx,
 161                                               struct smb_iconv_convenience *iconv_convenience)
 162 {
 163         struct nbt_dgram_socket *dgmsock;
 164         NTSTATUS status;
 165 
 166         dgmsock = talloc(mem_ctx, struct nbt_dgram_socket);
 167         if (dgmsock == NULL) goto failed;
 168 
 169         dgmsock->event_ctx = talloc_reference(dgmsock, event_ctx);
 170         if (dgmsock->event_ctx == NULL) goto failed;
 171 
 172         status = socket_create("ip", SOCKET_TYPE_DGRAM, &dgmsock->sock, 0);
 173         if (!NT_STATUS_IS_OK(status)) goto failed;
 174 
 175         socket_set_option(dgmsock->sock, "SO_BROADCAST", "1");
 176 
 177         talloc_steal(dgmsock, dgmsock->sock);
 178 
 179         dgmsock->fde = event_add_fd(dgmsock->event_ctx, dgmsock, 
 180                                     socket_get_fd(dgmsock->sock), 0,
 181                                     dgm_socket_handler, dgmsock);
 182 
 183         dgmsock->send_queue = NULL;
 184         dgmsock->incoming.handler = NULL;
 185         dgmsock->mailslot_handlers = NULL;
 186         dgmsock->iconv_convenience = iconv_convenience;
 187         
 188         return dgmsock;
 189 
 190 failed:
 191         talloc_free(dgmsock);
 192         return NULL;
 193 }
 194 
 195 
 196 /*
 197   setup a handler for generic incoming requests
 198 */
 199 NTSTATUS dgram_set_incoming_handler(struct nbt_dgram_socket *dgmsock,
     /* [<][>][^][v][top][bottom][index][help] */
 200                                     void (*handler)(struct nbt_dgram_socket *, 
 201                                                     struct nbt_dgram_packet *, 
 202                                                     struct socket_address *),
 203                                     void *private_data)
 204 {
 205         dgmsock->incoming.handler = handler;
 206         dgmsock->incoming.private_data = private_data;
 207         EVENT_FD_READABLE(dgmsock->fde);
 208         return NT_STATUS_OK;
 209 }
 210 
 211 
 212 /*
 213   queue a datagram for send
 214 */
 215 NTSTATUS nbt_dgram_send(struct nbt_dgram_socket *dgmsock,
     /* [<][>][^][v][top][bottom][index][help] */
 216                         struct nbt_dgram_packet *packet,
 217                         struct socket_address *dest)
 218 {
 219         struct nbt_dgram_request *req;
 220         NTSTATUS status = NT_STATUS_NO_MEMORY;
 221         enum ndr_err_code ndr_err;
 222 
 223         req = talloc(dgmsock, struct nbt_dgram_request);
 224         if (req == NULL) goto failed;
 225 
 226         req->dest = dest;
 227         if (talloc_reference(req, dest) == NULL) goto failed;
 228 
 229         ndr_err = ndr_push_struct_blob(&req->encoded, req, dgmsock->iconv_convenience, packet,
 230                                       (ndr_push_flags_fn_t)ndr_push_nbt_dgram_packet);
 231         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 232                 status = ndr_map_error2ntstatus(ndr_err);
 233                 goto failed;
 234         }
 235 
 236         DLIST_ADD_END(dgmsock->send_queue, req, struct nbt_dgram_request *);
 237 
 238         EVENT_FD_WRITEABLE(dgmsock->fde);
 239 
 240         return NT_STATUS_OK;
 241 
 242 failed:
 243         talloc_free(req);
 244         return status;
 245 }

/* [<][>][^][v][top][bottom][index][help] */