610afbc3e55fd463c69d805806531f9c2cc4d685
[samba.git] / source / 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         strcat(fname,"/");
52         strcat(fname,name);
53         strcat(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         struct connect_record crec;
119         pstring fname;
120         int fd=-1;
121         int i,foundi= -1;
122         int total_recs;
123         
124         if (max_connections <= 0)
125                 return(True);
126         
127         DEBUG(5,("trying claim %s %s %d\n",lp_lockdir(),name,max_connections));
128         
129         pstrcpy(fname,lp_lockdir());
130         trim_string(fname,"","/");
131         
132         if (!directory_exist(fname,NULL))
133                 mkdir(fname,0755);
134         
135         strcat(fname,"/");
136         strcat(fname,name);
137         strcat(fname,".LCK");
138         
139         if (!file_exist(fname,NULL)) {
140                 fd = open(fname,O_RDWR|O_CREAT|O_EXCL, 0644);
141         }
142
143         if (fd == -1) {
144                 fd = open(fname,O_RDWR);
145         }
146         
147         if (fd == -1) {
148                 DEBUG(1,("couldn't open lock file %s\n",fname));
149                 return(False);
150         }
151
152         if (fcntl_lock(fd,F_SETLKW,0,1,F_WRLCK)==False) {
153                 DEBUG(0,("ERROR: can't get lock on %s\n", fname));
154                 return False;
155         }
156
157         total_recs = file_size(fname) / sizeof(crec);
158                         
159         /* find a free spot */
160         for (i=0;i<max_connections;i++) {
161                 if (i>=total_recs || 
162                     lseek(fd,i*sizeof(crec),SEEK_SET) != i*sizeof(crec) ||
163                     read(fd,&crec,sizeof(crec)) != sizeof(crec)) {
164                         if (foundi < 0) foundi = i;
165                         break;
166                 }
167                 
168                 if (Clear && crec.pid && !process_exists(crec.pid)) {
169                         lseek(fd,i*sizeof(crec),SEEK_SET);
170                         bzero((void *)&crec,sizeof(crec));
171                         write(fd, &crec,sizeof(crec));
172                         if (foundi < 0) foundi = i;
173                         continue;
174                 }
175                 if (foundi < 0 && (!crec.pid || !process_exists(crec.pid))) {
176                         foundi=i;
177                         if (!Clear) break;
178                 }
179         }  
180         
181         if (foundi < 0) {
182                 DEBUG(3,("no free locks in %s\n",fname));
183                 if (fcntl_lock(fd,F_SETLKW,0,1,F_UNLCK)==False) {
184                         DEBUG(0,("ERROR: can't release lock on %s\n", fname));
185                 }
186                 close(fd);
187                 return(False);
188         }      
189         
190         /* fill in the crec */
191         bzero((void *)&crec,sizeof(crec));
192         crec.magic = 0x280267;
193         crec.pid = getpid();
194         crec.cnum = cnum;
195         if (cnum != -1) {
196                 crec.uid = Connections[cnum].uid;
197                 crec.gid = Connections[cnum].gid;
198                 StrnCpy(crec.name,lp_servicename(SNUM(cnum)),sizeof(crec.name)-1);
199         }
200         crec.start = time(NULL);
201         
202         StrnCpy(crec.machine,remote_machine,sizeof(crec.machine)-1);
203         StrnCpy(crec.addr,client_addr(),sizeof(crec.addr)-1);
204         
205         /* make our mark */
206         if (lseek(fd,foundi*sizeof(crec),SEEK_SET) != foundi*sizeof(crec) ||
207             write(fd, &crec,sizeof(crec)) != sizeof(crec)) {
208                 if (fcntl_lock(fd,F_SETLKW,0,1,F_UNLCK)==False) {
209                         DEBUG(0,("ERROR: can't release lock on %s\n", fname));
210                 }
211                 close(fd);
212                 return(False);
213         }
214
215         if (fcntl_lock(fd,F_SETLKW,0,1,F_UNLCK)==False) {
216                 DEBUG(0,("ERROR: can't release lock on %s\n", fname));
217         }
218         
219         close(fd);
220         return(True);
221 }