64b3f153cffe81ab11333947f82deb38345b629c
[nivanova/samba-autobuild/.git] / source3 / smbd / connection.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    connection claim routines
5    Copyright (C) Andrew Tridgell 1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24
25 extern connection_struct Connections[MAX_CONNECTIONS];
26 extern fstring remote_machine;
27
28 extern int DEBUGLEVEL;
29
30 /****************************************************************************
31 simple routines to do connection counting
32 ****************************************************************************/
33 BOOL yield_connection(int cnum,char *name,int max_connections)
34 {
35         struct connect_record crec;
36         pstring fname;
37         int fd;
38         int mypid = getpid();
39         int i;
40
41         DEBUG(3,("Yielding connection to %d %s\n",cnum,name));
42
43         if (max_connections <= 0)
44                 return(True);
45
46         bzero(&crec,sizeof(crec));
47
48         pstrcpy(fname,lp_lockdir());
49         trim_string(fname,"","/");
50
51         pstrcat(fname,"/");
52         pstrcat(fname,name);
53         pstrcat(fname,".LCK");
54
55         fd = open(fname,O_RDWR);
56         if (fd == -1) {
57                 DEBUG(2,("Couldn't open lock file %s (%s)\n",fname,strerror(errno)));
58                 return(False);
59         }
60
61         if (fcntl_lock(fd,F_SETLKW,0,1,F_WRLCK)==False) {
62                 DEBUG(0,("ERROR: can't get lock on %s\n", fname));
63                 return False;
64         }
65
66         /* find the right spot */
67         for (i=0;i<max_connections;i++) {
68                 if (read(fd, &crec,sizeof(crec)) != sizeof(crec)) {
69                         DEBUG(2,("Entry not found in lock file %s\n",fname));
70                         if (fcntl_lock(fd,F_SETLKW,0,1,F_UNLCK)==False) {
71                                 DEBUG(0,("ERROR: can't release lock on %s\n", fname));
72                         }
73                         close(fd);
74                         return(False);
75                 }
76                 if (crec.pid == mypid && crec.cnum == cnum)
77                         break;
78         }
79
80         if (crec.pid != mypid || crec.cnum != cnum) {
81                 if (fcntl_lock(fd,F_SETLKW,0,1,F_UNLCK)==False) {
82                         DEBUG(0,("ERROR: can't release lock on %s\n", fname));
83                 }
84                 close(fd);
85                 DEBUG(2,("Entry not found in lock file %s\n",fname));
86                 return(False);
87         }
88
89         bzero((void *)&crec,sizeof(crec));
90   
91         /* remove our mark */
92         if (lseek(fd,i*sizeof(crec),SEEK_SET) != i*sizeof(crec) ||
93             write(fd, &crec,sizeof(crec)) != sizeof(crec)) {
94                 DEBUG(2,("Couldn't update lock file %s (%s)\n",fname,strerror(errno)));
95                 if (fcntl_lock(fd,F_SETLKW,0,1,F_UNLCK)==False) {
96                         DEBUG(0,("ERROR: can't release lock on %s\n", fname));
97                 }
98                 close(fd);
99                 return(False);
100         }
101
102         if (fcntl_lock(fd,F_SETLKW,0,1,F_UNLCK)==False) {
103                 DEBUG(0,("ERROR: can't release lock on %s\n", fname));
104         }
105
106         DEBUG(3,("Yield successful\n"));
107
108         close(fd);
109         return(True);
110 }
111
112
113 /****************************************************************************
114 simple routines to do connection counting
115 ****************************************************************************/
116 BOOL claim_connection(int cnum,char *name,int max_connections,BOOL Clear)
117 {
118         extern int Client;
119         struct connect_record crec;
120         pstring fname;
121         int fd=-1;
122         int i,foundi= -1;
123         int total_recs;
124         
125         if (max_connections <= 0)
126                 return(True);
127         
128         DEBUG(5,("trying claim %s %s %d\n",lp_lockdir(),name,max_connections));
129         
130         pstrcpy(fname,lp_lockdir());
131         trim_string(fname,"","/");
132         
133         if (!directory_exist(fname,NULL))
134                 mkdir(fname,0755);
135         
136         pstrcat(fname,"/");
137         pstrcat(fname,name);
138         pstrcat(fname,".LCK");
139         
140         if (!file_exist(fname,NULL)) {
141                 fd = open(fname,O_RDWR|O_CREAT|O_EXCL, 0644);
142         }
143
144         if (fd == -1) {
145                 fd = open(fname,O_RDWR);
146         }
147         
148         if (fd == -1) {
149                 DEBUG(1,("couldn't open lock file %s\n",fname));
150                 return(False);
151         }
152
153         if (fcntl_lock(fd,F_SETLKW,0,1,F_WRLCK)==False) {
154                 DEBUG(0,("ERROR: can't get lock on %s\n", fname));
155                 return False;
156         }
157
158         total_recs = file_size(fname) / sizeof(crec);
159                         
160         /* find a free spot */
161         for (i=0;i<max_connections;i++) {
162                 if (i>=total_recs || 
163                     lseek(fd,i*sizeof(crec),SEEK_SET) != i*sizeof(crec) ||
164                     read(fd,&crec,sizeof(crec)) != sizeof(crec)) {
165                         if (foundi < 0) foundi = i;
166                         break;
167                 }
168                 
169                 if (Clear && crec.pid && !process_exists(crec.pid)) {
170                         lseek(fd,i*sizeof(crec),SEEK_SET);
171                         bzero((void *)&crec,sizeof(crec));
172                         write(fd, &crec,sizeof(crec));
173                         if (foundi < 0) foundi = i;
174                         continue;
175                 }
176                 if (foundi < 0 && (!crec.pid || !process_exists(crec.pid))) {
177                         foundi=i;
178                         if (!Clear) break;
179                 }
180         }  
181         
182         if (foundi < 0) {
183                 DEBUG(3,("no free locks in %s\n",fname));
184                 if (fcntl_lock(fd,F_SETLKW,0,1,F_UNLCK)==False) {
185                         DEBUG(0,("ERROR: can't release lock on %s\n", fname));
186                 }
187                 close(fd);
188                 return(False);
189         }      
190         
191         /* fill in the crec */
192         bzero((void *)&crec,sizeof(crec));
193         crec.magic = 0x280267;
194         crec.pid = getpid();
195         crec.cnum = cnum;
196         if (cnum != -1) {
197                 crec.uid = Connections[cnum].uid;
198                 crec.gid = Connections[cnum].gid;
199                 StrnCpy(crec.name,lp_servicename(SNUM(cnum)),sizeof(crec.name)-1);
200         }
201         crec.start = time(NULL);
202         
203         StrnCpy(crec.machine,remote_machine,sizeof(crec.machine)-1);
204         StrnCpy(crec.addr,client_addr(Client),sizeof(crec.addr)-1);
205         
206         /* make our mark */
207         if (lseek(fd,foundi*sizeof(crec),SEEK_SET) != foundi*sizeof(crec) ||
208             write(fd, &crec,sizeof(crec)) != sizeof(crec)) {
209                 if (fcntl_lock(fd,F_SETLKW,0,1,F_UNLCK)==False) {
210                         DEBUG(0,("ERROR: can't release lock on %s\n", fname));
211                 }
212                 close(fd);
213                 return(False);
214         }
215
216         if (fcntl_lock(fd,F_SETLKW,0,1,F_UNLCK)==False) {
217                 DEBUG(0,("ERROR: can't release lock on %s\n", fname));
218         }
219         
220         close(fd);
221         return(True);
222 }