~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/nmbd/nmbd_responserecordsdb.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   Unix SMB/CIFS implementation.
 
3
   NBT netbios library routines
 
4
   Copyright (C) Andrew Tridgell 1994-1998
 
5
   Copyright (C) Luke Kenneth Casson Leighton 1994-1998
 
6
   Copyright (C) Jeremy Allison 1994-1998
 
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
 
 
23
#include "includes.h"
 
24
 
 
25
int num_response_packets = 0;
 
26
 
 
27
/***************************************************************************
 
28
  Add an expected response record into the list
 
29
  **************************************************************************/
 
30
 
 
31
static void add_response_record(struct subnet_record *subrec,
 
32
                                struct response_record *rrec)
 
33
{
 
34
        num_response_packets++; /* count of total number of packets still around */
 
35
 
 
36
        DEBUG(4,("add_response_record: adding response record id:%hu to subnet %s. num_records:%d\n",
 
37
                rrec->response_id, subrec->subnet_name, num_response_packets));
 
38
 
 
39
        DLIST_ADD_END(subrec->responselist, rrec, struct response_record *);
 
40
}
 
41
 
 
42
/***************************************************************************
 
43
  Remove an expected response record from the list
 
44
  **************************************************************************/
 
45
 
 
46
void remove_response_record(struct subnet_record *subrec,
 
47
                                struct response_record *rrec)
 
48
{
 
49
        /* It is possible this can be called twice,
 
50
           with a rrec pointer that has been freed. So
 
51
           before we inderect into rrec, search for it
 
52
           on the responselist first. Bug #3617. JRA. */
 
53
 
 
54
        struct response_record *p = NULL;
 
55
 
 
56
        for (p = subrec->responselist; p; p = p->next) {
 
57
                if (p == rrec) {
 
58
                        break;
 
59
                }
 
60
        }
 
61
 
 
62
        if (p == NULL) {
 
63
                /* We didn't find rrec on the list. */
 
64
                return;
 
65
        }
 
66
 
 
67
        DLIST_REMOVE(subrec->responselist, rrec);
 
68
 
 
69
        if(rrec->userdata) {
 
70
                if(rrec->userdata->free_fn) {
 
71
                        (*rrec->userdata->free_fn)(rrec->userdata);
 
72
                } else {
 
73
                        ZERO_STRUCTP(rrec->userdata);
 
74
                        SAFE_FREE(rrec->userdata);
 
75
                }
 
76
        }
 
77
 
 
78
        /* Ensure we can delete. */
 
79
        rrec->packet->locked = False;
 
80
        free_packet(rrec->packet);
 
81
 
 
82
        ZERO_STRUCTP(rrec);
 
83
        SAFE_FREE(rrec);
 
84
 
 
85
        num_response_packets--; /* count of total number of packets still around */
 
86
}
 
87
 
 
88
/****************************************************************************
 
89
  Create a response record for an outgoing packet.
 
90
  **************************************************************************/
 
91
 
 
92
struct response_record *make_response_record( struct subnet_record *subrec,
 
93
                                              struct packet_struct *p,
 
94
                                              response_function resp_fn,
 
95
                                              timeout_response_function timeout_fn,
 
96
                                              success_function success_fn,
 
97
                                              fail_function fail_fn,
 
98
                                              struct userdata_struct *userdata)
 
99
{
 
100
        struct response_record *rrec;
 
101
        struct nmb_packet *nmb = &p->packet.nmb;
 
102
 
 
103
        if (!(rrec = SMB_MALLOC_P(struct response_record))) {
 
104
                DEBUG(0,("make_response_queue_record: malloc fail for response_record.\n"));
 
105
                return NULL;
 
106
        }
 
107
 
 
108
        memset((char *)rrec, '\0', sizeof(*rrec));
 
109
 
 
110
        rrec->response_id = nmb->header.name_trn_id;
 
111
 
 
112
        rrec->resp_fn = resp_fn;
 
113
        rrec->timeout_fn = timeout_fn;
 
114
        rrec->success_fn = success_fn;
 
115
        rrec->fail_fn = fail_fn;
 
116
 
 
117
        rrec->packet = p;
 
118
 
 
119
        if(userdata) {
 
120
                /* Intelligent userdata. */
 
121
                if(userdata->copy_fn) {
 
122
                        if((rrec->userdata = (*userdata->copy_fn)(userdata)) == NULL) {
 
123
                                DEBUG(0,("make_response_queue_record: copy fail for userdata.\n"));
 
124
                                ZERO_STRUCTP(rrec);
 
125
                                SAFE_FREE(rrec);
 
126
                                return NULL;
 
127
                        }
 
128
                } else {
 
129
                        /* Primitive userdata, do a memcpy. */
 
130
                        if((rrec->userdata = (struct userdata_struct *)
 
131
                                        SMB_MALLOC(sizeof(struct userdata_struct)+userdata->userdata_len)) == NULL) {
 
132
                                DEBUG(0,("make_response_queue_record: malloc fail for userdata.\n"));
 
133
                                ZERO_STRUCTP(rrec);
 
134
                                SAFE_FREE(rrec);
 
135
                                return NULL;
 
136
                        }
 
137
                        rrec->userdata->copy_fn = userdata->copy_fn;
 
138
                        rrec->userdata->free_fn = userdata->free_fn;
 
139
                        rrec->userdata->userdata_len = userdata->userdata_len;
 
140
                        memcpy(rrec->userdata->data, userdata->data, userdata->userdata_len);
 
141
                }
 
142
        } else {
 
143
                rrec->userdata = NULL;
 
144
        }
 
145
 
 
146
        rrec->num_msgs = 0;
 
147
 
 
148
        if(!nmb->header.nm_flags.bcast)
 
149
                rrec->repeat_interval = 5; /* 5 seconds for unicast packets. */
 
150
        else
 
151
                rrec->repeat_interval = 1; /* XXXX should be in ms */
 
152
        rrec->repeat_count = 3; /* 3 retries */
 
153
        rrec->repeat_time = time(NULL) + rrec->repeat_interval; /* initial retry time */
 
154
 
 
155
        /* This packet is not being processed. */
 
156
        rrec->in_expiration_processing = False;
 
157
 
 
158
        /* Lock the packet so we won't lose it while it's on the list. */
 
159
        p->locked = True;
 
160
 
 
161
        add_response_record(subrec, rrec);
 
162
 
 
163
        return rrec;
 
164
}
 
165
 
 
166
/****************************************************************************
 
167
  Find a response in a subnet's name query response list. 
 
168
  **************************************************************************/
 
169
 
 
170
static struct response_record *find_response_record_on_subnet(
 
171
                                struct subnet_record *subrec, uint16 id)
 
172
{  
 
173
        struct response_record *rrec = NULL;
 
174
 
 
175
        for (rrec = subrec->responselist; rrec; rrec = rrec->next) {
 
176
                if (rrec->response_id == id) {
 
177
                        DEBUG(4, ("find_response_record: found response record id = %hu on subnet %s\n",
 
178
                                id, subrec->subnet_name));
 
179
                        break;
 
180
                }
 
181
        }
 
182
        return rrec;
 
183
}
 
184
 
 
185
/****************************************************************************
 
186
  Find a response in any subnet's name query response list. 
 
187
  **************************************************************************/
 
188
 
 
189
struct response_record *find_response_record(struct subnet_record **ppsubrec,
 
190
                                uint16 id)
 
191
{  
 
192
        struct response_record *rrec = NULL;
 
193
 
 
194
        for ((*ppsubrec) = FIRST_SUBNET; (*ppsubrec); 
 
195
                                (*ppsubrec) = NEXT_SUBNET_INCLUDING_UNICAST(*ppsubrec)) {
 
196
                if((rrec = find_response_record_on_subnet(*ppsubrec, id)) != NULL)
 
197
                        return rrec;
 
198
        }
 
199
 
 
200
        /* There should never be response records on the remote_broadcast subnet.
 
201
                        Sanity check to ensure this is so. */
 
202
        if(remote_broadcast_subnet->responselist != NULL) {
 
203
                DEBUG(0,("find_response_record: response record found on subnet %s. This should \
 
204
never happen !\n", remote_broadcast_subnet->subnet_name));
 
205
        }
 
206
 
 
207
        /* Now check the WINS server subnet if it exists. */
 
208
        if(wins_server_subnet != NULL) {
 
209
                *ppsubrec = wins_server_subnet;
 
210
                if((rrec = find_response_record_on_subnet(*ppsubrec, id))!= NULL)
 
211
                        return rrec;
 
212
        }
 
213
 
 
214
        DEBUG(3,("find_response_record: response packet id %hu received with no \
 
215
matching record.\n", id));
 
216
 
 
217
        *ppsubrec = NULL;
 
218
 
 
219
        return NULL;
 
220
}
 
221
 
 
222
/****************************************************************************
 
223
  Check if a refresh is queued for a particular name on a particular subnet.
 
224
  **************************************************************************/
 
225
   
 
226
bool is_refresh_already_queued(struct subnet_record *subrec, struct name_record *namerec)
 
227
{  
 
228
        struct response_record *rrec = NULL;
 
229
   
 
230
        for (rrec = subrec->responselist; rrec; rrec = rrec->next) {
 
231
                struct packet_struct *p = rrec->packet;
 
232
                struct nmb_packet *nmb = &p->packet.nmb;
 
233
 
 
234
                if((nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_8) ||
 
235
                                (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_9)) {
 
236
                        /* Yes it's a queued refresh - check if the name is correct. */
 
237
                        if(nmb_name_equal(&nmb->question.question_name, &namerec->name))
 
238
                        return True;
 
239
                }
 
240
        }
 
241
 
 
242
        return False;
 
243
}