00001
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "config.h"
00019 #include "defines.h"
00020
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <time.h>
00024 #include <pthread.h>
00025 #include <gdome.h>
00026 #include <errno.h>
00027 #include <string.h>
00028
00029 #include <sys/stat.h>
00030
00031
00032 #include <sys/types.h>
00033 #include <sys/socket.h>
00034 #include <netdb.h>
00035 #include <unistd.h>
00036 #include <sys/un.h>
00037
00038 #include <sys/wait.h>
00039 #include <signal.h>
00040 #include <fcntl.h>
00041
00042 #ifdef CF_SHARED_MEM
00043 #include <sys/ipc.h>
00044 #include <sys/shm.h>
00045 #include <sys/sem.h>
00046 #endif
00047
00048 #ifdef CF_SHARED_MEM
00049 #include "semaphores.h"
00050 #endif
00051
00052 #include "cf_pthread.h"
00053
00054 #include "hashlib.h"
00055 #include "utils.h"
00056 #include "configparser.h"
00057 #include "readline.h"
00058 #include "fo_server.h"
00059 #include "initfinish.h"
00060 #include "serverlib.h"
00061 #include "readline.h"
00062 #include "archiver.h"
00063
00064
00065
00066
00067 int RUN;
00068 t_head head;
00070
00076 void flsh(int n) {
00077 int status;
00078
00079 cf_log(LOG_STD,__FILE__,__LINE__,"flushing file handles\n");
00080
00081 if((status = pthread_mutex_lock(&head.log_lock)) != 0) {
00082 fprintf(stderr,"pthread_mutex_lock: %s\n",strerror(status));
00083 return;
00084 }
00085
00086 if(head.std) {
00087 fflush(head.std);
00088 }
00089 if(head.err) {
00090 fflush(head.err);
00091 }
00092
00093 pthread_mutex_unlock(&head.log_lock);
00094 }
00095
00096
00097
00098 void terminate(int n) {
00099 cf_log(LOG_STD,__FILE__,__LINE__,"got signal SIG%d, going down\n",n);
00100 RUN = 0;
00101 }
00102
00103
00104
00110 void *archiver_and_writer(void *arg) {
00111 t_name_value *v = cfg_get_value(&fo_server_conf,"RunArchiver");
00112 int val = atoi(v->values[0]);
00113 #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
00114 struct sched_param param;
00115
00116
00117 memset(¶m,0,sizeof(struct sched_param));
00118 param.sched_priority = (sched_get_priority_min(SCHEDULING) + sched_get_priority_max(SCHEDULING)) / 2;
00119 pthread_setschedparam(pthread_self(),SCHEDULING,¶m);
00120 #endif
00121
00122 if(!v) {
00123 cf_log(LOG_ERR,__FILE__,__LINE__,"FATAL ERROR: could not get archiver intervall!\n");
00124 RUN = 0;
00125 return NULL;
00126 }
00127
00128 while(RUN) {
00129 sleep(val);
00130
00131 if(RUN) {
00132
00133 cf_log(LOG_STD,__FILE__,__LINE__,"running archiver...\n");
00134 cf_run_archiver_and_write_to_disk();
00135 }
00136 }
00137
00138 return NULL;
00139 }
00140
00141
00142
00147 void setup_server_infos(void) {
00148 FILE *fpid;
00149 t_name_value *pidfile;
00150 pid_t pid;
00151 u_char buff[50];
00152
00153
00154
00155
00156 pidfile = cfg_get_value(&fo_server_conf,"PIDFile");
00157 if(!pidfile) {
00158 fprintf(stderr,"I need a pid file!\n");
00159 exit(-1);
00160 }
00161
00162
00163
00164
00165 fpid = fopen(pidfile->values[0],"r");
00166 if(fpid) {
00167
00168
00169
00170 if(!fread(buff,1,50,fpid)) {
00171 fprintf(stderr,"I could not read the pid file!\n");
00172 exit(-1);
00173 }
00174
00175
00176
00177
00178 pid = atoi(buff);
00179 if(kill(pid,0) != -1) {
00180 fprintf(stderr,"Server seems to run already at pid %d\n",pid);
00181 exit(-1);
00182 }
00183 else {
00184
00185
00186
00187
00188 if(errno == EPERM) {
00189 fprintf(stderr,"Server seems to run already at pid %d\n",pid);
00190 exit(-1);
00191 }
00192 }
00193
00194
00195
00196
00197 fclose(fpid);
00198 }
00199 else {
00200
00201
00202
00203 if(errno != ENOENT) {
00204 fprintf(stderr,"error opening pid file: %s",strerror(errno));
00205 exit(-1);
00206 }
00207 }
00208
00209
00210
00211
00212
00213 fpid = fopen(pidfile->values[0],"w");
00214 if(fpid) {
00215 pid = getpid();
00216
00217 fprintf(fpid,"%d",pid);
00218 fclose(fpid);
00219 }
00220 else {
00221
00222
00223
00224 fprintf(stderr,"could not open pid file '%s'!\n",pidfile->values[0]);
00225 exit(-1);
00226 }
00227 }
00228
00229
00230 #ifdef CF_SHARED_MEM
00231
00232
00237 int create_shm_sem(t_name_value *shm) {
00238 union semun smn;
00239 unsigned short x = 0;
00240
00241 if((head.shm_sem = semget(atoi(shm->values[2]),1,S_IRWXU|S_IRWXG|S_IRWXO|IPC_CREAT)) == -1) {
00242 cf_log(LOG_ERR,__FILE__,__LINE__,"semget: %s\n",strerror(errno));
00243 return -1;
00244 }
00245
00246 smn.array = &x;
00247 if(semctl(head.shm_sem,0,SETALL,smn) == -1) {
00248 cf_log(LOG_ERR,__FILE__,__LINE__,"semctl: %s\n",strerror(errno));
00249 return -1;
00250 }
00251
00252 return 0;
00253 }
00254
00255
00256 #endif
00257
00258
00266 int main(int argc,char *argv[]) {
00267 int sockfd,size,status,connfd,ret = 0,i;
00268 u_char *fname;
00269 t_array *fnames;
00270 struct sockaddr_un *addr = fo_alloc(NULL,1,sizeof(struct sockaddr_un),FO_ALLOC_CALLOC);
00271 t_configfile default_conf,server_conf;
00272 pthread_t thr;
00273 t_name_value *pidfile;
00274 fd_set rfds;
00275 struct timeval timeout;
00276 pthread_attr_t attr;
00277
00278 size_t hi;
00279 t_handler_config *handler;
00280 t_server_init_filter fkt;
00281
00282 static const u_char *wanted[] = {
00283 "fo_default", "fo_server"
00284 };
00285
00286 #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
00287 struct sched_param param;
00288 #endif
00289
00290 #ifdef CF_SHARED_MEM
00291 t_name_value *shm;
00292 #endif
00293
00294
00295
00296 #ifndef DEBUG
00297 pid_t pid;
00298
00299
00300 pid = fork();
00301 switch(pid) {
00302 case -1:
00303 perror("fork");
00304 exit(-1);
00305
00306 case 0:
00307 if(setsid() == -1) {
00308 cf_log(LOG_ERR,__FILE__,__LINE__,"setsid: %s\n",strerror(errno));
00309 exit(-1);
00310 }
00311
00312 break;
00313
00314 default:
00315 printf("server forked. It's pid is: %d\n",pid);
00316 exit(0);
00317 }
00318 #endif
00319
00320 init_modules();
00321
00322
00323 str_init(&head.cache_invisible);
00324 str_init(&head.cache_visible);
00325
00326 head.date_visible = 0;
00327 head.date_invisible = 0;
00328
00329 head.thread = NULL;
00330
00331 head.std = NULL;
00332 head.err = NULL;
00333
00334 head.locked = 0;
00335
00336 head.clients.workers = 0;
00337 head.clients.clientnum = 0;
00338 head.clients.down = 0;
00339 head.clients.clients = NULL;
00340 head.clients.last = NULL;
00341
00342 head.servers = NULL;
00343
00344 head.protocol_handlers = NULL;
00345
00346 head.threads = NULL;
00347
00348 #ifdef CF_SHARED_MEM
00349 head.shm_ids[0] = -1;
00350 head.shm_ids[1] = -1;
00351
00352 head.shm_ptrs[0] = NULL;
00353 head.shm_ptrs[1] = NULL;
00354
00355 head.shm_sem = -1;
00356 #endif
00357
00358 RUN = 1;
00359
00360 cf_rwlock_init("head.lock",&head.lock);
00361 cf_rwlock_init("head.threads_lock",&head.threads_lock);
00362
00363 pthread_mutex_init(&head.log_lock,NULL);
00364
00365 cf_mutex_init("head.clients.cond_lock",&head.clients.cond_lock);
00366 cf_mutex_init("head.clients.lock",&head.clients.lock);
00367 cf_mutex_init("head.server_lock",&head.server_lock);
00368
00369 pthread_cond_init(&head.clients.cond,NULL);
00370
00371
00372 signal(SIGPIPE,SIG_IGN);
00373 signal(SIGINT,flsh);
00374 signal(SIGHUP,flsh);
00375 signal(SIGTERM,terminate);
00376
00377
00378
00379
00380
00381 if((fnames = get_conf_file(wanted,2)) == NULL) {
00382 return EXIT_FAILURE;
00383 }
00384
00385
00386 fname = *((u_char **)array_element_at(fnames,0));
00387 cfg_init_file(&default_conf,fname);
00388 cfg_register_options(&default_conf,default_options);
00389 free(fname);
00390
00391 fname = *((u_char **)array_element_at(fnames,1));
00392 cfg_init_file(&server_conf,fname);
00393 cfg_register_options(&server_conf,fo_server_options);
00394 free(fname);
00395
00396 array_destroy(fnames);
00397 free(fnames);
00398
00399
00400 if(read_config(&default_conf,NULL) != 0) {
00401 cfg_cleanup_file(&default_conf);
00402 cfg_cleanup_file(&server_conf);
00403
00404 fprintf(stderr,"configfile error!\n");
00405 return EXIT_FAILURE;
00406 }
00407
00408 if(read_config(&server_conf,NULL) != 0) {
00409 cfg_cleanup_file(&default_conf);
00410 cfg_cleanup_file(&server_conf);
00411
00412 fprintf(stderr,"configfile error!\n");
00413 return EXIT_FAILURE;
00414 }
00415
00416
00417
00418
00419
00420
00421
00422 setup_server_infos();
00423 pidfile = cfg_get_value(&fo_server_conf,"PIDFile");
00424
00425 #ifdef CF_SHARED_MEM
00426 shm = cfg_get_value(&fo_default_conf,"SharedMemIds");
00427
00428 if(create_shm_sem(shm) != 0) return EXIT_FAILURE;
00429
00430 cf_mutex_init("head.shm_lock",&head.shm_lock);
00431 #endif
00432
00433
00434
00435
00436 #ifndef DEBUG
00437 close(fileno(stdin));
00438 close(fileno(stdout));
00439 close(fileno(stderr));
00440 #endif
00441
00442 #ifdef sun
00443
00444
00445
00446
00447
00448
00449 thr_setconcurrency(6);
00450 #endif
00451
00452 pthread_attr_init(&attr);
00453
00454
00455
00456
00457
00458
00459
00460 #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
00461 memset(¶m,0,sizeof(struct sched_param));
00462
00463 param.sched_priority = (sched_get_priority_min(SCHEDULING) + sched_get_priority_max(SCHEDULING)) / 2;
00464
00465 pthread_setschedparam(pthread_self(),SCHEDULING,¶m);
00466
00467 param.sched_priority++;
00468 pthread_attr_setschedparam(&attr,¶m);
00469 pthread_attr_setinheritsched(&attr,PTHREAD_INHERIT_SCHED);
00470 #endif
00471
00472
00473 make_forumtree(&fo_default_conf,&head);
00474
00475
00476 sockfd = cf_set_us_up_the_socket(addr);
00477 size = sizeof(addr);
00478
00479 cf_push_server(sockfd,(struct sockaddr *)addr,size,cf_handle_request);
00480
00481
00482 cf_generate_cache(NULL);
00483
00484
00485
00486
00487
00488 if((status = pthread_create(&thr,&attr,archiver_and_writer,NULL)) != 0) {
00489 cf_log(LOG_ERR,__FILE__,__LINE__,"pthread_create: %s",strerror(status));
00490 RUN = 0;
00491 }
00492 pthread_detach(thr);
00493
00494
00495 if(Modules[INIT_HANDLER].elements) {
00496 ret = FLT_OK;
00497
00498 for(hi=0;hi<Modules[INIT_HANDLER].elements && (ret == FLT_DECLINE || ret == FLT_OK);hi++) {
00499 handler = array_element_at(&Modules[INIT_HANDLER],hi);
00500 fkt = (t_server_init_filter)handler->func;
00501 ret = fkt(sockfd);
00502 }
00503 }
00504
00505
00506
00507 if(ret != FLT_EXIT) {
00508 t_server *srv;
00509
00510 CF_RW_WR(&head.lock);
00511
00512
00513 for(i=0;i<INITIAL_WORKERS_NUM;i++) {
00514 if((status = pthread_create(&head.workers[i],&attr,cf_worker,NULL)) != 0) {
00515 cf_log(LOG_ERR,__FILE__,__LINE__,"pthread_create: %s\n",strerror(status));
00516 RUN = 0;
00517 break;
00518 }
00519
00520 cf_log(LOG_STD,__FILE__,__LINE__,"created worker %d\n",i);
00521 head.clients.workers++;
00522 }
00523
00524 CF_RW_UN(&head.lock);
00525
00526
00527
00528 cf_log(LOG_STD,__FILE__,__LINE__,"Read config, parsed xml, set up the socket and generated cache. Now listening...\n");
00529
00530
00531 while(RUN) {
00532
00533 FD_ZERO(&rfds);
00534
00535
00536 CF_LM(&head.server_lock);
00537
00538 for(srv = head.servers;srv;srv = srv->next) {
00539 if(sockfd < srv->sock) sockfd = srv->sock;
00540 FD_SET(srv->sock,&rfds);
00541 }
00542
00543 CF_UM(&head.server_lock);
00544
00545
00546
00547
00548
00549
00550 memset(&timeout,0,sizeof(struct timeval));
00551
00552
00553 timeout.tv_sec = 10;
00554
00555
00556 ret = select(sockfd+1,&rfds,NULL,NULL,&timeout);
00557
00558
00559 if(ret > 0) {
00560
00561 CF_LM(&head.server_lock);
00562
00563 for(srv=head.servers;srv;srv=srv->next) {
00564 if(FD_ISSET(srv->sock,&rfds)) {
00565 size = srv->size;
00566 connfd = accept(srv->sock,srv->addr,&size);
00567
00568
00569 if(connfd <= 0) {
00570 cf_log(LOG_ERR,__FILE__,__LINE__,"accept: %s\n",strerror(errno));
00571 continue;
00572 }
00573
00574 cf_push_client(connfd,srv->worker);
00575 }
00576 }
00577
00578 CF_UM(&head.server_lock);
00579 }
00580 }
00581 }
00582
00583
00584 cf_log(LOG_STD,__FILE__,__LINE__,"closing server sockets...\n");
00585 CF_LM(&head.server_lock);
00586
00587 if(1) {
00588 t_server *srv,*srv1;
00589
00590 for(srv=head.servers;srv;srv=srv1) {
00591 close(srv->sock);
00592 srv1 = srv->next;
00593 free(srv);
00594 }
00595 }
00596
00597 CF_UM(&head.server_lock);
00598
00599 free(addr);
00600
00601
00602 cf_log(LOG_STD,__FILE__,__LINE__,"cleaning up modules...\n");
00603 cleanup_modules(Modules);
00604
00605
00606 cf_log(LOG_STD,__FILE__,__LINE__,"running archiver and writing threads to disk...\n");
00607 cf_run_archiver_and_write_to_disk();
00608
00609
00610 cf_log(LOG_STD,__FILE__,__LINE__,"running cleanup code...\n");
00611 cleanup_forumtree();
00612
00613 #ifdef CF_SHARED_MEM
00614 cf_log(LOG_STD,__FILE__,__LINE__,"destroying shared memory and semaphores...\n");
00615
00616 if(head.shm_sem >= 0)
00617 if(semctl(head.shm_sem,0,IPC_RMID,NULL) == -1) cf_log(LOG_ERR,__FILE__,__LINE__,"semctl: %s\n",strerror(errno));
00618
00619 for(i=0;i<2;i++) {
00620 if(head.shm_ids[i] >= 0) {
00621 if(head.shm_ptrs[i])
00622 if(shmdt(head.shm_ptrs[i]) < 0) cf_log(LOG_ERR,__FILE__,__LINE__,"shmdt: %s\n",strerror(errno));
00623
00624 if(shmctl(head.shm_ids[i],IPC_RMID,0) < 0) cf_log(LOG_ERR,__FILE__,__LINE__,"shmctl: %s\n",strerror(errno));
00625 }
00626 }
00627 #endif
00628
00629
00630 CF_LM(&head.clients.lock);
00631
00632 size = head.clients.workers;
00633 head.clients.down = 1;
00634 CF_UM(&head.clients.lock);
00635
00636 pthread_cond_broadcast(&head.clients.cond);
00637
00638 for(i=0;i<size;i++) {
00639 pthread_join(head.workers[i],NULL);
00640 }
00641
00642
00643
00644
00645 if(head.clients.clients) {
00646 t_client *cli,*cli1;
00647
00648 CF_LM(&head.clients.lock);
00649
00650 for(cli=head.clients.clients;cli;cli=cli1) {
00651 writen(cli->sock,"506 Server is going down\n",25);
00652 close(cli->sock);
00653 cli1 = cli->next;
00654 free(cli);
00655 }
00656
00657 CF_UM(&head.clients.lock);
00658 }
00659
00660 if(head.threads) cf_hash_destroy(head.threads);
00661 if(head.protocol_handlers) cf_hash_destroy(head.protocol_handlers);
00662
00663
00664 cf_log(LOG_STD,__FILE__,__LINE__,"closing logfiles... bye!\n");
00665 pthread_mutex_lock(&head.log_lock);
00666 if(head.err) {
00667 fclose(head.err);
00668 }
00669 if(head.std) {
00670 fclose(head.std);
00671 }
00672 pthread_mutex_unlock(&head.log_lock);
00673
00674 cf_rwlock_destroy(&head.lock);
00675 cf_rwlock_destroy(&head.threads_lock);
00676
00677 pthread_mutex_destroy(&head.log_lock);
00678
00679 cf_mutex_destroy(&head.clients.cond_lock);
00680 cf_mutex_destroy(&head.clients.lock);
00681 cf_mutex_destroy(&head.server_lock);
00682
00683 pthread_cond_destroy(&head.clients.cond);
00684
00685
00686 unlink(pidfile->values[0]);
00687
00688
00689 cfg_cleanup(&fo_default_conf);
00690 cfg_cleanup(&fo_server_conf);
00691
00692 cfg_cleanup_file(&default_conf);
00693 cfg_cleanup_file(&server_conf);
00694
00695 return EXIT_SUCCESS;
00696 }
00697
00698