r15854: more talloc_set_destructor() typesafe fixes
[samba.git] / source4 / libcli / dgram / mailslot.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    packet handling for mailslot requests. 
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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 /*
24    This implements "Class 2 mailslots", i.e. the communication mechanism 
25    used for all mailslot packets smaller then 425 bytes. 
26
27    "Class 1 mailslots" (which use SMB) are used for messages larger 
28    then 426 bytes and are supported on some systems. These are not implemented
29    in Samba4 yet, as there don't appear to be any core services that use
30    them.
31
32    425 and 426-byte sized messages are not supported at all.
33 */
34
35 #include "includes.h"
36 #include "lib/events/events.h"
37 #include "dlinklist.h"
38 #include "libcli/dgram/libdgram.h"
39 #include "lib/socket/socket.h"
40
41 /*
42   destroy a mailslot handler
43 */
44 static int dgram_mailslot_destructor(struct dgram_mailslot_handler *dgmslot)
45 {
46         DLIST_REMOVE(dgmslot->dgmsock->mailslot_handlers, dgmslot);
47         return 0;
48 }
49
50 /*
51   start listening on a mailslot. talloc_free() the handle to stop listening
52 */
53 struct dgram_mailslot_handler *dgram_mailslot_listen(struct nbt_dgram_socket *dgmsock,
54                                                      const char *mailslot_name,
55                                                      dgram_mailslot_handler_t handler,
56                                                      void *private)
57 {
58         struct dgram_mailslot_handler *dgmslot;
59
60         dgmslot = talloc(dgmsock, struct dgram_mailslot_handler);
61         if (dgmslot == NULL) return NULL;
62
63         dgmslot->dgmsock = dgmsock;
64         dgmslot->mailslot_name = talloc_strdup(dgmslot, mailslot_name);
65         if (dgmslot->mailslot_name == NULL) {
66                 talloc_free(dgmslot);
67                 return NULL;
68         }
69         dgmslot->handler = handler;
70         dgmslot->private = private;
71
72         DLIST_ADD(dgmsock->mailslot_handlers, dgmslot);
73         talloc_set_destructor(dgmslot, dgram_mailslot_destructor);
74
75         EVENT_FD_READABLE(dgmsock->fde);
76
77         return dgmslot;
78 }
79
80 /*
81   find the handler for a specific mailslot name
82 */
83 struct dgram_mailslot_handler *dgram_mailslot_find(struct nbt_dgram_socket *dgmsock,
84                                                    const char *mailslot_name)
85 {
86         struct dgram_mailslot_handler *h;
87         for (h=dgmsock->mailslot_handlers;h;h=h->next) {
88                 if (strcasecmp(h->mailslot_name, mailslot_name) == 0) {
89                         return h;
90                 }
91         }
92         return NULL;
93 }
94
95 /*
96   check that a datagram packet is a valid mailslot request, and return the 
97   mailslot name if it is, otherwise return NULL
98 */
99 const char *dgram_mailslot_name(struct nbt_dgram_packet *packet)
100 {
101         if (packet->msg_type != DGRAM_DIRECT_UNIQUE &&
102             packet->msg_type != DGRAM_DIRECT_GROUP &&
103             packet->msg_type != DGRAM_BCAST) {
104                 return NULL;
105         }
106         if (packet->data.msg.dgram_body_type != DGRAM_SMB) return NULL;
107         if (packet->data.msg.body.smb.smb_command != SMB_TRANSACTION) return NULL;
108         return packet->data.msg.body.smb.body.trans.mailslot_name;
109 }
110
111
112 /*
113   create a temporary mailslot handler for a reply mailslot, allocating
114   a new mailslot name using the given base name and a random integer extension
115 */
116 struct dgram_mailslot_handler *dgram_mailslot_temp(struct nbt_dgram_socket *dgmsock,
117                                                    const char *mailslot_name,
118                                                    dgram_mailslot_handler_t handler,
119                                                    void *private)
120 {
121         char *name;
122         int i;
123         struct dgram_mailslot_handler *dgmslot;
124
125         /* try a 100 times at most */
126         for (i=0;i<100;i++) {
127                 name = talloc_asprintf(dgmsock, "%s%03u", 
128                                        mailslot_name,
129                                        generate_random() % 1000);
130                 if (name == NULL) return NULL;
131                 if (dgram_mailslot_find(dgmsock, name)) {
132                         talloc_free(name);
133                         return NULL;
134                 }
135                 dgmslot = dgram_mailslot_listen(dgmsock, name, handler, private);
136                 talloc_free(name);
137                 if (dgmslot != NULL) {
138                         return dgmslot;
139                 }
140         }
141         DEBUG(2,("Unable to create temporary mailslot from %s\n", mailslot_name));
142         return NULL;
143 }
144
145
146 /*
147   send a mailslot request
148 */
149 NTSTATUS dgram_mailslot_send(struct nbt_dgram_socket *dgmsock,
150                              enum dgram_msg_type msg_type,
151                              const char *mailslot_name,
152                              struct nbt_name *dest_name,
153                              struct socket_address *_dest,
154                              struct nbt_name *src_name,
155                              DATA_BLOB *request)
156 {
157         TALLOC_CTX *tmp_ctx = talloc_new(dgmsock);
158         struct nbt_dgram_packet packet;
159         struct socket_address *dest;
160         struct dgram_message *msg;
161         struct dgram_smb_packet *smb;
162         struct smb_trans_body *trans;
163         struct socket_address *src;
164         NTSTATUS status;
165
166         if (_dest->port == 0) {
167                 dest = socket_address_from_strings(tmp_ctx, _dest->family, 
168                                                    _dest->addr, lp_dgram_port());
169         } else {
170                 dest = _dest;
171         }
172         if (!dest) {
173                 return NT_STATUS_NO_MEMORY;
174         }
175
176         ZERO_STRUCT(packet);
177         packet.msg_type = msg_type;
178         packet.flags = DGRAM_FLAG_FIRST | DGRAM_NODE_NBDD;
179         packet.dgram_id = generate_random() % UINT16_MAX;
180         src = socket_get_my_addr(dgmsock->sock, tmp_ctx);
181         if (!src) {
182                 return NT_STATUS_NO_MEMORY;
183         }
184         packet.src_addr = src->addr;
185         packet.src_port = src->port;
186
187         msg = &packet.data.msg;
188         /* this length calculation is very crude - it should be based on gensize
189            calls */
190         msg->length = 138 + strlen(mailslot_name) + request->length;
191         msg->offset = 0;
192
193         msg->source_name = *src_name;
194         msg->dest_name = *dest_name;
195         msg->dgram_body_type = DGRAM_SMB;
196
197         smb = &msg->body.smb;
198         smb->smb_command = SMB_TRANSACTION;
199
200         trans = &smb->body.trans;
201         trans->total_data_count = request->length;
202         trans->timeout     = 1000;
203         trans->data_count  = request->length;
204         trans->data_offset = 70 + strlen(mailslot_name);
205         trans->opcode      = 1; /* write mail slot */
206         trans->priority    = 1;
207         trans->class       = 2;
208         trans->mailslot_name = mailslot_name;
209         trans->data = *request;
210
211         status = nbt_dgram_send(dgmsock, &packet, dest);
212
213         talloc_free(tmp_ctx);
214
215         return status;
216 }
217
218 /*
219   return the mailslot data portion from a mailslot packet
220 */
221 DATA_BLOB dgram_mailslot_data(struct nbt_dgram_packet *dgram)
222 {
223         struct smb_trans_body *trans = &dgram->data.msg.body.smb.body.trans;
224         DATA_BLOB ret = trans->data;
225         int pad = trans->data_offset - (70 + strlen(trans->mailslot_name));
226
227         if (pad < 0 || pad > ret.length) {
228                 DEBUG(2,("Badly formatted data in mailslot - pad = %d\n", pad));
229                 return data_blob(NULL, 0);
230         }
231         ret.data += pad;
232         ret.length -= pad;
233         return ret;     
234 }