// File: /workspace/github_c_makefile_star2_O2/stefpant[P]TCPserver/webserver/webserver.c
// Function: main
int main(int argc,char* argv[]){
	//int err;//thread error
	int s_port,c_port;
	int n_threads = 5;//by default 5 threads
	char *rootdir = NULL;
//	int flagSHUTDOWN=0;//when set 1 exit
//~~~~~~~~~~~~~~~~~~~~~~~~~~PARSE ARGUMENTS~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	printf("Parent %ld: just started!\n", pthread_self());
	if(input_parse(argc,argv,&s_port,&c_port,&n_threads,&rootdir) < 0){
		free(rootdir);
		exit(9);
	}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//printf("%s\n",rootdir);
//~~~~~~~~~~~~~~~~~~~~~INIT: pool,mutexes,conditions~~~~~~~~~~~~~~~~~~~~~~~
	reqArray_init(&ra);

	pthread_mutex_init(&mtx, 0);
	pthread_mutex_init(&mtxcounter, 0);
	pthread_mutex_init(&mtxbytes, 0);
	pthread_cond_init(&cv_notempty, 0);
	pthread_cond_init(&cv_notfull, 0);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~MAKING THREADS~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	pthread_t *tids = NULL;

	tids = malloc(n_threads*sizeof(pthread_t));

	for(int i=0; i<n_threads; i++)//create threads to execute threadExec
		pthread_create(tids+i,NULL,threadExec, (void *)rootdir);

	//test terminating last thread to create new one
	//to test this decrease above for loop by one( i<nthreads-1 )
	//pthread_create(tids+(n_threads-1),NULL,killthread, (void *)rootdir);

	printf("Parent %ld: just created new threads!\n", pthread_self());
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	time_t start,localend;
	int hh,mm,ss;
	time(&start);//server started
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~MAKING SOCKETS~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	int s_sock,c_sock,newsock,newcsock;
	struct sockaddr_in server;
	struct sockaddr * serverptr = (struct sockaddr *)&server;
	if( (s_sock = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0)) < 0 ) //socket for service port
		{perror("socket");exit(9);}
	server.sin_family = AF_INET;
	server.sin_addr.s_addr = htonl(INADDR_ANY);
	server.sin_port = htons(s_port);
	if( setsockopt(s_sock, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 },sizeof(int)) < 0 )
		{perror("setsockopt");exit(9);}
	if( bind(s_sock,serverptr,sizeof(server)) < 0 ){perror("bind");exit(9);}
	if( listen(s_sock,100) < 0 ){perror("listen");exit(9);}

	if( (c_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) //socket for command port
		{perror("socket");exit(9);}
	server.sin_port = htons(c_port); //change port
	if( setsockopt(c_sock, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 },sizeof(int)) < 0 )
		{perror("setsockopt");exit(9);}
	if( bind(c_sock,serverptr,sizeof(server)) < 0 ){perror("bind");exit(9);}
	if( listen(c_sock,100) < 0 ){perror("listen");exit(9);}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	struct pollfd pfds[2];
	pfds[0].fd = s_sock;
	pfds[0].events = POLLIN;
	pfds[1].fd = c_sock;
	pfds[1].events = POLLIN;

//~~~~~~~~~~~~~~~~~~~~~~~~~LOOP:ACCEPTING CONNECTIONS~~~~~~~~~~~~~~~~~~~~~~~
	while( 1 ){
//~~~~~~~~~~~~~~~~~~~~~~~~~CHECK IF THREADS ARE ALIVE~~~~~~~~~~~~~~~~~~~~~~~
		for(int i=0; i<n_threads; i++){
			if(pthread_kill(*(tids+i),0) != 0){//thread i died
				printf("Thread with id '%ld' died.\n",*(tids+i));
				pthread_create(tids+i,NULL,threadExec, (void *)rootdir);
				printf("Just created a new one with id '%ld'!\n",*(tids+i));
			}
		}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		poll(pfds,2,-1);//wait a connection
		if(pfds[0].revents & POLLIN){//client connected on service port
			if( (newsock = accept4(s_sock,NULL,NULL,SOCK_NONBLOCK)) < 0)//non blocking fd
				{perror("accept");exit(9);}
			place(&ra, newsock);
			pthread_cond_signal(&cv_notempty);
			//printf("Parent: send fd!\n");
		}
		if(pfds[1].revents & POLLIN){//client on command port
			if( (newcsock = accept(c_sock,NULL,NULL)) < 0)
				{perror("accept");exit(9);}
//			while(1){//1
				char *buf = malloc(9*sizeof(char));//should not be resized
				read_command(newcsock,&buf,9);
				if( !strcmp(buf,"STATS") ){
					time(&localend);
					localend -= start;
					hh = localend/3600;//creating time format
					localend -= hh*3600;
					mm = localend/60;
					ss = localend - mm*60;
					char* statrep=NULL;
					if(asprintf(&statrep,"Server up for %02d:%02d:%02d, served %d pages, %d bytes\n",hh,mm,ss,totalrc,totalBytes) != -1){
						int len=strlen(statrep);
						write(newcsock,statrep,len+1);
						free(statrep);
					}
					//printf("Server up for %02d:%02d:%02d, served %d pages, %d bytes\n",hh,mm,ss,totalrc,totalBytes);
				}
				else if( !strcmp(buf,"SHUTDOWN") ){
					close(newcsock);
					free(buf);
//					flagSHUTDOWN=1;//2
					break;
				}
//				else if( !strcmp(buf,"STOP") ){//3
//					close(newcsock);//4
//					free(buf);//5
//					break;//6
//				}//7
				else
					write(newcsock,"Unknown command!\n",18);
				free(buf);
				close(newcsock);//--8
//			}//9
		}
//		if(flagSHUTDOWN) break;//10
	}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//should clear pool first
	//here if i got SHUTDOWN command to send exit msg(sending -1 in pool)
	for(int i=0; i<n_threads; i++){
		place(&ra,-1);
		pthread_cond_signal(&cv_notempty);
		printf("Parent: send stop!\n");
	}

	for(int i=0; i<n_threads; i++)
		 pthread_join(*(tids+i),NULL);//join threads

	//printf("Finaly counter is %d\n",totalrc);

	//free structs
	pthread_mutex_destroy(&mtx);
	pthread_mutex_destroy(&mtxcounter);
	pthread_mutex_destroy(&mtxbytes);
	pthread_cond_destroy(&cv_notempty);
	pthread_cond_destroy(&cv_notfull);
	reqArray_destroy(&ra);
	close(s_sock);
	close(c_sock);
	free(rootdir);
	free(tids);
	return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x78, %rsp
movq %rsi, %rbx
movl %edi, %r15d
leaq -0x2c(%rbp), %r12
movl $0x5, (%r12)
leaq -0x48(%rbp), %r13
andq $0x0, (%r13)
callq 0x2270
leaq 0xf6d(%rip), %rdi       # 0x4313
movq %rax, -0x38(%rbp)
movq %rax, %rsi
xorl %eax, %eax
callq 0x2100
leaq -0x58(%rbp), %rdx
leaq -0x54(%rbp), %rcx
movl %r15d, %edi
movq %rbx, %rsi
movq %r12, %r8
movq %r13, %r9
callq 0x2e7b
testl %eax, %eax
js 0x38c2
leaq 0x2e7c(%rip), %rdi      # 0x6258
callq 0x30d4
leaq 0x2de8(%rip), %rdi      # 0x61d0
xorl %r13d, %r13d
xorl %esi, %esi
callq 0x2320
leaq 0x2e67(%rip), %rdi      # 0x6260
xorl %esi, %esi
callq 0x2320
leaq 0x2e81(%rip), %rdi      # 0x6288
xorl %esi, %esi
callq 0x2320
leaq 0x2e13(%rip), %rdi      # 0x6228
xorl %esi, %esi
callq 0x21c0
leaq 0x2dd5(%rip), %rdi      # 0x61f8
xorl %esi, %esi
callq 0x21c0
movslq -0x2c(%rbp), %r14
movq %r14, %rdi
shlq $0x3, %rdi
callq 0x21e0
movq %rax, %rbx
leaq -0x242(%rip), %r15      # 0x3202
movq %rax, %r12
movslq %r14d, %rax
cmpq %rax, %r13
jge 0x346d
movq -0x48(%rbp), %rcx
movq %r12, %rdi
xorl %esi, %esi
movq %r15, %rdx
callq 0x2250
incq %r13
movl -0x2c(%rbp), %r14d
addq $0x8, %r12
jmp 0x3447
leaq 0xeba(%rip), %rdi       # 0x432e
movq -0x38(%rbp), %rsi
xorl %eax, %eax
callq 0x2100
leaq -0x88(%rbp), %rdi
callq 0x21b0
pushq $0x2
popq %rdi
movl $0x801, %esi            # imm = 0x801
xorl %edx, %edx
callq 0x2350
testl %eax, %eax
js 0x389e
movl %eax, %r14d
movw $0x2, -0x70(%rbp)
andl $0x0, -0x6c(%rbp)
movzwl -0x58(%rbp), %eax
rolw $0x8, %ax
movw %ax, -0x6e(%rbp)
leaq -0x90(%rbp), %rcx
movl $0x1, (%rcx)
pushq $0x1
popq %rsi
pushq $0x2
popq %rdx
pushq $0x4
popq %r8
movl %r14d, %edi
callq 0x20a0
testl %eax, %eax
js 0x38a7
leaq -0x70(%rbp), %rsi
pushq $0x10
popq %rdx
movl %r14d, %edi
callq 0x2240
testl %eax, %eax
js 0x38b0
pushq $0x64
popq %rsi
movl %r14d, %edi
callq 0x21f0
testl %eax, %eax
js 0x38b9
pushq $0x2
popq %rdi
pushq $0x1
popq %rsi
xorl %edx, %edx
callq 0x2350
testl %eax, %eax
js 0x389e
movl %eax, %r15d
movzwl -0x54(%rbp), %eax
rolw $0x8, %ax
movw %ax, -0x6e(%rbp)
leaq -0x8c(%rbp), %rcx
movl $0x1, (%rcx)
pushq $0x1
popq %rsi
pushq $0x2
popq %rdx
pushq $0x4
popq %r8
movl %r15d, %edi
callq 0x20a0
testl %eax, %eax
js 0x38a7
leaq -0x70(%rbp), %rsi
pushq $0x10
popq %rdx
movl %r15d, %edi
callq 0x2240
testl %eax, %eax
js 0x38b0
pushq $0x64
popq %rsi
movl %r15d, %edi
callq 0x21f0
testl %eax, %eax
js 0x38b9
leaq -0x80(%rbp), %rcx
movl %r14d, -0x38(%rbp)
movl %r14d, (%rcx)
movw $0x1, %ax
movw %ax, 0x4(%rcx)
movl %r15d, -0x30(%rbp)
movl %r15d, 0x8(%rcx)
movw %ax, 0xc(%rcx)
pushq $0x2
popq %r14
pushq $-0x1
popq %r13
xorl %r12d, %r12d
movslq -0x2c(%rbp), %rax
cmpq %rax, %r12
jge 0x3603
movq (%rbx,%r12,8), %rdi
xorl %esi, %esi
callq 0x2170
testl %eax, %eax
je 0x35fe
leaq (%rbx,%r12,8), %r15
movq (%r15), %rsi
leaq 0xda2(%rip), %rdi       # 0x4373
xorl %eax, %eax
callq 0x2100
movq -0x48(%rbp), %rcx
movq %r15, %rdi
xorl %esi, %esi
leaq -0x3e6(%rip), %rdx      # 0x3202
callq 0x2250
movq (%r15), %rsi
leaq 0xd98(%rip), %rdi       # 0x438f
xorl %eax, %eax
callq 0x2100
incq %r12
jmp 0x35ab
leaq -0x80(%rbp), %rdi
movq %r14, %rsi
movl %r13d, %edx
callq 0x2230
testb $0x1, -0x7a(%rbp)
je 0x364b
movl -0x38(%rbp), %edi
xorl %esi, %esi
xorl %edx, %edx
movl $0x800, %ecx            # imm = 0x800
callq 0x20f0
testl %eax, %eax
js 0x388a
leaq 0x2c20(%rip), %rdi      # 0x6258
movl %eax, %esi
callq 0x312a
leaq 0x2be2(%rip), %rdi      # 0x6228
callq 0x2150
testb $0x1, -0x72(%rbp)
movl $0x0, %r12d
je 0x35ab
movl -0x30(%rbp), %edi
xorl %esi, %esi
xorl %edx, %edx
callq 0x22c0
testl %eax, %eax
js 0x388a
movl %eax, %r15d
pushq $0x9
popq %rdi
callq 0x21e0
movq %rax, -0x40(%rbp)
movl %r15d, %edi
leaq -0x40(%rbp), %rsi
pushq $0x9
popq %rdx
callq 0x260c
movq -0x40(%rbp), %r12
movq %r12, %rdi
leaq 0xd22(%rip), %rsi       # 0x43bd
callq 0x2180
testl %eax, %eax
je 0x36d2
movq %r12, %rdi
leaq 0xd4e(%rip), %rsi       # 0x43fc
callq 0x2180
testl %eax, %eax
je 0x379d
movl %r15d, %edi
leaq 0xd40(%rip), %rsi       # 0x4405
pushq $0x12
popq %rdx
callq 0x20b0
jmp 0x3787
leaq -0x60(%rbp), %rdi
callq 0x21b0
movq -0x60(%rbp), %r8
subq -0x88(%rbp), %r8
movq %r8, %rax
cqto
movl $0xe10, %ecx            # imm = 0xE10
idivq %rcx
movq %rax, %rcx
movabsq $0xe1000000000, %rdx    # imm = 0xE1000000000
imulq %rdx, %rax
sarq $0x20, %rax
subq %rax, %r8
movq %r8, -0x60(%rbp)
movq %r8, %rax
cqto
pushq $0x3c
popq %rsi
idivq %rsi
movq %rax, %rdx
movabsq $0x3c00000000, %rsi     # imm = 0x3C00000000
imulq %rsi, %rdx
andq $0x0, -0x50(%rbp)
shrq $0x20, %rdx
subl %edx, %r8d
movl 0x2a8a(%rip), %r9d      # 0x61c8
movl 0x2a88(%rip), %edx      # 0x61cc
movl %edx, (%rsp)
leaq -0x50(%rbp), %rdi
leaq 0xc71(%rip), %rsi       # 0x43c3
movl %ecx, %edx
movl %eax, %ecx
xorl %eax, %eax
callq 0x2220
cmpl $-0x1, %eax
je 0x3787
movq -0x50(%rbp), %r12
movq %r12, %rdi
callq 0x20e0
incl %eax
movslq %eax, %rdx
movl %r15d, %edi
movq %r12, %rsi
callq 0x20b0
movq -0x50(%rbp), %rdi
callq 0x2030
movq -0x40(%rbp), %rdi
callq 0x2030
movl %r15d, %edi
callq 0x2130
jmp 0x35a8
movl %r15d, %edi
callq 0x2130
movq -0x40(%rbp), %rdi
callq 0x2030
xorl %r14d, %r14d
pushq $-0x1
popq %r15
leaq 0x2a6c(%rip), %r12      # 0x6228
leaq 0xc66(%rip), %r13       # 0x4429
movl -0x2c(%rbp), %eax
cmpl %eax, %r14d
jge 0x37ef
leaq 0x2a86(%rip), %rdi      # 0x6258
movl %r15d, %esi
callq 0x312a
movq %r12, %rdi
callq 0x2150
movq %r13, %rdi
callq 0x2090
incl %r14d
jmp 0x37c3
xorl %r14d, %r14d
movl -0x30(%rbp), %r15d
cltq
cmpq %rax, %r14
jge 0x3810
movq (%rbx,%r14,8), %rdi
xorl %esi, %esi
callq 0x2300
incq %r14
movl -0x2c(%rbp), %eax
jmp 0x37f6
leaq 0x29b9(%rip), %rdi      # 0x61d0
callq 0x2110
leaq 0x2a3d(%rip), %rdi      # 0x6260
callq 0x2110
leaq 0x2a59(%rip), %rdi      # 0x6288
callq 0x2110
leaq 0x29ed(%rip), %rdi      # 0x6228
callq 0x2280
leaq 0x29b1(%rip), %rdi      # 0x61f8
callq 0x2280
leaq 0x2a05(%rip), %rdi      # 0x6258
callq 0x3108
movl -0x38(%rbp), %edi
callq 0x2130
movl %r15d, %edi
callq 0x2130
movq -0x48(%rbp), %rdi
callq 0x2030
movq %rbx, %rdi
callq 0x2030
xorl %eax, %eax
addq $0x78, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0xb25(%rip), %rdi       # 0x43b6
callq 0x22b0
pushq $0x9
popq %rdi
callq 0x22f0
leaq 0xab0(%rip), %rdi       # 0x4355
jmp 0x3891
leaq 0xaae(%rip), %rdi       # 0x435c
jmp 0x3891
leaq 0xab0(%rip), %rdi       # 0x4367
jmp 0x3891
leaq 0xaac(%rip), %rdi       # 0x436c
jmp 0x3891
movq -0x48(%rbp), %rdi
callq 0x2030
jmp 0x3896