00001
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "config.h"
00022 #include "defines.h"
00023
00024 #include <stdlib.h>
00025 #include <stdio.h>
00026 #include <pthread.h>
00027 #include <string.h>
00028 #include <ctype.h>
00029 #include <errno.h>
00030
00031 #include <sys/types.h>
00032
00033
00034 #include <sys/socket.h>
00035 #include <netdb.h>
00036 #include <unistd.h>
00037 #include <sys/un.h>
00038
00039 #include <sys/stat.h>
00040 #include <sys/wait.h>
00041 #include <time.h>
00042
00043 #include <gdome.h>
00044
00045 #ifdef CF_SHARED_MEM
00046 # ifdef MAX
00047 # undef MAX
00048 # endif
00049 # ifdef MIN
00050 # undef MIN
00051 # endif
00052
00053 # include <sys/param.h>
00054 # include <sys/ipc.h>
00055 # include <sys/shm.h>
00056 # include <sys/sem.h>
00057 #endif
00058
00059 #ifdef CF_SHARED_MEM
00060 # include "semaphores.h"
00061 # include "shm_locking.h"
00062 #endif
00063
00064 #include "cf_pthread.h"
00065
00066 #include "hashlib.h"
00067 #include "utils.h"
00068 #include "configparser.h"
00069 #include "readline.h"
00070 #include "fo_server.h"
00071 #include "serverlib.h"
00072 #include "xml_handling.h"
00073 #include "charconvert.h"
00074 #include "archiver.h"
00075
00076
00077
00078
00079 int cf_register_protocol_handler(u_char *handler_hook,t_server_protocol_handler handler) {
00080 CF_RW_WR(&head.lock);
00081
00082 if(head.protocol_handlers == NULL) {
00083 if((head.protocol_handlers = cf_hash_new(NULL)) == NULL) {
00084 cf_log(LOG_ERR,__FILE__,__LINE__,"cf_hash_new: %s\n",strerror(errno));
00085 exit(EXIT_FAILURE);
00086 }
00087 }
00088
00089 if(cf_hash_set_static(head.protocol_handlers,handler_hook,strlen(handler_hook),handler) == 0) {
00090 cf_log(LOG_ERR,__FILE__,__LINE__,"cf_hash_set: %s\n",strerror(errno));
00091 return -1;
00092 }
00093
00094 CF_RW_UN(&head.lock);
00095
00096 return 0;
00097 }
00098
00099
00100
00101 void cf_register_thread(t_thread *t) {
00102 u_char buff[50];
00103 size_t len;
00104
00105 len = snprintf(buff,50,"t%lld",t->tid);
00106
00107 CF_RW_WR(&head.threads_lock);
00108
00109 if(!head.threads) head.threads = cf_hash_new(NULL);
00110
00111 cf_hash_set(head.threads,buff,len,&t,sizeof(t));
00112
00113 CF_RW_UN(&head.threads_lock);
00114 }
00115
00116
00117
00118 void cf_unregister_thread(t_thread *t) {
00119 u_char buff[50];
00120 size_t len;
00121
00122 len = snprintf(buff,50,"t%lld",t->tid);
00123
00124 cf_log(LOG_DBG,__FILE__,__LINE__,"unregistering thread %lld...\n",t->tid);
00125
00126 CF_RW_WR(&head.threads_lock);
00127
00128 cf_hash_entry_delete(head.threads,buff,len);
00129
00130 CF_RW_UN(&head.threads_lock);
00131 }
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144 int cf_push_server(int sockfd,struct sockaddr *addr,int size,t_worker handler) {
00145 t_server *cl;
00146
00147 CF_LM(&head.server_lock);
00148
00149 if(!head.servers) {
00150 head.servers = fo_alloc(NULL,1,sizeof(t_server),FO_ALLOC_MALLOC);
00151 head.servers->worker = handler;
00152 head.servers->sock = sockfd;
00153 head.servers->addr = addr;
00154 head.servers->size = size;
00155 head.servers->next = NULL;
00156 }
00157 else {
00158 for(cl=head.servers;cl->next;cl=cl->next) {
00159 if(cl->sock == sockfd) {
00160 cf_log(LOG_ERR,__FILE__,__LINE__,"push_server: plugin tried to register server socket twicely (sock %d)\n",sockfd);
00161 CF_UM(&head.server_lock);
00162 return -1;
00163 }
00164 }
00165
00166 if(cl->sock == sockfd) {
00167 cf_log(LOG_ERR,__FILE__,__LINE__,"push_server: plugin tried to register server socket twicely (sock %d)\n",sockfd);
00168 CF_UM(&head.server_lock);
00169 return -1;
00170 }
00171
00172 cl->next = fo_alloc(NULL,1,sizeof(t_server),FO_ALLOC_MALLOC);
00173 cl->next->sock = sockfd;
00174 cl->next->worker = handler;
00175 cl->next->addr = addr;
00176 cl->next->size = size;
00177 cl->next->next = NULL;
00178 }
00179
00180
00181 cf_log(LOG_STD,__FILE__,__LINE__,"push_server: registered server socket %d\n",sockfd);
00182 CF_UM(&head.server_lock);
00183
00184 return 0;
00185 }
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196 int cf_push_client(int connfd,t_worker handler) {
00197 int status;
00198
00199
00200
00201
00202 CF_LM(&head.clients.lock);
00203
00204
00205
00206
00207
00208 while(head.clients.workers <= 0 || (head.clients.clientnum / head.clients.workers >= 3 && head.clients.workers <= MAX_WORKERS_NUM)) {
00209
00210 if((status = pthread_create(&head.workers[head.clients.workers],NULL,cf_worker,NULL)) != 0) {
00211 cf_log(LOG_ERR,__FILE__,__LINE__,"pthread_create: %s\n",strerror(status));
00212 RUN = 0;
00213 return -1;
00214 }
00215
00216 cf_log(LOG_STD,__FILE__,__LINE__,"created worker %d now!\n",++head.clients.workers);
00217 }
00218
00219
00220
00221 if(head.clients.clientnum > MAX_CLIENT_NUM) {
00222 CF_UM(&head.clients.lock);
00223
00224 cf_log(LOG_STD,__FILE__,__LINE__,"handling request directly...\n");
00225 handler(connfd);
00226 }
00227 else {
00228
00229 if(!head.clients.last) {
00230 head.clients.last = head.clients.clients = fo_alloc(NULL,1,sizeof(t_client),FO_ALLOC_CALLOC);
00231 head.clients.last->sock = connfd;
00232 head.clients.last->worker = handler;
00233 head.clients.last->next = NULL;
00234 }
00235 else {
00236 head.clients.last->next = fo_alloc(NULL,1,sizeof(t_client),FO_ALLOC_MALLOC);
00237 head.clients.last->next->sock = connfd;
00238 head.clients.last->next->worker = handler;
00239 head.clients.last->next->next = NULL;
00240 head.clients.last = head.clients.last->next;
00241 }
00242
00243 head.clients.clientnum++;
00244
00245 CF_UM(&head.clients.lock);
00246
00247
00248 CF_LM(&head.clients.cond_lock);
00249
00250
00251 pthread_cond_signal(&head.clients.cond);
00252
00253
00254 CF_UM(&head.clients.cond_lock);
00255
00256 CF_LM(&head.clients.lock);
00257
00258
00259 if(head.clients.clientnum > CLIENT_PRIORITY_NUM) {
00260 CF_UM(&head.clients.lock);
00261
00262 cf_log(LOG_STD,__FILE__,__LINE__,"yielding server thread...\n");
00263 pthread_yield();
00264 }
00265 else {
00266 CF_UM(&head.clients.lock);
00267 }
00268 }
00269
00270 return 0;
00271 }
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285 void cf_log(int mode,const u_char *file,int line,const u_char *format,...) {
00286 u_char str[300];
00287 int status;
00288 t_name_value *v;
00289 time_t t;
00290 struct tm *tm;
00291 int sz;
00292 va_list ap;
00293 register u_char *ptr,*ptr1;
00294
00295 #ifndef DEBUG
00296 if(mode == LOG_DBG) return;
00297 #endif
00298
00299 for(ptr1=ptr=(u_char *)file;*ptr;ptr++) {
00300 if(*ptr == '/') ptr1 = ptr + 1;
00301 }
00302
00303 t = time(NULL);
00304 tm = localtime(&t);
00305
00306 if((status = pthread_mutex_lock(&head.log_lock)) != 0) {
00307 fprintf(stderr,"pthread_mutex_lock: %s\n",strerror(status));
00308 return;
00309 }
00310
00311 if(!head.std) {
00312 v = cfg_get_value(&fo_server_conf,"StdLog");
00313 head.std = fopen(v->values[0],"a");
00314 }
00315 if(!head.err) {
00316 v = cfg_get_value(&fo_server_conf,"ErrorLog");
00317 head.err = fopen(v->values[0],"a");
00318 }
00319
00320 sz = snprintf(str,300,"[%4d-%02d-%02d %02d:%02d:%02d]:%s:%d ",tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec,ptr1,line);
00321
00322 va_start(ap, format);
00323 if(mode == LOG_ERR) {
00324 fwrite(str,sz,1,head.err);
00325 vfprintf(head.err,format,ap);
00326 fflush(head.err);
00327
00328 #ifdef DEBUG
00329 fwrite(str,sz,1,stderr);
00330 vfprintf(stderr,format,ap);
00331 #endif
00332 }
00333 else if(mode == LOG_STD) {
00334 fwrite(str,sz,1,head.std);
00335 vfprintf(head.std,format,ap);
00336
00337
00338
00339
00340
00341
00342
00343 #ifdef DEBUG
00344 fflush(head.std);
00345
00346 fwrite(str,sz,1,stdout);
00347 vfprintf(stdout,format,ap);
00348 #endif
00349 }
00350 #ifdef DEBUG
00351 else {
00352 fwrite(str,sz,1,head.std);
00353 fwrite(str,sz,1,stdout);
00354 fwrite("DEBUG: ",7,1,head.std);
00355 fwrite("DEBUG: ",7,1,stdout);
00356 vfprintf(head.std,format,ap);
00357 vfprintf(stdout,format,ap);
00358 fflush(head.std);
00359 fflush(stdout);
00360 }
00361 #endif
00362 va_end(ap);
00363
00364 pthread_mutex_unlock(&head.log_lock);
00365 }
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376 int cf_set_us_up_the_socket(struct sockaddr_un *addr) {
00377 int sock;
00378 t_name_value *sockpath = cfg_get_value(&fo_default_conf,"SocketName");
00379
00380 if(!sockpath) {
00381 cf_log(LOG_ERR,__FILE__,__LINE__,"could not find socket path!\n");
00382 RUN = 0;
00383 return -1;
00384 }
00385
00386 sock = socket(AF_LOCAL,SOCK_STREAM,0);
00387
00388 if(sock == -1) {
00389 cf_log(LOG_ERR,__FILE__,__LINE__,"socket: %s\n",sock,strerror(errno));
00390 RUN = 0;
00391 return -1;
00392 }
00393
00394 unlink(sockpath->values[0]);
00395
00396 memset(addr,0,sizeof(struct sockaddr_un));
00397 addr->sun_family = AF_LOCAL;
00398 (void)strncpy(addr->sun_path,sockpath->values[0],104);
00399
00400 if(bind(sock,(struct sockaddr *)addr,sizeof(struct sockaddr_un)) < 0) {
00401 cf_log(LOG_ERR,__FILE__,__LINE__,"bind: %s\n",strerror(errno));
00402 RUN = 0;
00403 return -1;
00404 }
00405
00406 if(listen(sock,LISTENQ) != 0) {
00407 cf_log(LOG_ERR,__FILE__,__LINE__,"listen: %s\n",strerror(errno));
00408 RUN = 0;
00409 return -1;
00410 }
00411
00412 chmod(sockpath->values[0],S_IRWXU|S_IRWXG|S_IRWXO);
00413
00414 return sock;
00415 }
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426 void *cf_worker(void *arg) {
00427 t_client *client;
00428 struct timespec timeout;
00429 int retries = 0,status;
00430
00431 while(RUN) {
00432
00433
00434
00435
00436 CF_LM(&head.clients.lock);
00437
00438 while(!head.clients.clients && RUN) {
00439
00440 CF_UM(&head.clients.lock);
00441
00442
00443 CF_LM(&head.clients.cond_lock);
00444
00445
00446 timeout.tv_sec = time(NULL) + 5;
00447 timeout.tv_nsec = 0;
00448
00449
00450 if((status = pthread_cond_timedwait(&head.clients.cond,&head.clients.cond_lock.mutex,&timeout)) != 0) {
00451 CF_UM(&head.clients.cond_lock);
00452
00453
00454 if(status != ETIMEDOUT) {
00455 cf_log(LOG_ERR,__FILE__,__LINE__,"pthread_cond_timedwait: %s. We're going to retry it...\n",strerror(status));
00456 retries++;
00457 }
00458 else {
00459 retries = 0;
00460 }
00461
00462 CF_LM(&head.clients.lock);
00463
00464 if(retries < 3) {
00465 continue;
00466 }
00467 else {
00468 cf_log(LOG_ERR,__FILE__,__LINE__,"Worker tried it three times, and he got three times an error. He goes down...\n");
00469 head.clients.workers--;
00470 CF_UM(&head.clients.lock);
00471 return NULL;
00472 }
00473 }
00474
00475
00476 CF_UM(&head.clients.cond_lock);
00477
00478
00479 CF_LM(&head.clients.lock);
00480 }
00481
00482
00483 if(RUN) {
00484
00485 client = head.clients.clients;
00486
00487 if(client) {
00488 head.clients.clients = client->next;
00489 head.clients.clientnum--;
00490
00491 if(!head.clients.clients) head.clients.last = NULL;
00492
00493 CF_UM(&head.clients.lock);
00494
00495 if(client->worker) {
00496 client->worker(client->sock);
00497 }
00498 else {
00499
00500 cf_log(LOG_ERR,__FILE__,__LINE__,"Wasting client?!\n");
00501 close(client->sock);
00502 }
00503
00504 free(client);
00505 }
00506 else {
00507
00508 CF_UM(&head.clients.lock);
00509 }
00510 }
00511 else {
00512 CF_UM(&head.clients.lock);
00513 }
00514 }
00515
00516 return NULL;
00517 }
00518
00519
00520
00527 int cf_tokenize(u_char *line,u_char ***tokens) {
00528 int n = 0,reser = 5;
00529 register u_char *ptr,*prev;
00530
00531 *tokens = malloc(5 * sizeof(u_char **));
00532 if(!*tokens) return 0;
00533
00534 for(prev=ptr=line;*ptr;ptr++) {
00535 if(n >= reser) {
00536 reser += 5;
00537 *tokens = fo_alloc(*tokens,reser,sizeof(*tokens),FO_ALLOC_REALLOC);
00538 }
00539
00540 if(isspace(*ptr) || *ptr == ':') {
00541 if(ptr - 1 == prev || ptr == prev) {
00542 prev = ptr;
00543 continue;
00544 }
00545
00546 *ptr = 0;
00547 (*tokens)[n++] = memdup(prev,ptr-prev+1);
00548 prev = ptr+1;
00549 }
00550 }
00551
00552 if(prev != ptr && prev-1 != ptr && *ptr) (*tokens)[n++] = memdup(prev,ptr-prev);
00553
00554 return n;
00555 }
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567 void cf_handle_request(int sockfd) {
00568 int shallRun = 1,i;
00569 rline_t *tsd = fo_alloc(NULL,1,sizeof(*tsd),FO_ALLOC_CALLOC);
00570 u_char *line = NULL,**tokens;
00571 int locked = 0,tnum = 0;
00572
00573 while(shallRun) {
00574 line = readline(sockfd,tsd);
00575 cf_log(LOG_DBG,__FILE__,__LINE__,"%s",line?line:(u_char *)"(NULL)\n");
00576
00577 if(line) {
00578 tnum = cf_tokenize(line,&tokens);
00579
00580 if(tnum) {
00581 if(cf_strcmp(tokens[0],"QUIT") == 0) {
00582 if(tnum == 2) {
00583 if(cf_strcmp(tokens[1],"SERVER") == 0) {
00584 shallRun = 0;
00585 RUN = 0;
00586
00587 writen(sockfd,"200 Bye, bye\n",13);
00588 }
00589 else {
00590 writen(sockfd,"500 What do you mean?\n",22);
00591 }
00592 }
00593 else {
00594 shallRun = 0;
00595 writen(sockfd,"200 Bye, bye\n",13);
00596 }
00597 }
00598 else if(cf_strcmp(tokens[0],"ARCHIVE") == 0) {
00599 u_int64_t tid;
00600 u_char *ln = readline(sockfd,tsd);
00601
00602 if(ln == NULL) {
00603 cf_log(LOG_ERR,__FILE__,__LINE__,"declined archivation because user name not present\n");
00604 writen(sockfd,"403 Access Denied\n",18);
00605 }
00606 if(tnum < 3) {
00607 writen(sockfd,"500 Sorry\n",10);
00608 cf_log(LOG_ERR,__FILE__,__LINE__,"Bad request\n");
00609 }
00610 else {
00611 tid = strtoull(tokens[2]+2,NULL,10);
00612 cf_log(LOG_ERR,__FILE__,__LINE__,"archiving thread %lld by user %s",tid,ln);
00613
00614 cf_archive_thread(sockfd,tid);
00615 cf_generate_cache(NULL);
00616 }
00617
00618 if(ln) free(ln);
00619 }
00620 else if(cf_strcmp(tokens[0],"DELETE") == 0) {
00621 u_int64_t tid,mid;
00622 t_thread *t;
00623 t_posting *p;
00624 int lvl;
00625 u_char *ln = readline(sockfd,tsd);
00626
00627 if(ln == NULL) {
00628 cf_log(LOG_ERR,__FILE__,__LINE__,"declined deletion because user name not present\n");
00629 writen(sockfd,"403 Access Denied\n",18);
00630 }
00631 else if(tnum != 3) {
00632 writen(sockfd,"501 Thread id or message id missing\n",36);
00633 }
00634 else {
00635 tid = strtoull(tokens[1]+2,NULL,10);
00636 mid = strtoull(tokens[2]+2,NULL,10);
00637
00638 t = cf_get_thread(tid);
00639
00640 if(!t) {
00641 writen(sockfd,"404 Thread Not Found\n",21);
00642 cf_log(LOG_ERR,__FILE__,__LINE__,"Thread not found\n");
00643 }
00644 else {
00645 p = cf_get_posting(t,mid);
00646
00647 if(!p) {
00648 writen(sockfd,"404 Message Not Found\n",22);
00649 cf_log(LOG_ERR,__FILE__,__LINE__,"Message not found\n");
00650 }
00651 else {
00652 cf_log(LOG_ERR,__FILE__,__LINE__,"Deleted posting %lld in thread %lld by user %s\n",tid,mid,ln);
00653
00654 CF_RW_WR(&t->lock);
00655
00656 lvl = p->level;
00657 p->invisible = 1;
00658
00659 for(p=p->next;p && p->level > lvl;p=p->next) {
00660 p->invisible = 1;
00661 }
00662
00663 writen(sockfd,"200 Ok\n",7);
00664
00665 CF_RW_UN(&t->lock);
00666
00667
00668 cf_generate_cache(NULL);
00669 }
00670 }
00671 }
00672
00673 if(ln) free(ln);
00674 }
00675 else if(cf_strcmp(tokens[0],"UNDELETE") == 0) {
00676 u_int64_t tid,mid;
00677 t_thread *t;
00678 t_posting *p;
00679 int lvl;
00680 u_char *ln = readline(sockfd,tsd);
00681
00682 if(ln == NULL) {
00683 cf_log(LOG_ERR,__FILE__,__LINE__,"declined undelete because user name not present\n");
00684 writen(sockfd,"403 Access Denied\n",18);
00685 }
00686 if(tnum < 3) {
00687 writen(sockfd,"501 Thread id or message id missing\n",36);
00688 }
00689 else {
00690 tid = strtoull(tokens[1]+2,NULL,10);
00691 mid = strtoull(tokens[2]+2,NULL,10);
00692
00693 t = cf_get_thread(tid);
00694
00695 if(!t) {
00696 writen(sockfd,"404 Thread Not Found\n",21);
00697 cf_log(LOG_ERR,__FILE__,__LINE__,"Thread not found\n");
00698 }
00699 else {
00700 p = cf_get_posting(t,mid);
00701 cf_log(LOG_ERR,__FILE__,__LINE__,"Undelete posting %lld in posting %lld by user %lld\n",tid,mid,ln);
00702
00703 if(!p) {
00704 writen(sockfd,"404 Message Not Found\n",22);
00705 cf_log(LOG_ERR,__FILE__,__LINE__,"Message not found\n");
00706 }
00707 else {
00708 CF_RW_WR(&t->lock);
00709
00710 lvl = p->level;
00711 p->invisible = 0;
00712
00713 for(p=p->next;p && p->level > lvl;p=p->next) {
00714 p->invisible = 0;
00715 }
00716
00717 writen(sockfd,"200 Ok\n",7);
00718
00719 CF_RW_UN(&t->lock);
00720
00721
00722 cf_generate_cache(NULL);
00723 }
00724 }
00725 }
00726
00727 if(ln) free(ln);
00728 }
00729 else if(cf_strcmp(line,"UNLOCK") == 0) {
00730 if(tnum == 2 && cf_strcmp(tokens[1],"FORUM") == 0) {
00731 CF_RW_WR(&head.lock);
00732 head.locked = 0;
00733 CF_RW_UN(&head.lock);
00734 }
00735 else {
00736 writen(sockfd,"500 What's up?\n",15);
00737 }
00738 }
00739 else {
00740 CF_RW_RD(&head.lock);
00741 locked = head.locked;
00742 CF_RW_UN(&head.lock);
00743
00744 if(locked == 0) {
00745 if(cf_strcmp(tokens[0],"LOCK") == 0) {
00746 if(tnum == 2 && cf_strcmp(tokens[1],"FORUM") == 0) {
00747 CF_RW_WR(&head.lock);
00748 head.locked = 1;
00749 CF_RW_UN(&head.lock);
00750 }
00751 else {
00752 writen(sockfd,"500 What's up?\n",15);
00753 }
00754 }
00755 else {
00756
00757 t_server_protocol_handler handler;
00758 int ret;
00759
00760 CF_RW_RD(&head.lock);
00761
00762 if(head.protocol_handlers) {
00763 CF_RW_UN(&head.lock);
00764
00765 handler = cf_hash_get(head.protocol_handlers,tokens[0],strlen(tokens[0]));
00766 if(handler == NULL) {
00767 writen(sockfd,"500 What's up?\n",15);
00768 }
00769 else {
00770 ret = handler(sockfd,(const u_char **)tokens,tnum,tsd);
00771
00772 if(ret == FLT_DECLINE) {
00773 writen(sockfd,"500 What's up?\n",15);
00774 }
00775 }
00776 }
00777 else {
00778 writen(sockfd,"500 What's up?\n",15);
00779 CF_RW_UN(&head.lock);
00780 }
00781 }
00782 }
00783 }
00784
00785 free(line);
00786 line = NULL;
00787
00788 for(i=0;i<tnum;i++) free(tokens[i]);
00789 free(tokens);
00790 }
00791 else {
00792 writen(sockfd,"500 What's up?\n",15);
00793 }
00794 }
00795 else {
00796 shallRun = 0;
00797 }
00798 }
00799
00800 if(line) free(line);
00801
00802 free(tsd);
00803 close(sockfd);
00804 }
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816 int cf_read_posting(t_posting *p,int sock,rline_t *tsd) {
00817 u_char *line = NULL;
00818 unsigned long llen;
00819 p->user.ip = NULL;
00820
00821 do {
00822 line = readline(sock,tsd);
00823
00824 if(line) {
00825 llen = tsd->rl_len;
00826 line[llen-1] = '\0';
00827
00828 cf_log(LOG_DBG,__FILE__,__LINE__,"read_posting: got line %s\n",line);
00829
00830 if(cf_strncmp(line,"Unid:",5) == 0) {
00831 p->unid = strdup(line+6);
00832 p->unid_len = llen - 7;
00833 }
00834 else if(cf_strncmp(line,"Author:",7) == 0) {
00835 p->user.name = strdup(line+8);
00836 p->user.name_len = llen - 9;
00837 }
00838 else if(cf_strncmp(line,"EMail:",6) == 0) {
00839 p->user.email = strdup(line+7);
00840 p->user.email_len = llen - 8;
00841 }
00842 else if(cf_strncmp(line,"Category:",9) == 0) {
00843 p->category = strdup(line+10);
00844 p->category_len = llen - 11;
00845 }
00846 else if(cf_strncmp(line,"Subject:",8) == 0) {
00847 p->subject = strdup(line+9);
00848 p->subject_len = llen - 10;
00849 }
00850 else if(cf_strncmp(line,"HomepageUrl:",12) == 0) {
00851 p->user.hp = strdup(line+13);
00852 p->user.hp_len = llen - 14;
00853 }
00854 else if(cf_strncmp(line,"ImageUrl:",9) == 0) {
00855 p->user.img = strdup(line+10);
00856 p->user.img_len = llen - 11;
00857 }
00858 else if(cf_strncmp(line,"Body:",5) == 0) {
00859 p->content = strdup(line+6);
00860 p->content_len = llen - 7;
00861 }
00862 else if(cf_strncmp(line,"RemoteAddr:",11) == 0) {
00863 p->user.ip = strdup(line+12);
00864 p->user.ip_len = llen - 13;
00865 }
00866 else {
00867 free(line);
00868 line = NULL;
00869 }
00870
00871 if(line) free(line);
00872 }
00873 else {
00874 cf_log(LOG_ERR,__FILE__,__LINE__,"readline: %s\n",strerror(errno));
00875 }
00876 } while(line);
00877
00878 p->date = time(NULL);
00879
00880 if(!p->user.name || !p->user.ip || !p->unid) {
00881 writen(sock,"500 Sorry\n",10);
00882 return 0;
00883 }
00884
00885 CF_RW_WR(&head.lock);
00886 p->mid = ++head.mid;
00887 CF_RW_UN(&head.lock);
00888
00889 return 1;
00890 }
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903 void cf_send_posting(int sock,u_int64_t tid,u_int64_t mid,int invisible) {
00904 int n;
00905 u_char buff[500];
00906 t_thread *t = cf_get_thread(tid);
00907 t_posting *p;
00908 t_string bff;
00909 int first = 1;
00910
00911 if(!t) {
00912 writen(sock,"404 Thread not found\n",21);
00913 return;
00914 }
00915
00916 if(mid != 0) {
00917 p = cf_get_posting(t,mid);
00918
00919 if(!p) {
00920 writen(sock,"404 Posting not found\n",22);
00921 return;
00922 }
00923 }
00924
00925 str_init(&bff);
00926
00927 str_chars_append(&bff,"200 Ok\n",7);
00928
00929 CF_RW_RD(&t->lock);
00930
00931 if(p) {
00932 if(p->invisible == 1 && !invisible) {
00933 writen(sock,"404 Posting not found\n",22);
00934 CF_RW_UN(&t->lock);
00935 return;
00936 }
00937 }
00938
00939 p = t->postings;
00940 n = sprintf(buff,"THREAD t%lld m%lld\n",t->tid,p->mid);
00941 str_chars_append(&bff,buff,n);
00942
00943 for(;p;p=p->next) {
00944 if(p->invisible && !invisible) {
00945 for(;p && p->invisible;p=p->next);
00946 if(!p) break;
00947 }
00948
00949 if(!first) {
00950 n = sprintf(buff,"MSG m%lld\n",p->mid);
00951 str_chars_append(&bff,buff,n);
00952 }
00953
00954 first = 0;
00955
00956 str_chars_append(&bff,"Author:",7);
00957 str_chars_append(&bff,p->user.name,p->user.name_len);
00958
00959 if(p->user.email) {
00960 str_chars_append(&bff,"\nEMail:",7);
00961 str_chars_append(&bff,p->user.email,p->user.email_len);
00962 }
00963
00964 if(p->user.hp) {
00965 str_chars_append(&bff,"\nHomepage:",10);
00966 str_chars_append(&bff,p->user.hp,p->user.hp_len);
00967 }
00968
00969 if(p->user.img) {
00970 str_chars_append(&bff,"\nImage:",7);
00971 str_chars_append(&bff,p->user.img,p->user.img_len);
00972 }
00973
00974 str_chars_append(&bff,"\nSubject:",9);
00975 str_chars_append(&bff,p->subject,p->subject_len);
00976
00977 if(p->category) {
00978 str_chars_append(&bff,"\nCategory:",10);
00979 str_chars_append(&bff,p->category,p->category_len);
00980 }
00981
00982 n = sprintf(buff,"\nDate:%ld\n",p->date);
00983 str_chars_append(&bff,buff,n);
00984
00985 n = sprintf(buff,"Level:%d\n",p->level);
00986 str_chars_append(&bff,buff,n);
00987
00988 n = sprintf(buff,"Visible:%d\n",p->invisible == 0);
00989 str_chars_append(&bff,buff,n);
00990
00991 str_chars_append(&bff,"Content:",8);
00992 str_chars_append(&bff,p->content,p->content_len);
00993
00994 str_char_append(&bff,'\n');
00995 }
00996
00997 CF_RW_UN(&t->lock);
00998
00999 str_char_append(&bff,'\n');
01000
01001 writen(sock,bff.content,bff.len);
01002 free(bff.content);
01003 }
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015 t_posting *cf_get_posting(t_thread *t,u_int64_t mid) {
01016 t_posting *p;
01017
01018 CF_RW_RD(&t->lock);
01019
01020 for(p=t->postings;p && p->mid != mid;p=p->next);
01021
01022 CF_RW_UN(&t->lock);
01023
01024 return p;
01025 }
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036 t_thread *cf_get_thread(u_int64_t tid) {
01037 t_thread **t = NULL;
01038 u_char buff[50];
01039 size_t len;
01040
01041 len = snprintf(buff,50,"t%lld",tid);
01042
01043 CF_RW_RD(&head.threads_lock);
01044 if(head.threads) t = cf_hash_get(head.threads,buff,len);
01045 CF_RW_UN(&head.threads_lock);
01046
01047 return t ? *t : NULL;
01048 }
01049
01050
01051
01052 #ifdef CF_SHARED_MEM
01053
01054
01061 int cf_shmdt(void *ptr) {
01062 cf_log(LOG_DBG,__FILE__,__LINE__,"shmdt: detaching %ld\n",ptr);
01063 return shmdt(ptr);
01064 }
01065
01066
01067
01076 void *cf_shmat(int shmid,void *addr,int shmflag) {
01077 void *ptr = shmat(shmid,addr,shmflag);
01078
01079 cf_log(LOG_DBG,__FILE__,__LINE__,"shmat: attatching segment %d (%ld)\n",shmid,ptr);
01080
01081 return ptr;
01082 }
01083
01084
01085 void cf_generate_shared_memory() {
01086 t_mem_pool pool;
01087 t_thread *t,*t1;
01088 t_posting *p;
01089 t_name_value *v = cfg_get_value(&fo_default_conf,"SharedMemIds");
01090 u_int32_t val;
01091 time_t tm = time(NULL);
01092 unsigned short semval;
01093
01094 mem_init(&pool);
01095
01096 CF_RW_RD(&head.lock);
01097 t1 = t = head.thread;
01098 CF_RW_UN(&head.lock);
01099
01100
01101
01102
01103
01104
01105
01106 mem_append(&pool,&tm,sizeof(t));
01107
01108 for(;t;t=t1) {
01109 CF_RW_RD(&t->lock);
01110
01111
01112 mem_append(&pool,&(t->tid),sizeof(t->tid));
01113 mem_append(&pool,&(t->posts),sizeof(t->posts));
01114
01115 for(p=t->postings;p;p=p->next) {
01116 mem_append(&pool,&(p->mid),sizeof(p->mid));
01117
01118 val = p->subject_len + 1;
01119 mem_append(&pool,&val,sizeof(val));
01120 mem_append(&pool,p->subject,val);
01121
01122 val = p->category_len + 1;
01123 if(val > 1) {
01124 mem_append(&pool,&val,sizeof(val));
01125 mem_append(&pool,p->category,val);
01126 }
01127 else {
01128 val = 0;
01129 mem_append(&pool,&val,sizeof(val));
01130 }
01131
01132 val = p->content_len + 1;
01133 mem_append(&pool,&val,sizeof(val));
01134 mem_append(&pool,p->content,val);
01135
01136 mem_append(&pool,&(p->date),sizeof(p->date));
01137 mem_append(&pool,&(p->level),sizeof(p->level));
01138 mem_append(&pool,&(p->invisible),sizeof(p->invisible));
01139
01140 val = p->user.name_len + 1;
01141 mem_append(&pool,&val,sizeof(val));
01142 mem_append(&pool,p->user.name,val);
01143
01144 val = p->user.email_len + 1;
01145 if(val > 1) {
01146 mem_append(&pool,&val,sizeof(val));
01147 mem_append(&pool,p->user.email,val);
01148 }
01149 else {
01150 val = 0;
01151 mem_append(&pool,&val,sizeof(val));
01152 }
01153
01154 val = p->user.hp_len + 1;
01155 if(val > 1) {
01156 mem_append(&pool,&val,sizeof(val));
01157 mem_append(&pool,p->user.hp,val);
01158 }
01159 else {
01160 val = 0;
01161 mem_append(&pool,&val,sizeof(val));
01162 }
01163
01164 val = p->user.img_len + 1;
01165 if(val > 1) {
01166 mem_append(&pool,&val,sizeof(val));
01167 mem_append(&pool,p->user.img,val);
01168 }
01169 else {
01170 val = 0;
01171 mem_append(&pool,&val,sizeof(val));
01172 }
01173 }
01174
01175 t1 = t->next;
01176 CF_RW_UN(&t->lock);
01177 t = t1;
01178 }
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188 CF_LM(&head.shm_lock);
01189
01190 if(cf_sem_getval(head.shm_sem,0,1,&semval) == -1) {
01191 cf_log(LOG_ERR,__FILE__,__LINE__,"cf_sem_getval: %s\n",strerror(errno));
01192 exit(-1);
01193 }
01194
01195
01196 if(semval != 0 && semval != 1) {
01197 cf_log(LOG_ERR,__FILE__,__LINE__,"hu? what happened? semval is %d\n",semval);
01198 semval = 0;
01199 }
01200
01201 cf_log(LOG_DBG,__FILE__,__LINE__,"shm_ids[%d]: %ld\n",semval,head.shm_ids[semval]);
01202
01203
01204 if(head.shm_ids[semval] != -1) {
01205
01206
01207 cf_log(LOG_DBG,__FILE__,__LINE__,"shm_ptrs[%d]: %ld\n",semval,head.shm_ptrs[semval]);
01208
01209
01210 if(head.shm_ptrs[semval]) {
01211 if(cf_shmdt(head.shm_ptrs[semval]) != 0) {
01212 cf_log(LOG_ERR,__FILE__,__LINE__,"shmdt: %s (semval: %d)\n",strerror(errno),semval);
01213 CF_UM(&head.shm_lock);
01214 mem_cleanup(&pool);
01215 return;
01216 }
01217 }
01218
01219
01220 if(shmctl(head.shm_ids[semval],IPC_RMID,NULL) != 0) {
01221 cf_log(LOG_ERR,__FILE__,__LINE__,"shmctl: %s\n",strerror(errno));
01222 CF_UM(&head.shm_lock);
01223 mem_cleanup(&pool);
01224 return;
01225 }
01226 }
01227
01228 if((head.shm_ids[semval] = shmget(atoi(v->values[semval]),pool.len,IPC_CREAT|CF_SHARED_MODE)) == -1) {
01229 cf_log(LOG_ERR,__FILE__,__LINE__,"shmget: %s\n",strerror(errno));
01230 exit(EXIT_FAILURE);
01231 }
01232
01233 if((head.shm_ptrs[semval] = cf_shmat(head.shm_ids[semval],NULL,0)) == NULL) {
01234 cf_log(LOG_ERR,__FILE__,__LINE__,"shmat: %s\n",strerror(errno));
01235 exit(EXIT_FAILURE);
01236 }
01237
01238 memcpy(head.shm_ptrs[semval],pool.content,pool.len);
01239
01240 mem_cleanup(&pool);
01241
01242 if(semval == 1) {
01243 CF_SEM_DOWN(head.shm_sem,0);
01244 }
01245 else {
01246 CF_SEM_UP(head.shm_sem,0);
01247 }
01248
01249 CF_UM(&head.shm_lock);
01250
01251 cf_log(LOG_DBG,__FILE__,__LINE__,"generated shared memory segment %d\n",semval);
01252 }
01253
01254 #endif
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265 void *cf_generate_cache(void *arg) {
01266 #ifndef CF_SHARED_MEM
01267 t_string str1,str2;
01268
01269 str_init(&str1);
01270 str_init(&str2);
01271
01272 cf_generate_list(&str1,0);
01273 cf_generate_list(&str2,1);
01274
01275 CF_RW_WR(&head.lock);
01276
01277 if(head.cache_invisible.content) {
01278 free(head.cache_invisible.content);
01279 }
01280 if(head.cache_visible.content) {
01281 free(head.cache_visible.content);
01282 }
01283
01284 head.cache_invisible.content = str2.content;
01285 head.cache_visible.content = str1.content;
01286 head.cache_invisible.len = str2.len;
01287 head.cache_visible.len = str1.len;
01288
01289 head.date_visible = time(NULL);
01290 head.date_invisible = time(NULL);
01291
01292 head.fresh = 1;
01293
01294 CF_RW_UN(&head.lock);
01295 #else
01296 cf_generate_shared_memory();
01297 #endif
01298
01299 return NULL;
01300 }
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312 void cf_generate_list(t_string *str,int del) {
01313 int n;
01314 u_char buff[500];
01315 t_thread *t,*t1;
01316
01317 str_chars_append(str,"200 Ok\n",7);
01318
01319 CF_RW_RD(&head.lock);
01320 t1 = head.thread;
01321 CF_RW_UN(&head.lock);
01322
01323 while(t1) {
01324 int first = 1;
01325 t_posting *p;
01326
01327 t = t1;
01328
01329 CF_RW_RD(&t->lock);
01330
01331 for(p = t->postings;p;p = p->next) {
01332 if(p->invisible && !del) {
01333 for(;p && p->invisible;p=p->next);
01334
01335 if(!p) {
01336 break;
01337 }
01338 }
01339
01340
01341
01342 if(first) {
01343 first = 0;
01344 n = sprintf(buff,"THREAD t%lld m%lld\n",t->tid,p->mid);
01345 }
01346 else {
01347 n = sprintf(buff,"MSG m%lld\n",p->mid);
01348 }
01349
01350 str_chars_append(str,buff,n);
01351
01352
01353 str_chars_append(str,"Author:",7);
01354 str_chars_append(str,p->user.name,p->user.name_len);
01355
01356
01357 str_chars_append(str,"\nSubject:",9);
01358 str_chars_append(str,p->subject,p->subject_len);
01359
01360
01361 if(p->category) {
01362 str_chars_append(str,"\nCategory:",10);
01363 str_chars_append(str,p->category,p->category_len);
01364 }
01365
01366
01367 n = sprintf(buff,"\nDate:%ld\n",p->date);
01368 str_chars_append(str,buff,n);
01369
01370
01371 n = sprintf(buff,"Level:%d\n",p->level);
01372 str_chars_append(str,buff,n);
01373
01374 n = sprintf(buff,"Visible:%d\n",p->invisible == 0);
01375 str_chars_append(str,buff,n);
01376 }
01377
01378 str_chars_append(str,"END\n",4);
01379
01380 t1 = t->next;
01381 CF_RW_UN(&t->lock);
01382 }
01383
01384 str_char_append(str,'\n');
01385 }
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400 void cf_send_thread_list(int sockfd,int del) {
01401 int n;
01402 u_char buff[500];
01403 t_thread *t,*t1;
01404
01405 CF_RW_RD(&head.lock);
01406 t = head.thread;
01407 CF_RW_UN(&head.lock);
01408
01409 writen(sockfd,"200 Ok\n",7);
01410
01411 while(t) {
01412 int first = 1;
01413 t_posting *p;
01414
01415 CF_RW_RD(&t->lock);
01416
01417 for(p = t->postings;p;p = p->next) {
01418 if(p->invisible && !del) {
01419 for(;p && p->invisible;p=p->next);
01420
01421 if(!p) {
01422 break;
01423 }
01424 }
01425
01426
01427 if(first) {
01428 first = 0;
01429 n = sprintf(buff,"THREAD t%lld m%lld\n",t->tid,p->mid);
01430 }
01431 else {
01432 n = sprintf(buff,"MSG m%lld\n",p->mid);
01433 }
01434
01435 if(writen(sockfd,buff,n) <= 0) {
01436 cf_log(LOG_ERR,__FILE__,__LINE__,"writen: %s\n",strerror(errno));
01437 CF_RW_UN(&t->lock);
01438 return;
01439 }
01440
01441
01442 if(writen(sockfd,"Author:",7) <= 0) {
01443 cf_log(LOG_ERR,__FILE__,__LINE__,"writen: %s\n",strerror(errno));
01444 CF_RW_UN(&t->lock);
01445 return;
01446 }
01447 if(writen(sockfd,p->user.name,p->user.name_len) <= 0) {
01448 cf_log(LOG_ERR,__FILE__,__LINE__,"writen: %s\n",strerror(errno));
01449 CF_RW_UN(&t->lock);
01450 return;
01451 }
01452
01453
01454 if(writen(sockfd,"\nSubject:",9) <= 0) {
01455 cf_log(LOG_ERR,__FILE__,__LINE__,"writen: %s\n",strerror(errno));
01456 CF_RW_UN(&t->lock);
01457 return;
01458 }
01459 if(writen(sockfd,p->subject,p->subject_len) <= 0) {
01460 cf_log(LOG_ERR,__FILE__,__LINE__,"writen: %s\n",strerror(errno));
01461 CF_RW_UN(&t->lock);
01462 return;
01463 }
01464
01465
01466 if(p->category) {
01467 if(writen(sockfd,"\nCategory:",10) <= 0) {
01468 cf_log(LOG_ERR,__FILE__,__LINE__,"writen: %s\n",strerror(errno));
01469 CF_RW_UN(&t->lock);
01470 return;
01471 }
01472 if(writen(sockfd,p->category,p->category_len) <= 0) {
01473 cf_log(LOG_ERR,__FILE__,__LINE__,"writen: %s\n",strerror(errno));
01474 CF_RW_UN(&t->lock);
01475 return;
01476 }
01477 }
01478
01479
01480 n = sprintf(buff,"\nDate:%ld\n",p->date);
01481 if(writen(sockfd,buff,n) <= 0) {
01482 cf_log(LOG_ERR,__FILE__,__LINE__,"writen: %s\n",strerror(errno));
01483 CF_RW_UN(&t->lock);
01484 return;
01485 }
01486
01487
01488 n = sprintf(buff,"Level:%d\n",p->level);
01489 if(writen(sockfd,buff,n) <= 0) {
01490 cf_log(LOG_ERR,__FILE__,__LINE__,"writen: %s\n",strerror(errno));
01491 CF_RW_UN(&t->lock);
01492 return;
01493 }
01494 }
01495
01496 writen(sockfd,"END\n",4);
01497
01498 t1 = t->next;
01499 CF_RW_UN(&t->lock);
01500 t = t1;
01501 }
01502
01503 writen(sockfd,"\n",1);
01504 }
01505
01506
01507