r12608: Remove some unused #include lines.
[abartlet/samba.git/.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(void *ptr)
45 {
46         struct dgram_mailslot_handler *dgmslot = 
47                 talloc_get_type(ptr, struct dgram_mailslot_handler);
48         
49         DLIST_REMOVE(dgmslot->dgmsock->mailslot_handlers, dgmslot);
50         return 0;
51 }
52
53 /*
54   start listening on a mailslot. talloc_free() the handle to stop listening
55 */
56 struct dgram_mailslot_handler *dgram_mailslot_listen(struct nbt_dgram_socket *dgmsock,
57                                                      const char *mailslot_name,
58                                                      dgram_mailslot_handler_t handler,
59                                                      void *private)
60 {
61         struct dgram_mailslot_handler *dgmslot;
62
63         dgmslot = talloc(dgmsock, struct dgram_mailslot_handler);
64         if (dgmslot == NULL) return NULL;
65
66         dgmslot->dgmsock = dgmsock;
67         dgmslot->mailslot_name = talloc_strdup(dgmslot, mailslot_name);
68         if (dgmslot->mailslot_name == NULL) {
69                 talloc_free(dgmslot);
70                 return NULL;
71         }
72         dgmslot->handler = handler;
73         dgmslot->private = private;
74
75         DLIST_ADD(dgmsock->mailslot_handlers, dgmslot);
76         talloc_set_destructor(dgmslot, dgram_mailslot_destructor);
77
78         EVENT_FD_READABLE(dgmsock->fde);
79
80         return dgmslot;
81 }
82
83 /*
84   find the handler for a specific mailslot name
85 */
86 struct dgram_mailslot_handler *dgram_mailslot_find(struct nbt_dgram_socket *dgmsock,
87                                                    const char *mailslot_name)
88 {
89         struct dgram_mailslot_handler *h;
90         for (h=dgmsock->mailslot_handlers;h;h=h->next) {
91                 if (strcasecmp(h->mailslot_name, mailslot_name) == 0) {
92                         return h;
93                 }
94         }
95         return NULL;
96 }
97
98 /*
99   check that a datagram packet is a valid mailslot request, and return the 
100   mailslot name if it is, otherwise return NULL
101 */
102 const char *dgram_mailslot_name(struct nbt_dgram_packet *packet)
103 {
104         if (packet->msg_type != DGRAM_DIRECT_UNIQUE &&
105             packet->msg_type != DGRAM_DIRECT_GROUP &&
106             packet->msg_type != DGRAM_BCAST) {
107                 return NULL;
108         }
109         if (packet->data.msg.dgram_body_type != DGRAM_SMB) return NULL;
110         if (packet->data.msg.body.smb.smb_command != SMB_TRANSACTION) return NULL;
111         return packet->data.msg.body.smb.body.trans.mailslot_name;
112 }
113
114
115 /*
116   create a temporary mailslot handler for a reply mailslot, allocating
117   a new mailslot name using the given base name and a random integer extension
118 */
119 struct dgram_mailslot_handler *dgram_mailslot_temp(struct nbt_dgram_socket *dgmsock,
120                                                    const char *mailslot_name,
121                                                    dgram_mailslot_handler_t handler,
122                                                    void *private)
123 {
124         char *name;
125         int i;
126         struct dgram_mailslot_handler *dgmslot;
127
128         /* try a 100 times at most */
129         for (i=0;i<100;i++) {
130                 name = talloc_asprintf(dgmsock, "%s%03u", 
131                                        mailslot_name,
132                                        generate_random() % 1000);
133                 if (name == NULL) return NULL;
134                 if (dgram_mailslot_find(dgmsock, name)) {
135                         talloc_free(name);
136                         return NULL;
137                 }
138                 dgmslot = dgram_mailslot_listen(dgmsock, name, handler, private);
139                 talloc_free(name);
140                 return dgmslot;
141         }
142         DEBUG(2,("Unable to create temporary mailslot from %s\n", mailslot_name));
143         return NULL;
144 }
145
146
147 /*
148   send a mailslot request
149 */
150 NTSTATUS dgram_mailslot_send(struct nbt_dgram_socket *dgmsock,
151                              enum dgram_msg_type msg_type,
152                              const char *mailslot_name,
153                              struct nbt_name *dest_name,
154                              const struct nbt_peer_socket *_dest,
155                              struct nbt_name *src_name,
156                              DATA_BLOB *request)
157 {
158         TALLOC_CTX *tmp_ctx = talloc_new(dgmsock);
159         struct nbt_dgram_packet packet;
160         struct nbt_peer_socket dest = *_dest;
161         struct dgram_message *msg;
162         struct dgram_smb_packet *smb;
163         struct smb_trans_body *trans;
164         NTSTATUS status;
165
166         if (dest.port == 0) {
167                 dest.port = lp_dgram_port();
168         }
169
170         ZERO_STRUCT(packet);
171         packet.msg_type = msg_type;
172         packet.flags = DGRAM_FLAG_FIRST | DGRAM_NODE_NBDD;
173         packet.dgram_id = generate_random() % UINT16_MAX;
174         packet.src_addr = socket_get_my_addr(dgmsock->sock, tmp_ctx);
175         packet.src_port = socket_get_my_port(dgmsock->sock);
176
177         msg = &packet.data.msg;
178         /* this length calculation is very crude - it should be based on gensize
179            calls */
180         msg->length = 138 + strlen(mailslot_name) + request->length;
181         msg->offset = 0;
182
183         msg->source_name = *src_name;
184         msg->dest_name = *dest_name;
185         msg->dgram_body_type = DGRAM_SMB;
186
187         smb = &msg->body.smb;
188         smb->smb_command = SMB_TRANSACTION;
189
190         trans = &smb->body.trans;
191         trans->total_data_count = request->length;
192         trans->timeout     = 1000;
193         trans->data_count  = request->length;
194         trans->data_offset = 70 + strlen(mailslot_name);
195         trans->opcode      = 1; /* write mail slot */
196         trans->priority    = 1;
197         trans->class       = 2;
198         trans->mailslot_name = mailslot_name;
199         trans->data = *request;
200
201         status = nbt_dgram_send(dgmsock, &packet, &dest);
202
203         talloc_free(tmp_ctx);
204
205         return status;
206 }
207
208 /*
209   return the mailslot data portion from a mailslot packet
210 */
211 DATA_BLOB dgram_mailslot_data(struct nbt_dgram_packet *dgram)
212 {
213         struct smb_trans_body *trans = &dgram->data.msg.body.smb.body.trans;
214         DATA_BLOB ret = trans->data;
215         int pad = trans->data_offset - (70 + strlen(trans->mailslot_name));
216
217         if (pad < 0 || pad > ret.length) {
218                 DEBUG(2,("Badly formatted data in mailslot - pad = %d\n", pad));
219                 return data_blob(NULL, 0);
220         }
221         ret.data += pad;
222         ret.length -= pad;
223         return ret;     
224 }