1 /*
2  * Copyright (C) 2016 Jakub Kruszona-Zawadzki, Core Technology Sp. z o.o.
3  *
4  * This file is part of MooseFS.
5  *
6  * MooseFS is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, version 2 (only).
9  *
10  * MooseFS is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with MooseFS; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA
18  * or visit http://www.gnu.org/licenses/gpl-2.0.html
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <stdio.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <syslog.h>
32 #include <errno.h>
33 #include <inttypes.h>
34 
35 #include "MFSCommunication.h"
36 
37 #include "sessions.h"
38 #include "bio.h"
39 #include "filesystem.h"
40 #include "openfiles.h"
41 #include "changelog.h"
42 #include "metadata.h"
43 #include "datapack.h"
44 #include "cfg.h"
45 #include "main.h"
46 #include "slogger.h"
47 #include "massert.h"
48 
49 #define SESSION_STATS 16
50 
51 #define SESSION_HASHSIZE 256
52 #define SESSION_HASH(sessionid) ((sessionid)%(SESSION_HASHSIZE))
53 
54 // opened files
55 /*
56 typedef struct filelist {
57 	uint32_t inode;
58 	struct filelist *next;
59 } filelist;
60 */
61 
62 typedef struct session {
63 	uint32_t sessionid;
64 	char *info;
65 	uint32_t peerip;
66 	uint8_t closed;
67 	uint8_t sesflags;
68 	uint8_t mingoal;
69 	uint8_t maxgoal;
70 	uint32_t mintrashtime;
71 	uint32_t maxtrashtime;
72 	uint32_t rootuid;
73 	uint32_t rootgid;
74 	uint32_t mapalluid;
75 	uint32_t mapallgid;
76 	uint32_t rootinode;
77 	uint32_t disconnected;	// 0 = connected ; other = disconnection timestamp
78 	uint32_t nsocks;	// >0 - connected (number of active connections) ; 0 - not connected
79 	uint32_t infopeerip;	// peer ip for info
80 	uint32_t infoversion;	// version for info
81 	uint32_t currentopstats[SESSION_STATS];
82 	uint32_t lasthouropstats[SESSION_STATS];
83 //	filelist *openedfiles;
84 	struct session *next;
85 } session;
86 
87 static session *sessionshashtab[SESSION_HASHSIZE];
88 // static session *sessionshead=NULL;
89 static uint32_t nextsessionid;
90 
91 static uint32_t SessionSustainTime;
92 
93 static uint32_t starttime;
94 
sessions_attach_session(void * vsesdata,uint32_t peerip,uint32_t version)95 void sessions_attach_session(void* vsesdata,uint32_t peerip,uint32_t version) {
96 	session *sesdata = (session*)vsesdata;
97 	sesdata->closed = 0;
98 	sesdata->nsocks++;
99 	sesdata->infopeerip = peerip;
100 	sesdata->infoversion = version;
101 	sesdata->disconnected = 0;
102 }
103 
sessions_close_session(uint32_t sessionid)104 void sessions_close_session(uint32_t sessionid) {
105 	session *asesdata;
106 	if (sessionid==0) {
107 		return;
108 	}
109 	for (asesdata = sessionshashtab[SESSION_HASH(sessionid)] ; asesdata ; asesdata=asesdata->next) {
110 		if (asesdata->sessionid==sessionid) {
111 			if (asesdata->nsocks==1) {
112 				asesdata->closed = 1;
113 			}
114 		}
115 	}
116 	return;
117 }
118 
sessions_disconnection(void * vsesdata)119 void sessions_disconnection(void *vsesdata) {
120 	session *sesdata = (session*)vsesdata;
121 	if (sesdata) {
122 		if (sesdata->nsocks>0) {
123 			sesdata->nsocks--;
124 		}
125 		if (sesdata->nsocks==0) {
126 			sesdata->disconnected = main_time();
127 			changelog("%"PRIu32"|SESDISCONNECTED(%"PRIu32")",main_time(),sesdata->sessionid);
128 		}
129 	}
130 }
131 
sessions_find_session(uint32_t sessionid)132 void* sessions_find_session(uint32_t sessionid) {
133 	session *asesdata;
134 	if (sessionid==0) {
135 		return NULL;
136 	}
137 	for (asesdata = sessionshashtab[SESSION_HASH(sessionid)] ; asesdata ; asesdata=asesdata->next) {
138 		if (asesdata->sessionid==sessionid) {
139 			return asesdata;
140 		}
141 	}
142 	return NULL;
143 }
144 
sessions_clean_session(session * sesdata)145 static inline void sessions_clean_session(session *sesdata) {
146 //	filelist *fl,*afl;
147 	of_sessionremoved(sesdata->sessionid);
148 //	fl=sesdata->openedfiles;
149 //	while (fl) {
150 //		afl = fl;
151 //		fl=fl->next;
152 //		fs_release(afl->inode,sesdata->sessionid);
153 //		free(afl);
154 //	}
155 //	sesdata->openedfiles=NULL;
156 	if (sesdata->info) {
157 		free(sesdata->info);
158 	}
159 }
160 
sessions_store(bio * fd)161 uint8_t sessions_store(bio *fd) {
162 	session *asesdata;
163 	uint32_t ileng;
164 	uint8_t fsesrecord[47+SESSION_STATS*8]; // 4+4+4+4+1+1+1+4+4+4+4+4+4+SESSION_STATS*4+SESSION_STATS*4
165 	uint8_t *ptr;
166 	int i;
167 	uint32_t hpos;
168 	if (fd==NULL) {
169 		return 0x12;
170 	}
171 	ptr = fsesrecord;
172 	put32bit(&ptr,nextsessionid);
173 	put16bit(&ptr,SESSION_STATS);
174 	if (bio_write(fd,fsesrecord,6)!=6) {
175 		return 0xFF;
176 	}
177 	for (hpos = 0 ; hpos < SESSION_HASHSIZE ; hpos++) {
178 		for (asesdata = sessionshashtab[hpos] ; asesdata ; asesdata=asesdata->next) {
179 			if (asesdata->closed==0) {
180 				ptr = fsesrecord;
181 				if (asesdata->info) {
182 					ileng = strlen(asesdata->info);
183 				} else {
184 					ileng = 0;
185 				}
186 				put32bit(&ptr,asesdata->sessionid);
187 				put32bit(&ptr,ileng);
188 				put32bit(&ptr,asesdata->peerip);
189 				put32bit(&ptr,asesdata->rootinode);
190 				put8bit(&ptr,asesdata->sesflags);
191 				put8bit(&ptr,asesdata->mingoal);
192 				put8bit(&ptr,asesdata->maxgoal);
193 				put32bit(&ptr,asesdata->mintrashtime);
194 				put32bit(&ptr,asesdata->maxtrashtime);
195 				put32bit(&ptr,asesdata->rootuid);
196 				put32bit(&ptr,asesdata->rootgid);
197 				put32bit(&ptr,asesdata->mapalluid);
198 				put32bit(&ptr,asesdata->mapallgid);
199 				put32bit(&ptr,asesdata->disconnected);
200 				for (i=0 ; i<SESSION_STATS ; i++) {
201 					put32bit(&ptr,asesdata->currentopstats[i]);
202 				}
203 				for (i=0 ; i<SESSION_STATS ; i++) {
204 					put32bit(&ptr,asesdata->lasthouropstats[i]);
205 				}
206 				if (bio_write(fd,fsesrecord,(47+SESSION_STATS*8))!=(47+SESSION_STATS*8)) {
207 					return 0xFF;
208 				}
209 				if (ileng>0) {
210 					if (bio_write(fd,asesdata->info,ileng)!=ileng) {
211 						return 0xFF;
212 					}
213 				}
214 			}
215 		}
216 	}
217 	memset(fsesrecord,0,(47+SESSION_STATS*8));
218 	if (bio_write(fd,fsesrecord,(47+SESSION_STATS*8))!=(47+SESSION_STATS*8)) {
219 		return 0xFF;
220 	}
221 	return 0;
222 }
223 
sessions_load(bio * fd,uint8_t mver)224 int sessions_load(bio *fd,uint8_t mver) {
225 	session *asesdata;
226 	uint32_t ileng;
227 	uint8_t hdr[8];
228 	uint8_t *fsesrecord;
229 	const uint8_t *ptr;
230 	uint16_t statsinfile;
231 	uint32_t recsize;
232 	uint32_t i,sessionid,hpos;
233 
234 	if (mver<0x12) {
235 		if (bio_read(fd,hdr,8)!=8) {
236 			return -1;
237 		}
238 
239 		ptr = hdr;
240 		switch (get16bit(&ptr)) {
241 			case 1:
242 				mver = 0x10;
243 				break;
244 			case 2:
245 				mver = 0x11;
246 				break;
247 			default:
248 				return -1;
249 		}
250 	} else {
251 		if (bio_read(fd,hdr,6)!=6) {
252 			return -1;
253 		}
254 
255 		ptr = hdr;
256 	}
257 	nextsessionid = get32bit(&ptr);
258 	statsinfile = get16bit(&ptr);
259 
260 	if (mver<0x11) {
261 		recsize = 43+statsinfile*8;
262 	} else {
263 		recsize = 47+statsinfile*8;
264 	}
265 	fsesrecord = malloc(recsize);
266 	passert(fsesrecord);
267 
268 	while(1) {
269 		if (bio_read(fd,fsesrecord,recsize)==recsize) {
270 			ptr = fsesrecord;
271 			sessionid = get32bit(&ptr);
272 			if (sessionid==0) {
273 				free(fsesrecord);
274 				return 0;
275 			}
276 			asesdata = (session*)malloc(sizeof(session));
277 			passert(asesdata);
278 			asesdata->sessionid = sessionid;
279 			ileng = get32bit(&ptr);
280 			asesdata->peerip = get32bit(&ptr);
281 			asesdata->rootinode = get32bit(&ptr);
282 			asesdata->sesflags = get8bit(&ptr);
283 			asesdata->mingoal = get8bit(&ptr);
284 			asesdata->maxgoal = get8bit(&ptr);
285 			asesdata->mintrashtime = get32bit(&ptr);
286 			asesdata->maxtrashtime = get32bit(&ptr);
287 			asesdata->rootuid = get32bit(&ptr);
288 			asesdata->rootgid = get32bit(&ptr);
289 			asesdata->mapalluid = get32bit(&ptr);
290 			asesdata->mapallgid = get32bit(&ptr);
291 			if (mver>=0x11) {
292 				asesdata->disconnected = get32bit(&ptr);
293 			} else {
294 				asesdata->disconnected = main_time();
295 			}
296 			asesdata->info = NULL;
297 			asesdata->closed = 0;
298 //			asesdata->openedfiles = NULL;
299 			asesdata->nsocks = 0;
300 			asesdata->infopeerip = asesdata->peerip;
301 			asesdata->infoversion = 0;
302 			for (i=0 ; i<SESSION_STATS ; i++) {
303 				asesdata->currentopstats[i] = (i<statsinfile)?get32bit(&ptr):0;
304 			}
305 			if (statsinfile>SESSION_STATS) {
306 				ptr+=4*(statsinfile-SESSION_STATS);
307 			}
308 			for (i=0 ; i<SESSION_STATS ; i++) {
309 				asesdata->lasthouropstats[i] = (i<statsinfile)?get32bit(&ptr):0;
310 			}
311 			if (ileng>0) {
312 				asesdata->info = malloc(ileng+1);
313 				passert(asesdata->info);
314 				if (bio_read(fd,asesdata->info,ileng)!=ileng) {
315 					free(asesdata->info);
316 					free(asesdata);
317 					free(fsesrecord);
318 					return -1;
319 				}
320 				asesdata->info[ileng]=0;
321 			}
322 			hpos = SESSION_HASH(sessionid);
323 			asesdata->next = sessionshashtab[hpos];
324 			sessionshashtab[hpos] = asesdata;
325 		} else {
326 			free(fsesrecord);
327 			return -1;
328 		}
329 	}
330 }
331 
332 /* import from old metadata */
sessions_set_nextsessionid(uint32_t nsi)333 void sessions_set_nextsessionid(uint32_t nsi) {
334 	nextsessionid = nsi;
335 }
336 /*
337 uint32_t sessions_getnextsessionid(void) {
338 	return nextsessionid;
339 }
340 */
sessions_import_data(void)341 int sessions_import_data(void) {
342 	session *asesdata;
343 	uint32_t ileng;
344 //	uint8_t fsesrecord[33+SESSION_STATS*8];	// 4+4+4+4+1+4+4+4+4+SESSION_STATS*4+SESSION_STATS*4
345 	uint8_t hdr[8];
346 	uint8_t *fsesrecord;
347 	const uint8_t *ptr;
348 	uint8_t mapalldata;
349 	uint8_t goaltrashdata;
350 	uint32_t i,statsinfile;
351 	uint32_t hpos;
352 	int r;
353 	FILE *fd;
354 
355 	fd = fopen("sessions.mfs","r");
356 	if (fd==NULL) {
357 		mfs_errlog_silent(LOG_WARNING,"can't load sessions, fopen error");
358 		if (errno==ENOENT) {	// it's ok if file does not exist
359 			nextsessionid = 1;
360 			return 0;
361 		} else {
362 			return -1;
363 		}
364 	}
365 	if (fread(hdr,8,1,fd)!=1) {
366 		syslog(LOG_WARNING,"can't load sessions, fread error");
367 		fclose(fd);
368 		return -1;
369 	}
370 	if (memcmp(hdr,MFSSIGNATURE "S 1.5",8)==0) {
371 		mapalldata = 0;
372 		goaltrashdata = 0;
373 		statsinfile = 16;
374 	} else if (memcmp(hdr,MFSSIGNATURE "S \001\006\001",8)==0) {
375 		mapalldata = 1;
376 		goaltrashdata = 0;
377 		statsinfile = 16;
378 	} else if (memcmp(hdr,MFSSIGNATURE "S \001\006\002",8)==0) {
379 		mapalldata = 1;
380 		goaltrashdata = 0;
381 		statsinfile = 21;
382 	} else if (memcmp(hdr,MFSSIGNATURE "S \001\006\003",8)==0) {
383 		mapalldata = 1;
384 		goaltrashdata = 0;
385 		if (fread(hdr,2,1,fd)!=1) {
386 			syslog(LOG_WARNING,"can't load sessions, fread error");
387 			fclose(fd);
388 			return -1;
389 		}
390 		ptr = hdr;
391 		statsinfile = get16bit(&ptr);
392 	} else if (memcmp(hdr,MFSSIGNATURE "S \001\006\004",8)==0) {
393 		mapalldata = 1;
394 		goaltrashdata = 1;
395 		if (fread(hdr,2,1,fd)!=1) {
396 			syslog(LOG_WARNING,"can't load sessions, fread error");
397 			fclose(fd);
398 			return -1;
399 		}
400 		ptr = hdr;
401 		statsinfile = get16bit(&ptr);
402 	} else {
403 		syslog(LOG_WARNING,"can't load sessions, bad header");
404 		fclose(fd);
405 		return -1;
406 	}
407 
408 	if (mapalldata==0) {
409 		fsesrecord = malloc(25+statsinfile*8);
410 	} else if (goaltrashdata==0) {
411 		fsesrecord = malloc(33+statsinfile*8);
412 	} else {
413 		fsesrecord = malloc(43+statsinfile*8);
414 	}
415 	passert(fsesrecord);
416 
417 	while (!feof(fd)) {
418 		if (mapalldata==0) {
419 			r = fread(fsesrecord,25+statsinfile*8,1,fd);
420 		} else if (goaltrashdata==0) {
421 			r = fread(fsesrecord,33+statsinfile*8,1,fd);
422 		} else {
423 			r = fread(fsesrecord,43+statsinfile*8,1,fd);
424 		}
425 		if (r==1) {
426 			ptr = fsesrecord;
427 			asesdata = (session*)malloc(sizeof(session));
428 			passert(asesdata);
429 			asesdata->sessionid = get32bit(&ptr);
430 			ileng = get32bit(&ptr);
431 			asesdata->peerip = get32bit(&ptr);
432 			asesdata->rootinode = get32bit(&ptr);
433 			asesdata->sesflags = get8bit(&ptr);
434 			if (goaltrashdata) {
435 				asesdata->mingoal = get8bit(&ptr);
436 				asesdata->maxgoal = get8bit(&ptr);
437 				asesdata->mintrashtime = get32bit(&ptr);
438 				asesdata->maxtrashtime = get32bit(&ptr);
439 			} else { // set defaults (no limits)
440 				asesdata->mingoal = 1;
441 				asesdata->maxgoal = 9;
442 				asesdata->mintrashtime = 0;
443 				asesdata->maxtrashtime = UINT32_C(0xFFFFFFFF);
444 			}
445 			asesdata->rootuid = get32bit(&ptr);
446 			asesdata->rootgid = get32bit(&ptr);
447 			if (mapalldata) {
448 				asesdata->mapalluid = get32bit(&ptr);
449 				asesdata->mapallgid = get32bit(&ptr);
450 			} else {
451 				asesdata->mapalluid = 0;
452 				asesdata->mapallgid = 0;
453 			}
454 			asesdata->info = NULL;
455 			asesdata->closed = 0;
456 //			asesdata->openedfiles = NULL;
457 			asesdata->disconnected = main_time();
458 			asesdata->nsocks = 0;
459 			asesdata->infopeerip = 0;
460 			asesdata->infoversion = 0;
461 			for (i=0 ; i<SESSION_STATS ; i++) {
462 				asesdata->currentopstats[i] = (i<statsinfile)?get32bit(&ptr):0;
463 			}
464 			if (statsinfile>SESSION_STATS) {
465 				ptr+=4*(statsinfile-SESSION_STATS);
466 			}
467 			for (i=0 ; i<SESSION_STATS ; i++) {
468 				asesdata->lasthouropstats[i] = (i<statsinfile)?get32bit(&ptr):0;
469 			}
470 			if (ileng>0) {
471 				asesdata->info = malloc(ileng+1);
472 				passert(asesdata->info);
473 				if (fread(asesdata->info,ileng,1,fd)!=1) {
474 					free(asesdata->info);
475 					free(asesdata);
476 					free(fsesrecord);
477 					syslog(LOG_WARNING,"can't load sessions, fread error");
478 					fclose(fd);
479 					return -1;
480 				}
481 				asesdata->info[ileng]=0;
482 			}
483 			hpos = SESSION_HASH(asesdata->sessionid);
484 			asesdata->next = sessionshashtab[hpos];
485 			sessionshashtab[hpos] = asesdata;
486 		}
487 		if (ferror(fd)) {
488 			free(fsesrecord);
489 			syslog(LOG_WARNING,"can't load sessions, fread error");
490 			fclose(fd);
491 			return -1;
492 		}
493 	}
494 	free(fsesrecord);
495 	syslog(LOG_NOTICE,"sessions have been loaded");
496 	fclose(fd);
497 	return 1;
498 }
499 
sessions_import(void)500 void sessions_import(void) {
501 	fprintf(stderr,"loading sessions ... ");
502 	fflush(stderr);
503 	switch (sessions_import_data()) {
504 		case 0:	// no file
505 			fprintf(stderr,"file not found\n");
506 			fprintf(stderr,"if it is not fresh installation then you have to restart all active mounts !!!\n");
507 			break;
508 		case 1: // file loaded
509 			fprintf(stderr,"ok\n");
510 			fprintf(stderr,"sessions file has been loaded\n");
511 			break;
512 		default:
513 			fprintf(stderr,"error\n");
514 			fprintf(stderr,"due to missing sessions you have to restart all active mounts !!!\n");
515 			break;
516 	}
517 }
518 
519 /*
520 int sessions_open_file(void* vsesdata,uint32_t inode) {
521 	session *sesdata = (session*)vsesdata;
522 	filelist *ofptr,**ofpptr;
523 	int status;
524 
525 	ofpptr = &(sesdata->openedfiles);
526 	while ((ofptr=*ofpptr)) {
527 		if (ofptr->inode==inode) {
528 			return STATUS_OK;	// file already acquired - nothing to do
529 		}
530 		if (ofptr->inode>inode) {
531 			break;
532 		}
533 		ofpptr = &(ofptr->next);
534 	}
535 	status = fs_acquire(inode,sesdata->sessionid);
536 	if (status==STATUS_OK) {
537 		ofptr = (filelist*)malloc(sizeof(filelist));
538 		passert(ofptr);
539 		ofptr->inode = inode;
540 		ofptr->next = *ofpptr;
541 		*ofpptr = ofptr;
542 	}
543 	return status;
544 }
545 
546 int sessions_connect_session_with_inode(uint32_t sessionid,uint32_t inode) {
547 	session *asesdata;
548 	filelist *ofptr,**ofpptr;
549 
550 	for (asesdata = sessionshead ; asesdata && asesdata->sessionid!=sessionid; asesdata=asesdata->next) ;
551 	if (asesdata==NULL) {
552 		return 0;
553 	}
554 
555 	ofpptr = &(asesdata->openedfiles);
556 	while ((ofptr=*ofpptr)) {
557 		if (ofptr->inode==inode) {
558 			return 2;
559 		}
560 		if (ofptr->inode>inode) {
561 			break;
562 		}
563 		ofpptr = &(ofptr->next);
564 	}
565 	ofptr = (filelist*)malloc(sizeof(filelist));
566 	passert(ofptr);
567 	ofptr->inode = inode;
568 	ofptr->next = *ofpptr;
569 	*ofpptr = ofptr;
570 	return 1;
571 }
572 */
573 
574 //uint32_t sessions_get_statscnt(void) {
575 //	return SESSION_STATS;
576 //}
577 
sessions_datasize(uint8_t vmode)578 uint32_t sessions_datasize(uint8_t vmode) {
579 	session *sesdata;
580 	uint32_t hpos;
581 	uint32_t size;
582 
583 	size = 2;
584 	for (hpos = 0 ; hpos < SESSION_HASHSIZE ; hpos++) {
585 		for (sesdata = sessionshashtab[hpos] ; sesdata ; sesdata=sesdata->next) {
586 			if (vmode<2) {
587 				if (sesdata->nsocks>0) {
588 					size += 37+SESSION_STATS*8+(vmode?10:0);
589 					if (sesdata->info) {
590 						size += strlen(sesdata->info);
591 					}
592 					if (sesdata->rootinode==0) {
593 						size += 1;
594 					} else {
595 						size += fs_getdirpath_size(sesdata->rootinode);
596 					}
597 				}
598 			} else {
599 				size += 56+SESSION_STATS*8;
600 				if (sesdata->info) {
601 					size += strlen(sesdata->info);
602 				}
603 				if (sesdata->rootinode==0) {
604 					size += 1;
605 				} else {
606 					size += fs_getdirpath_size(sesdata->rootinode);
607 				}
608 			}
609 		}
610 	}
611 	return size;
612 }
613 
sessions_datafill(uint8_t * ptr,uint8_t vmode)614 void sessions_datafill(uint8_t *ptr,uint8_t vmode) {
615 	session *sesdata;
616 	uint32_t now;
617 	uint32_t hpos;
618 	uint32_t pleng,ileng,i;
619 
620 	put16bit(&ptr,SESSION_STATS);
621 	now = main_time();
622 	for (hpos = 0 ; hpos < SESSION_HASHSIZE ; hpos++) {
623 		for (sesdata = sessionshashtab[hpos] ; sesdata ; sesdata=sesdata->next) {
624 			if (vmode<2) {
625 				if (sesdata->nsocks>0) {
626 					put32bit(&ptr,sesdata->sessionid);
627 					put32bit(&ptr,sesdata->infopeerip);
628 					put32bit(&ptr,sesdata->infoversion);
629 					if (sesdata->info) {
630 						ileng = strlen(sesdata->info);
631 						put32bit(&ptr,ileng);
632 						memcpy(ptr,sesdata->info,ileng);
633 						ptr+=ileng;
634 					} else {
635 						put32bit(&ptr,0);
636 					}
637 					if (sesdata->rootinode==0) { // meta
638 						pleng = 1;
639 						put32bit(&ptr,pleng);
640 						put8bit(&ptr,'.');
641 					} else {
642 						pleng = fs_getdirpath_size(sesdata->rootinode);
643 						put32bit(&ptr,pleng);
644 						if (pleng>0) {
645 							fs_getdirpath_data(sesdata->rootinode,ptr,pleng);
646 							ptr+=pleng;
647 						}
648 					}
649 					put8bit(&ptr,sesdata->sesflags);
650 					put32bit(&ptr,sesdata->rootuid);
651 					put32bit(&ptr,sesdata->rootgid);
652 					put32bit(&ptr,sesdata->mapalluid);
653 					put32bit(&ptr,sesdata->mapallgid);
654 					if (vmode) {
655 						put8bit(&ptr,sesdata->mingoal);
656 						put8bit(&ptr,sesdata->maxgoal);
657 						put32bit(&ptr,sesdata->mintrashtime);
658 						put32bit(&ptr,sesdata->maxtrashtime);
659 					}
660 					for (i=0 ; i<SESSION_STATS ; i++) {
661 						put32bit(&ptr,sesdata->currentopstats[i]);
662 					}
663 					for (i=0 ; i<SESSION_STATS ; i++) {
664 						put32bit(&ptr,sesdata->lasthouropstats[i]);
665 					}
666 				}
667 			} else {
668 				put32bit(&ptr,sesdata->sessionid);
669 				if (sesdata->infopeerip==0 && sesdata->peerip!=0) {
670 					put32bit(&ptr,sesdata->peerip);
671 				} else {
672 					put32bit(&ptr,sesdata->infopeerip);
673 				}
674 				put32bit(&ptr,sesdata->infoversion);
675 				put32bit(&ptr,of_noofopenedfiles(sesdata->sessionid));
676 				if (sesdata->nsocks>255) {
677 					put8bit(&ptr,255);
678 				} else {
679 					put8bit(&ptr,sesdata->nsocks);
680 				}
681 				if (sesdata->nsocks>0) {
682 					put32bit(&ptr,UINT32_C(0xFFFFFFFF));
683 				} else {
684 					if (sesdata->closed || sesdata->disconnected+SessionSustainTime<now) {
685 						put32bit(&ptr,0);
686 					} else {
687 						put32bit(&ptr,sesdata->disconnected+SessionSustainTime-now);
688 					}
689 				}
690 				if (sesdata->info) {
691 					ileng = strlen(sesdata->info);
692 					put32bit(&ptr,ileng);
693 					memcpy(ptr,sesdata->info,ileng);
694 					ptr+=ileng;
695 				} else {
696 					put32bit(&ptr,0);
697 				}
698 				if (sesdata->rootinode==0) { // meta
699 					pleng = 1;
700 					put32bit(&ptr,pleng);
701 					put8bit(&ptr,'.');
702 				} else {
703 					pleng = fs_getdirpath_size(sesdata->rootinode);
704 					put32bit(&ptr,pleng);
705 					if (pleng>0) {
706 						fs_getdirpath_data(sesdata->rootinode,ptr,pleng);
707 						ptr+=pleng;
708 					}
709 				}
710 				put8bit(&ptr,sesdata->sesflags);
711 				put32bit(&ptr,sesdata->rootuid);
712 				put32bit(&ptr,sesdata->rootgid);
713 				put32bit(&ptr,sesdata->mapalluid);
714 				put32bit(&ptr,sesdata->mapallgid);
715 				put8bit(&ptr,sesdata->mingoal);
716 				put8bit(&ptr,sesdata->maxgoal);
717 				put32bit(&ptr,sesdata->mintrashtime);
718 				put32bit(&ptr,sesdata->maxtrashtime);
719 				for (i=0 ; i<SESSION_STATS ; i++) {
720 					put32bit(&ptr,sesdata->currentopstats[i]);
721 				}
722 				for (i=0 ; i<SESSION_STATS ; i++) {
723 					put32bit(&ptr,sesdata->lasthouropstats[i]);
724 				}
725 			}
726 		}
727 	}
728 }
729 /*
730 uint32_t sessions_datasize(void *vsesdata,uint8_t vmode) {
731 	session *sesdata = (session*)vsesdata;
732 	uint32_t size;
733 
734 	size = 25+SESSION_STATS*8+(vmode?10:0);
735 	if (sesdata->info) {
736 		size += strlen(sesdata->info);
737 	}
738 	if (sesdata->rootinode==0) {
739 		size += 1;
740 	} else {
741 		size += fs_getdirpath_size(sesdata->rootinode);
742 	}
743 	return size;
744 }
745 
746 uint32_t sessions_datafill(uint8_t *ptr,void *vsesdata,uint8_t vmode) {
747 	session *sesdata = (session*)vsesdata;
748 	uint32_t pleng,ileng,i;
749 
750 	if (sesdata->info) {
751 		ileng = strlen(sesdata->info);
752 		put32bit(&ptr,ileng);
753 		memcpy(ptr,sesdata->info,ileng);
754 		ptr+=ileng;
755 	} else {
756 		put32bit(&ptr,0);
757 		ileng = 0;
758 	}
759 	if (sesdata->rootinode==0) { // meta
760 		pleng = 1;
761 		put32bit(&ptr,pleng);
762 		put8bit(&ptr,'.');
763 	} else {
764 		pleng = fs_getdirpath_size(sesdata->rootinode);
765 		put32bit(&ptr,pleng);
766 		if (pleng>0) {
767 			fs_getdirpath_data(sesdata->rootinode,ptr,pleng);
768 			ptr+=pleng;
769 		}
770 	}
771 	put8bit(&ptr,sesdata->sesflags);
772 	put32bit(&ptr,sesdata->rootuid);
773 	put32bit(&ptr,sesdata->rootgid);
774 	put32bit(&ptr,sesdata->mapalluid);
775 	put32bit(&ptr,sesdata->mapallgid);
776 	if (vmode) {
777 		put8bit(&ptr,sesdata->mingoal);
778 		put8bit(&ptr,sesdata->maxgoal);
779 		put32bit(&ptr,sesdata->mintrashtime);
780 		put32bit(&ptr,sesdata->maxtrashtime);
781 	}
782 	for (i=0 ; i<SESSION_STATS ; i++) {
783 		put32bit(&ptr,sesdata->currentopstats[i]);
784 	}
785 	for (i=0 ; i<SESSION_STATS ; i++) {
786 		put32bit(&ptr,sesdata->lasthouropstats[i]);
787 	}
788 	return 25+SESSION_STATS*8+(vmode?10:0)+ileng+pleng;
789 }
790 */
sessions_create_session(uint32_t rootinode,uint8_t sesflags,uint32_t rootuid,uint32_t rootgid,uint32_t mapalluid,uint32_t mapallgid,uint8_t mingoal,uint8_t maxgoal,uint32_t mintrashtime,uint32_t maxtrashtime,uint32_t peerip,const char * info,uint32_t ileng)791 static inline void* sessions_create_session(uint32_t rootinode,uint8_t sesflags,uint32_t rootuid,uint32_t rootgid,uint32_t mapalluid,uint32_t mapallgid,uint8_t mingoal,uint8_t maxgoal,uint32_t mintrashtime,uint32_t maxtrashtime,uint32_t peerip,const char *info,uint32_t ileng) {
792 	session *sesdata;
793 	uint32_t hpos;
794 
795 	sesdata = (session*)malloc(sizeof(session));
796 	passert(sesdata);
797 	sesdata->sessionid = nextsessionid++;
798 	sesdata->rootinode = rootinode;
799 	sesdata->sesflags = (sesflags&(~SESFLAG_METARESTORE));
800 	sesdata->rootuid = rootuid;
801 	sesdata->rootgid = rootgid;
802 	sesdata->mapalluid = mapalluid;
803 	sesdata->mapallgid = mapallgid;
804 	sesdata->mingoal = mingoal;
805 	sesdata->maxgoal = maxgoal;
806 	sesdata->mintrashtime = mintrashtime;
807 	sesdata->maxtrashtime = maxtrashtime;
808 	sesdata->peerip = peerip;
809 	if (ileng>0) {
810 		if (info[ileng-1]==0) {
811 			sesdata->info = strdup(info);
812 			passert(sesdata->info);
813 		} else {
814 			sesdata->info = malloc(ileng+1);
815 			passert(sesdata->info);
816 			memcpy(sesdata->info,info,ileng);
817 			sesdata->info[ileng]=0;
818 		}
819 	}
820 	sesdata->closed = 0;
821 //	sesdata->openedfiles = NULL;
822 	sesdata->disconnected = 0;
823 	sesdata->nsocks = 0;
824 	sesdata->infopeerip = 0;
825 	sesdata->infoversion = 0;
826 	memset(sesdata->currentopstats,0,4*SESSION_STATS);
827 	memset(sesdata->lasthouropstats,0,4*SESSION_STATS);
828 	hpos = SESSION_HASH(sesdata->sessionid);
829 	sesdata->next = sessionshashtab[hpos];
830 	sessionshashtab[hpos] = sesdata;
831 	if ((sesflags&SESFLAG_METARESTORE)==0) {
832 		changelog("%" PRIu32 "|SESADD(%"PRIu32",%"PRIu8",%"PRIu32",%"PRIu32",%"PRIu32",%"PRIu32",%"PRIu8",%"PRIu8",%"PRIu32",%"PRIu32",%"PRIu32",%s):%"PRIu32,main_time(),rootinode,sesflags,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime,peerip,changelog_escape_name(ileng,(uint8_t*)info),sesdata->sessionid);
833 	} else {
834 		meta_version_inc();
835 	}
836 	return sesdata;
837 }
838 
sessions_new_session(uint32_t rootinode,uint8_t sesflags,uint32_t rootuid,uint32_t rootgid,uint32_t mapalluid,uint32_t mapallgid,uint8_t mingoal,uint8_t maxgoal,uint32_t mintrashtime,uint32_t maxtrashtime,uint32_t peerip,const char * info,uint32_t ileng)839 void* sessions_new_session(uint32_t rootinode,uint8_t sesflags,uint32_t rootuid,uint32_t rootgid,uint32_t mapalluid,uint32_t mapallgid,uint8_t mingoal,uint8_t maxgoal,uint32_t mintrashtime,uint32_t maxtrashtime,uint32_t peerip,const char *info,uint32_t ileng) {
840 	session *sesdata;
841 	sesdata = sessions_create_session(rootinode,sesflags&(~SESFLAG_METARESTORE),rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime,peerip,info,ileng);
842 	return sesdata;
843 }
844 
sessions_mr_sesadd(uint32_t rootinode,uint8_t sesflags,uint32_t rootuid,uint32_t rootgid,uint32_t mapalluid,uint32_t mapallgid,uint8_t mingoal,uint8_t maxgoal,uint32_t mintrashtime,uint32_t maxtrashtime,uint32_t peerip,const uint8_t * info,uint32_t ileng,uint32_t sessionid)845 uint8_t sessions_mr_sesadd(uint32_t rootinode,uint8_t sesflags,uint32_t rootuid,uint32_t rootgid,uint32_t mapalluid,uint32_t mapallgid,uint8_t mingoal,uint8_t maxgoal,uint32_t mintrashtime,uint32_t maxtrashtime,uint32_t peerip,const uint8_t *info,uint32_t ileng,uint32_t sessionid) {
846 	session *sesdata;
847 	sesdata = sessions_create_session(rootinode,sesflags|SESFLAG_METARESTORE,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime,peerip,(const char*)info,ileng);
848 	if (sesdata->sessionid!=sessionid) {
849 		return ERROR_MISMATCH;
850 	}
851 	return STATUS_OK;
852 }
853 
sessions_mr_sesdel(uint32_t sessionid)854 uint8_t sessions_mr_sesdel(uint32_t sessionid) {
855 	session **sesdata,*asesdata;
856 	uint8_t status = ERROR_BADSESSIONID;
857 	uint32_t hpos;
858 
859 	hpos = SESSION_HASH(sessionid);
860 	sesdata = sessionshashtab + hpos;
861 	while ((asesdata=*sesdata)) {
862 		if (asesdata->sessionid==sessionid) {
863 			sessions_clean_session(asesdata);
864 			*sesdata = asesdata->next;
865 			free(asesdata);
866 			status = STATUS_OK;
867 		} else {
868 			sesdata = &(asesdata->next);
869 		}
870 	}
871 	if (status==STATUS_OK) {
872 		meta_version_inc();
873 	}
874 	return status;
875 }
876 
sessions_mr_disconnected(uint32_t sessionid,uint32_t disctime)877 uint8_t sessions_mr_disconnected(uint32_t sessionid,uint32_t disctime) {
878 	session *sesdata;
879 
880 	for (sesdata = sessionshashtab[SESSION_HASH(sessionid)] ; sesdata ; sesdata = sesdata->next) {
881 		if (sesdata->sessionid == sessionid) {
882 			sesdata->disconnected = disctime;
883 			meta_version_inc();
884 			return STATUS_OK;
885 		}
886 	}
887 	return ERROR_NOTFOUND;
888 }
889 
sessions_mr_session(uint32_t sessionid)890 uint8_t sessions_mr_session(uint32_t sessionid) {
891 	if (sessionid!=nextsessionid) {
892 		return ERROR_MISMATCH;
893 	}
894 	nextsessionid++;
895 	meta_version_inc();
896 	return STATUS_OK;
897 }
898 
sessions_new(void)899 void sessions_new(void) {
900 	nextsessionid=1;
901 }
902 
903 /*
904 void sessions_sync_open_files(void *vsesdata,const uint8_t *ptr,uint32_t inodecnt) {
905 	session *sesdata = (session*)vsesdata;
906 
907 
908 	filelist *ofptr,**ofpptr;
909 	uint32_t inode;
910 
911 	ofpptr = &(sesdata->openedfiles);
912 	if (inodecnt) {
913 		inodecnt--;
914 		inode = get32bit(&ptr);
915 	} else {
916 		inode = 0;
917 	}
918 
919 	while ((ofptr=*ofpptr) && inodecnt>0) {
920 		if (ofptr->inode<inode) {
921 			fs_release(ofptr->inode,sesdata->sessionid);
922 			*ofpptr = ofptr->next;
923 			free(ofptr);
924 		} else {
925 			if (ofptr->inode>inode) {
926 				if (fs_acquire(inode,sesdata->sessionid)==STATUS_OK) {
927 					ofptr = (filelist*)malloc(sizeof(filelist));
928 					passert(ofptr);
929 					ofptr->next = *ofpptr;
930 					ofptr->inode = inode;
931 					*ofpptr = ofptr;
932 					ofpptr = &(ofptr->next);
933 				}
934 			} else {
935 				ofpptr = &(ofptr->next);
936 			}
937 			if (inodecnt) {
938 				inodecnt--;
939 				inode = get32bit(&ptr);
940 			} else {
941 				inode = 0;
942 			}
943 		}
944 	}
945 	while (inode>0) {
946 		if (fs_acquire(inode,sesdata->sessionid)==STATUS_OK) {
947 			ofptr = (filelist*)malloc(sizeof(filelist));
948 			passert(ofptr);
949 			ofptr->next = *ofpptr;
950 			ofptr->inode = inode;
951 			*ofpptr = ofptr;
952 			ofpptr = &(ofptr->next);
953 		}
954 		if (inodecnt) {
955 			inodecnt--;
956 			inode = get32bit(&ptr);
957 		} else {
958 			inode = 0;
959 		}
960 	}
961 	while ((ofptr=*ofpptr)) {
962 		fs_release(ofptr->inode,sesdata->sessionid);
963 		*ofpptr = ofptr->next;
964 		free(ofptr);
965 	}
966 }
967 */
sessions_get_id(void * vsesdata)968 uint32_t sessions_get_id(void *vsesdata) {
969 	session *sesdata = (session*)vsesdata;
970 	return sesdata->sessionid;
971 }
972 
sessions_get_peerip(void * vsesdata)973 uint32_t sessions_get_peerip(void *vsesdata) {
974 	session *sesdata = (session*)vsesdata;
975 	return sesdata->peerip;
976 }
977 
sessions_get_rootinode(void * vsesdata)978 uint32_t sessions_get_rootinode(void *vsesdata) {
979 	session *sesdata = (session*)vsesdata;
980 	return sesdata->rootinode;
981 }
982 
sessions_get_sesflags(void * vsesdata)983 uint32_t sessions_get_sesflags(void *vsesdata) {
984 	session *sesdata = (session*)vsesdata;
985 	return sesdata->sesflags | ((sesdata->infoversion>=VERSION2INT(1,7,32))?SESFLAG_ATTRBIT:0);
986 }
987 
sessions_is_root_remapped(void * vsesdata)988 uint8_t sessions_is_root_remapped(void *vsesdata) {
989 	session *sesdata = (session*)vsesdata;
990 	return (sesdata->rootuid!=0)?1:0;
991 }
992 
sessions_check_goal(void * vsesdata,uint8_t smode,uint8_t goal)993 uint8_t sessions_check_goal(void *vsesdata,uint8_t smode,uint8_t goal) {
994 	session *sesdata = (session*)vsesdata;
995 	switch (smode) {
996 		case SMODE_SET:
997 			if (goal<sesdata->mingoal || goal>sesdata->maxgoal) {
998 				return ERROR_EPERM;
999 			}
1000 		case SMODE_INCREASE:
1001 			if (goal>sesdata->maxgoal) {
1002 				return ERROR_EPERM;
1003 			}
1004 		case SMODE_DECREASE:
1005 			if (goal<sesdata->mingoal) {
1006 				return ERROR_EPERM;
1007 			}
1008 	}
1009 	return STATUS_OK;
1010 }
1011 
sessions_check_trashtime(void * vsesdata,uint8_t smode,uint32_t trashtime)1012 uint8_t sessions_check_trashtime(void *vsesdata,uint8_t smode,uint32_t trashtime) {
1013 	session *sesdata = (session*)vsesdata;
1014 	switch (smode) {
1015 		case SMODE_SET:
1016 			if (trashtime<sesdata->mintrashtime || trashtime>sesdata->maxtrashtime) {
1017 				return ERROR_EPERM;
1018 			}
1019 		case SMODE_INCREASE:
1020 			if (trashtime>sesdata->maxtrashtime) {
1021 				return ERROR_EPERM;
1022 			}
1023 		case SMODE_DECREASE:
1024 			if (trashtime<sesdata->mintrashtime) {
1025 				return ERROR_EPERM;
1026 			}
1027 	}
1028 	return STATUS_OK;
1029 }
1030 
sessions_inc_stats(void * vsesdata,uint8_t statid)1031 void sessions_inc_stats(void *vsesdata,uint8_t statid) {
1032 	session *sesdata = (session*)vsesdata;
1033 	if (sesdata && statid<SESSION_STATS) {
1034 		sesdata->currentopstats[statid]++;
1035 	}
1036 }
1037 
sessions_ugid_remap(void * vsesdata,uint32_t * auid,uint32_t * agid)1038 void sessions_ugid_remap(void *vsesdata,uint32_t *auid,uint32_t *agid) {
1039 	session *sesdata = (session*)vsesdata;
1040 	if (*auid==0) {
1041 		*auid = sesdata->rootuid;
1042 		if (agid) {
1043 			*agid = sesdata->rootgid;
1044 		}
1045 	} else if (sesdata->sesflags&SESFLAG_MAPALL) {
1046 		*auid = sesdata->mapalluid;
1047 		if (agid) {
1048 			*agid = sesdata->mapallgid;
1049 		}
1050 	}
1051 }
1052 
sessions_check(void)1053 void sessions_check(void) {
1054 	session **sesdata,*asesdata;
1055 	uint32_t now;
1056 	uint32_t hpos;
1057 
1058 	now = main_time();
1059 	if (starttime+120>now) {
1060 		return;
1061 	}
1062 	for (hpos = 0 ; hpos < SESSION_HASHSIZE ; hpos++) {
1063 		sesdata = sessionshashtab + hpos;
1064 		while ((asesdata=*sesdata)) {
1065 			if (asesdata->nsocks==0 && (asesdata->closed || asesdata->disconnected+SessionSustainTime<now)) {
1066 				changelog("%"PRIu32"|SESDEL(%"PRIu32")",main_time(),asesdata->sessionid);
1067 				syslog(LOG_NOTICE,"remove session: %u",asesdata->sessionid);
1068 				sessions_clean_session(asesdata);
1069 				*sesdata = asesdata->next;
1070 				free(asesdata);
1071 			} else {
1072 				sesdata = &(asesdata->next);
1073 			}
1074 		}
1075 	}
1076 }
1077 
sessions_force_remove(uint32_t sessionid)1078 uint8_t sessions_force_remove(uint32_t sessionid) {
1079 	session **sesdata,*asesdata;
1080 	uint32_t hpos;
1081 
1082 	hpos = SESSION_HASH(sessionid);
1083 	sesdata = sessionshashtab + hpos;
1084 	while ((asesdata=*sesdata)) {
1085 		if (asesdata->sessionid==sessionid) {
1086 			if (asesdata->nsocks==0) {
1087 				changelog("%"PRIu32"|SESDEL(%"PRIu32")",main_time(),asesdata->sessionid);
1088 				syslog(LOG_NOTICE,"remove session: %u",asesdata->sessionid);
1089 				sessions_clean_session(asesdata);
1090 				*sesdata = asesdata->next;
1091 				free(asesdata);
1092 				return STATUS_OK;
1093 			} else {
1094 				return ERROR_ACTIVE;
1095 			}
1096 		} else {
1097 			sesdata = &(asesdata->next);
1098 		}
1099 	}
1100 	return ERROR_NOTFOUND;
1101 }
1102 
sessions_statsmove(void)1103 void sessions_statsmove(void) {
1104 	session *sesdata;
1105 	uint32_t hpos;
1106 	for (hpos = 0 ; hpos < SESSION_HASHSIZE ; hpos++) {
1107 		for (sesdata = sessionshashtab[hpos] ; sesdata ; sesdata=sesdata->next) {
1108 			memcpy(sesdata->lasthouropstats,sesdata->currentopstats,4*SESSION_STATS);
1109 			memset(sesdata->currentopstats,0,4*SESSION_STATS);
1110 		}
1111 	}
1112 }
1113 
sessions_cleanup(void)1114 void sessions_cleanup(void) {
1115 	session *ss,*ssn;
1116 	uint32_t hpos;
1117 //	filelist *of,*ofn;
1118 
1119 	for (hpos = 0 ; hpos < SESSION_HASHSIZE ; hpos++) {
1120 		for (ss = sessionshashtab[hpos] ; ss ; ss = ssn) {
1121 			ssn = ss->next;
1122 	//		for (of = ss->openedfiles ; of ; of = ofn) {
1123 	//			ofn = of->next;
1124 	//			free(of);
1125 	//		}
1126 			if (ss->info) {
1127 				free(ss->info);
1128 			}
1129 			free(ss);
1130 		}
1131 		sessionshashtab[hpos] = NULL;
1132 	}
1133 }
1134 
sessions_reload(void)1135 void sessions_reload(void) {
1136 	SessionSustainTime = cfg_getuint32("SESSION_SUSTAIN_TIME",86400);
1137 	if (SessionSustainTime>7*86400) {
1138 		SessionSustainTime=7*86400;
1139 		mfs_syslog(LOG_WARNING,"SESSION_SUSTAIN_TIME too big (more than week) - setting this value to one week");
1140 	}
1141 	if (SessionSustainTime<60) {
1142 		SessionSustainTime=60;
1143 		mfs_syslog(LOG_WARNING,"SESSION_SUSTAIN_TIME too low (less than minute) - setting this value to one minute");
1144 	}
1145 }
1146 
sessions_init(void)1147 int sessions_init(void) {
1148 	uint32_t hpos;
1149 
1150 	starttime = main_time();
1151 	for (hpos = 0 ; hpos < SESSION_HASHSIZE ; hpos++) {
1152 		sessionshashtab[hpos] = NULL;
1153 	}
1154 	sessions_reload();
1155 	main_time_register(10,0,sessions_check);
1156 	main_time_register(3600,0,sessions_statsmove);
1157 	main_reload_register(sessions_reload);
1158 	return 0;
1159 }
1160