r6223: added a bit more datagram infrastructure and the beginnings of a test
[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 #include "includes.h"
24 #include "lib/events/events.h"
25 #include "dlinklist.h"
26 #include "libcli/nbt/libnbt.h"
27 #include "libcli/dgram/libdgram.h"
28 #include "lib/socket/socket.h"
29
30 /*
31   destroy a mailslot handler
32 */
33 static int dgram_mailslot_destructor(void *ptr)
34 {
35         struct dgram_mailslot_handler *dgmslot = 
36                 talloc_get_type(ptr, struct dgram_mailslot_handler);
37         
38         DLIST_REMOVE(dgmslot->dgmsock->mailslot_handlers, dgmslot);
39         return 0;
40 }
41
42 /*
43   start listening on a mailslot. talloc_free() the handle to stop listening
44 */
45 struct dgram_mailslot_handler *dgram_mailslot_listen(struct nbt_dgram_socket *dgmsock,
46                                                      const char *mailslot_name,
47                                                      dgram_mailslot_handler_t handler,
48                                                      void *private)
49 {
50         struct dgram_mailslot_handler *dgmslot;
51
52         dgmslot = talloc(dgmsock, struct dgram_mailslot_handler);
53         if (dgmslot == NULL) return NULL;
54
55         dgmslot->dgmsock = dgmsock;
56         dgmslot->mailslot_name = talloc_strdup(dgmslot, mailslot_name);
57         if (dgmslot->mailslot_name == NULL) {
58                 talloc_free(dgmslot);
59                 return NULL;
60         }
61         dgmslot->handler = handler;
62         dgmslot->private = private;
63
64         DLIST_ADD(dgmsock->mailslot_handlers, dgmslot);
65         talloc_set_destructor(dgmslot, dgram_mailslot_destructor);
66
67         return dgmslot;
68 }
69
70 /*
71   find the handler for a specific mailslot name
72 */
73 struct dgram_mailslot_handler *dgram_mailslot_find(struct nbt_dgram_socket *dgmsock,
74                                                    const char *mailslot_name)
75 {
76         struct dgram_mailslot_handler *h;
77         for (h=dgmsock->mailslot_handlers;h;h=h->next) {
78                 if (strcasecmp(h->mailslot_name, mailslot_name) == 0) {
79                         return h;
80                 }
81         }
82         return NULL;
83 }
84
85 /*
86   check that a datagram packet is a valid mailslot request, and return the 
87   mailslot name if it is, otherwise return NULL
88 */
89 const char *dgram_mailslot_name(struct nbt_dgram_packet *packet)
90 {
91         if (packet->msg_type != DGRAM_DIRECT_UNIQUE &&
92             packet->msg_type != DGRAM_DIRECT_GROUP &&
93             packet->msg_type != DGRAM_BCAST) {
94                 return NULL;
95         }
96         if (packet->data.msg.dgram_body_type != DGRAM_SMB) return NULL;
97         if (packet->data.msg.body.smb.smb_command != SMB_TRANSACTION) return NULL;
98         if (packet->data.msg.body.smb.smb_command != SMB_TRANSACTION) return NULL;
99         return packet->data.msg.body.smb.body.trans.mailslot_name;
100 }
101
102
103 /*
104   create a temporary mailslot handler for a reply mailslot, allocating
105   a new mailslot name using the given base name and a random integer extension
106 */
107 struct dgram_mailslot_handler *dgram_mailslot_temp(struct nbt_dgram_socket *dgmsock,
108                                                    const char *mailslot_name,
109                                                    dgram_mailslot_handler_t handler,
110                                                    void *private)
111 {
112         char *name;
113         int i;
114         struct dgram_mailslot_handler *dgmslot;
115
116         /* try a 100 times at most */
117         for (i=0;i<100;i++) {
118                 name = talloc_asprintf(dgmsock, "%s%03u", 
119                                        mailslot_name,
120                                        generate_random() % 1000);
121                 if (name == NULL) return NULL;
122                 if (dgram_mailslot_find(dgmsock, name)) {
123                         talloc_free(name);
124                         return NULL;
125                 }
126                 dgmslot = dgram_mailslot_listen(dgmsock, name, handler, private);
127                 talloc_free(name);
128                 return dgmslot;
129         }
130         DEBUG(2,("Unable to create temporary mailslot from %s\n", mailslot_name));
131         return NULL;
132 }
133
134
135 /*
136   send a mailslot request
137 */
138 NTSTATUS dgram_mailslot_send(struct nbt_dgram_socket *dgmsock,
139                              enum dgram_msg_type msg_type,
140                              const char *mailslot_name,
141                              struct nbt_name *dest_name,
142                              const char *dest_address,
143                              struct nbt_name *src_name,
144                              DATA_BLOB *request)
145 {
146         TALLOC_CTX *tmp_ctx = talloc_new(dgmsock);
147         struct nbt_dgram_packet packet;
148         struct dgram_message *msg;
149         struct dgram_smb_packet *smb;
150         struct smb_trans_body *trans;
151         NTSTATUS status;
152
153         ZERO_STRUCT(packet);
154         packet.msg_type = msg_type;
155         packet.flags = DGRAM_FLAG_FIRST;
156         packet.dgram_id = generate_random() % UINT16_MAX;
157         packet.source = socket_get_my_addr(dgmsock->sock, tmp_ctx);
158         packet.src_port = socket_get_my_port(dgmsock->sock);
159
160         msg = &packet.data.msg;
161         /* this length calculation is very crude - it should be based on gensize
162            calls */
163         msg->length = 138 + strlen(mailslot_name) + request->length; 
164         msg->offset = 0;
165
166         msg->source_name = *src_name;
167         msg->dest_name = *dest_name;
168         msg->dgram_body_type = DGRAM_SMB;
169
170         smb = &msg->body.smb;
171         smb->smb_command = SMB_TRANSACTION;
172
173         trans = &smb->body.trans;
174         trans->total_data_count = request->length;
175         trans->timeout     = (uint32_t)-1;
176         trans->data_count  = request->length;
177         trans->data_offset = 70 + strlen(mailslot_name);
178         trans->opcode      = 1; /* write mail slot */
179         trans->priority    = 1;
180         trans->class       = 2;
181         trans->mailslot_name = mailslot_name;
182         trans->data = *request;
183
184         status = nbt_dgram_send(dgmsock, &packet, dest_address, lp_dgram_port());
185
186         talloc_free(tmp_ctx);
187
188         return status;
189 }