// File: /workspace/github_c_makefile_star2_O3/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 $0x88, %rsp
movq %rsi, %r14
movl %edi, %r15d
leaq -0x2c(%rbp), %r12
movl $0x5, (%r12)
leaq -0x48(%rbp), %r13
movq $0x0, (%r13)
callq 0x2280
movq %rax, %rbx
leaq 0xd14(%rip), %rdi       # 0x4313
movq %rax, %rsi
xorl %eax, %eax
callq 0x2100
leaq -0x58(%rbp), %rdx
leaq -0x54(%rbp), %rcx
movl %r15d, %edi
movq %r14, %rsi
movq %r12, %r8
movq %r13, %r9
callq 0x3044
testl %eax, %eax
js 0x3b82
movl $0x18, %edi
callq 0x21f0
movq %rax, %r14
movq %rax, 0x2c22(%rip)      # 0x6260
movl $0xc8, %edi
callq 0x21f0
movq %rax, (%r14)
movl $0xffffffff, 0x10(%r14) # imm = 0xFFFFFFFF
movq $0x0, 0x8(%r14)
leaq 0x2b76(%rip), %rdi      # 0x61d8
xorl %esi, %esi
callq 0x2330
leaq 0x2bf8(%rip), %rdi      # 0x6268
xorl %esi, %esi
callq 0x2330
leaq 0x2c12(%rip), %rdi      # 0x6290
xorl %esi, %esi
callq 0x2330
leaq 0x2ba4(%rip), %rdi      # 0x6230
xorl %esi, %esi
callq 0x21d0
leaq 0x2b66(%rip), %rdi      # 0x6200
xorl %esi, %esi
callq 0x21d0
movslq -0x2c(%rbp), %r14
leaq (,%r14,8), %rdi
callq 0x21f0
movq %rax, %r13
testq %r14, %r14
jle 0x36e8
xorl %r12d, %r12d
leaq -0x295(%rip), %r14      # 0x342f
movq %r13, %r15
movq -0x48(%rbp), %rcx
movq %r15, %rdi
xorl %esi, %esi
movq %r14, %rdx
callq 0x2260
incq %r12
movslq -0x2c(%rbp), %rax
addq $0x8, %r15
cmpq %rax, %r12
jl 0x36c7
leaq 0xc3f(%rip), %rdi       # 0x432e
movq %rbx, %rsi
xorl %eax, %eax
callq 0x2100
leaq -0x98(%rbp), %rdi
callq 0x21c0
movl $0x2, %edi
movl $0x801, %esi            # imm = 0x801
xorl %edx, %edx
callq 0x2360
testl %eax, %eax
js 0x3b95
movl %eax, %ebx
movw $0x2, -0x78(%rbp)
movzwl -0x58(%rbp), %eax
rolw $0x8, %ax
movl $0x0, -0x74(%rbp)
movw %ax, -0x76(%rbp)
leaq -0xa0(%rbp), %rcx
movl $0x1, (%rcx)
movl %ebx, %edi
movl $0x1, %esi
movl $0x2, %edx
movl $0x4, %r8d
callq 0x20a0
testl %eax, %eax
js 0x3b9a
leaq -0x78(%rbp), %rsi
movl %ebx, %edi
movl $0x10, %edx
callq 0x2250
testl %eax, %eax
js 0x3b9f
movl %ebx, %edi
movl $0x64, %esi
callq 0x2200
testl %eax, %eax
js 0x3ba4
movl $0x2, %edi
movl $0x1, %esi
xorl %edx, %edx
callq 0x2360
testl %eax, %eax
js 0x3ba9
movl %eax, %r14d
movzwl -0x54(%rbp), %eax
rolw $0x8, %ax
movw %ax, -0x76(%rbp)
leaq -0x9c(%rbp), %rcx
movl $0x1, (%rcx)
movl %r14d, %edi
movl $0x1, %esi
movl $0x2, %edx
movl $0x4, %r8d
callq 0x20a0
testl %eax, %eax
js 0x3bae
leaq -0x78(%rbp), %rsi
movl %r14d, %edi
movl $0x10, %edx
callq 0x2250
testl %eax, %eax
js 0x3bb3
movq %r13, -0x60(%rbp)
movl %r14d, %edi
movl $0x64, %esi
callq 0x2200
testl %eax, %eax
js 0x3bb8
leaq -0x90(%rbp), %rcx
movl %ebx, -0x34(%rbp)
movl %ebx, (%rcx)
movw $0x1, %ax
movw %ax, 0x4(%rcx)
movl %r14d, -0x30(%rbp)
movl %r14d, 0x8(%rcx)
movw %ax, 0xc(%rcx)
leaq 0xb34(%rip), %r13       # 0x4373
leaq -0x417(%rip), %r14      # 0x342f
leaq 0xb42(%rip), %r15       # 0x438f
cmpl $0x0, -0x2c(%rbp)
jle 0x38a3
movq -0x60(%rbp), %rbx
xorl %r12d, %r12d
movq (%rbx), %rdi
xorl %esi, %esi
callq 0x2180
testl %eax, %eax
je 0x3893
movq (%rbx), %rsi
movq %r13, %rdi
xorl %eax, %eax
callq 0x2100
movq -0x48(%rbp), %rcx
movq %rbx, %rdi
xorl %esi, %esi
movq %r14, %rdx
callq 0x2260
movq (%rbx), %rsi
movq %r15, %rdi
xorl %eax, %eax
callq 0x2100
incq %r12
movslq -0x2c(%rbp), %rax
addq $0x8, %rbx
cmpq %rax, %r12
jl 0x385a
movl $0x2, %esi
leaq -0x90(%rbp), %rdi
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
callq 0x2240
testb $0x1, -0x8a(%rbp)
je 0x38f5
movl -0x34(%rbp), %edi
xorl %esi, %esi
xorl %edx, %edx
movl $0x800, %ecx            # imm = 0x800
callq 0x20f0
testl %eax, %eax
js 0x3b78
leaq 0x297e(%rip), %rdi      # 0x6260
movl %eax, %esi
callq 0x330e
leaq 0x2940(%rip), %rdi      # 0x6230
callq 0x2160
testb $0x1, -0x82(%rbp)
je 0x384d
movl -0x30(%rbp), %edi
xorl %esi, %esi
xorl %edx, %edx
callq 0x22d0
testl %eax, %eax
js 0x3b7d
movl %eax, %ebx
movl $0x9, %edi
callq 0x21f0
movq %rax, -0x40(%rbp)
movl %ebx, %edi
leaq -0x40(%rbp), %rsi
movl $0x9, %edx
callq 0x275b
movq -0x40(%rbp), %r12
movq %r12, %rdi
leaq 0xa79(%rip), %rsi       # 0x43bd
callq 0x2190
testl %eax, %eax
je 0x397c
movq %r12, %rdi
leaq 0xaa5(%rip), %rsi       # 0x43fc
callq 0x2190
testl %eax, %eax
je 0x3a74
movl $0x12, %edx
movl %ebx, %edi
leaq 0xa93(%rip), %rsi       # 0x4405
callq 0x20b0
jmp 0x3a5f
leaq -0x68(%rbp), %rdi
callq 0x21c0
movq -0x68(%rbp), %r8
subq -0x98(%rbp), %r8
movq %r8, %rax
movabsq $0x48d159e26af37c05, %rcx # imm = 0x48D159E26AF37C05
imulq %rcx
movq %rdx, %r10
movq %rdx, %rax
shrq $0x3f, %rax
sarq $0xa, %r10
addq %rax, %r10
movq %r10, %rax
movabsq $0xe1000000000, %rcx    # imm = 0xE1000000000
imulq %rcx, %rax
sarq $0x20, %rax
subq %rax, %r8
movq %r8, -0x68(%rbp)
movq %r8, %rax
movabsq $-0x7777777777777777, %rcx # imm = 0x8888888888888889
imulq %rcx
movq %rdx, %rcx
addq %r8, %rcx
movq %rcx, %rax
shrq $0x3f, %rax
sarq $0x5, %rcx
addq %rax, %rcx
movq %rcx, %rax
movabsq $0x3c00000000, %rdx     # imm = 0x3C00000000
imulq %rdx, %rax
shrq $0x20, %rax
subl %eax, %r8d
movq $0x0, -0x50(%rbp)
movl 0x27b8(%rip), %r9d      # 0x61d0
movl 0x27b6(%rip), %eax      # 0x61d4
movl %eax, (%rsp)
leaq -0x50(%rbp), %rdi
leaq 0x997(%rip), %rsi       # 0x43c3
movl %r10d, %edx
xorl %eax, %eax
callq 0x2230
cmpl $-0x1, %eax
je 0x3a5f
movq -0x50(%rbp), %r12
movq %r12, %rdi
callq 0x20e0
incl %eax
movslq %eax, %rdx
movl %ebx, %edi
movq %r12, %rsi
callq 0x20b0
movq -0x50(%rbp), %rdi
callq 0x2030
movq -0x40(%rbp), %rdi
callq 0x2030
movl %ebx, %edi
callq 0x2140
jmp 0x384d
movl %ebx, %edi
callq 0x2140
movq -0x40(%rbp), %rdi
callq 0x2030
cmpl $0x0, -0x2c(%rbp)
movq -0x60(%rbp), %r13
jle 0x3aec
xorl %r12d, %r12d
leaq 0x27c8(%rip), %rbx      # 0x6260
leaq 0x2791(%rip), %r14      # 0x6230
leaq 0x983(%rip), %r15       # 0x4429
movq %rbx, %rdi
movl $0xffffffff, %esi       # imm = 0xFFFFFFFF
callq 0x330e
movq %r14, %rdi
callq 0x2160
movq %r15, %rdi
callq 0x2090
incl %r12d
movl -0x2c(%rbp), %eax
cmpl %eax, %r12d
jl 0x3aa6
testl %eax, %eax
jle 0x3aec
xorl %ebx, %ebx
movq (%r13,%rbx,8), %rdi
xorl %esi, %esi
callq 0x2310
incq %rbx
movslq -0x2c(%rbp), %rax
cmpq %rax, %rbx
jl 0x3ad4
leaq 0x26e5(%rip), %rdi      # 0x61d8
callq 0x2110
leaq 0x2769(%rip), %rdi      # 0x6268
callq 0x2110
leaq 0x2785(%rip), %rdi      # 0x6290
callq 0x2110
leaq 0x2719(%rip), %rdi      # 0x6230
callq 0x2290
leaq 0x26dd(%rip), %rdi      # 0x6200
callq 0x2290
movq 0x2731(%rip), %rax      # 0x6260
movq (%rax), %rdi
callq 0x2030
movq 0x2722(%rip), %rdi      # 0x6260
callq 0x2030
movl -0x34(%rbp), %edi
callq 0x2140
movl -0x30(%rbp), %edi
callq 0x2140
movq -0x48(%rbp), %rdi
callq 0x2030
movq %r13, %rdi
callq 0x2030
xorl %eax, %eax
addq $0x88, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
callq 0x2380
callq 0x2398
movq -0x48(%rbp), %rdi
callq 0x2030
movl $0x9, %edi
callq 0x2300
callq 0x2458
callq 0x2440
callq 0x2428
callq 0x2410
callq 0x23f8
callq 0x23e0
callq 0x23c8
callq 0x23b0