/* needed to define accept() and gethostbyaddr() correctly when using flag -std1 */ #ifdef __unix__ #ifndef _XOPEN_SOURCE_EXTENDED #define _XOPEN_SOURCE_EXTENDED #endif #endif #include #include #include #include #include #include #include #include #include "sys_util.h" #include "err_handling.h" #include "coc_logfile.h" #include "coc_server.h" #include "str_util.h" static Str_Buf *buf, *bufo; static fd_set mask, rmask; static int maxfd; struct CocClient *cList, *cLastCmd=NULL; static int mainFd; static int modified; int CocInitServer(int bufsize, int port) { int i; struct sockaddr_in sadr; char *err; if (bufsize==0) bufsize=1024; ERR_P(buf=str_create_buf(bufsize, '\0')); ERR_P(bufo=str_create_buf(bufsize,'\0')); NEW(cList); /* empty header */ /* first try to connect to an existing server */ ERR_SI(mainFd=socket(AF_INET, SOCK_STREAM, 0)); i = 1; ERR_SI(setsockopt(mainFd,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(int))); /* allow quick port reuse */ ERR_I(CocCreateSockAdr(&sadr, NULL, port)); ERR_SI(bind(mainFd, (struct sockaddr *)&sadr, sizeof(sadr))); logfileOut(LOG_INFO, "created server on port %d\n", port); ERR_SI(listen(mainFd, 8)); FD_ZERO(&mask); FD_SET(mainFd, &mask); maxfd=mainFd+1; return(0); OnError: return(-1); } int CocHandle1Request(int tmo_msec, int fd) { struct sockaddr_in cadr; struct hostent *h; struct timeval tmo={0,1}; struct CocClient *cl, *cl0; int i, newfd, setmode; size_t cadrlen; char *err, *varname; rmask=mask; if (fd>0) FD_SET(fd, &rmask); tmo.tv_sec=tmo_msec / 1000; tmo.tv_usec=(tmo_msec % 1000)*1000+1; if (fd>=maxfd) maxfd=fd+1; ERR_SI(i=select(maxfd,&rmask,NULL,NULL,&tmo)); if (fd>0 && FD_ISSET(fd, &rmask)) return(1); /* event on fd */ if (i==0) return(0); /* timeout */ if (FD_ISSET(mainFd, &rmask)) { ERR_SI(newfd=accept(mainFd, (struct sockaddr *)&cadr, &cadrlen)); FD_SET(newfd, &mask); if (newfd>=maxfd) maxfd=newfd+1; cl=cList; cl->fd=newfd; cl->mode=0; cl->cmd[0]='\0'; cl->res[0]='\0'; NEW(cList); cList->next=cl; h=gethostbyaddr(&cadr.sin_addr, 4, AF_INET); if (h==NULL) { logfileOut(LOG_INFO, "(%d) open from %s\n", newfd, "local"); } else { logfileOut(LOG_INFO, "(%d) open from %s\n", newfd, h->h_name); } } else { cl0=cList; cl=cl0->next; while (cl!=NULL) { if (FD_ISSET(cl->fd, &rmask)) { buf->wrpos=recv(cl->fd, buf->buf, buf->dsize, 0); if (buf->wrpos<=0) { logfileOut(LOG_INFO, "(%d) disconnected\n",cl->fd); close(cl->fd); FD_CLR(cl->fd, &mask); cl0->next=cl->next; FREE(cl); cl=cl0; } else { str_put_start(bufo); str_get_start(buf); ERR_I(str_put_str(bufo, "")); /* empty error message */ setmode=0; err=NULL; ERR_P(varname=str_get_str(buf, NULL)); logfileOut(LOG_NET, "(%d) ", cl->fd); if (varname[0]=='#') { /* access code */ if (0==strcmp(varname,"#rdacc")) { logfileOut(LOG_INFO, "set read mode\n"); cl->mode=1; } else if (0==strcmp(varname,"#rwacs")) { logfileOut(LOG_INFO, "set write mode\n"); cl->mode=2; } else { err="bad access code"; } } else if (cl->mode==0) { err="no access"; } else { while (1) { if (varname[0]=='[') { if (cl->mode<2) { err="no write access"; break; } setmode=1; /* switch to set mode */ } else if (varname[0]==']') { /* switch to read mode */ setmode=0; } else if (setmode) { if (0==strcmp("$", varname)) { /* special case: command */ ERR_P(str_get_str(buf, cl->cmd)); cl->res[0]='\0'; } else { i=CocGetVar(serverVarList, buf, varname, 1); if (i<0) { err=ErrMessage; break; } } modified=1; } else { if (0==strcmp("$", varname)) { /* special case: response */ ERR_I(str_put_str(bufo, cl->res)); cl->res[0]='\0'; } else { i=CocPutVar(serverVarList, bufo, varname, 0); if (i<0) { err=ErrMessage; break; } } } if (buf->rdpos>=buf->wrpos) { ERR_I(str_get_end(buf)); break; } ERR_P(varname=str_get_str(buf, NULL)); } str_get_start(buf); logfileOutBuf(LOG_NET, buf); str_get_start(bufo); logfileOut(LOG_NET, " |"); logfileOutBuf(LOG_NET, bufo); } if (err==NULL) { logfileOut(LOG_NET, "\n"); } else { str_put_start(bufo); /* reset output */ str_put_str(bufo, err); /* put error message */ logfileOut(LOG_NET, " (%s)\n", err); /* logfileMask(LOG_NET); */ } ERR_SI(send(cl->fd, bufo->buf, bufo->wrpos, 0)); } } cl0=cl; cl=cl->next; } } if (modified) return(2); return(3); OnError: return(-1); } int CocHandleRequests(int tmo_msec, int fd) { struct timeb tim1, tim0; int tdif, iret; if (modified && fd==0) { /* earlier modification */ modified=0; return(2); } ftime(&tim0); tdif=tmo_msec; while (tdif>=0) { ERR_I(iret=CocHandle1Request(tdif, fd)); if (fd==0) { if (iret==2) return(2); /* modification of a varaible */ } else { if (iret==1) return(1); /* event on fd */ } if (iret==0) return(0); /* timeout */ ftime(&tim1); tdif=tmo_msec-((tim1.time-tim0.time)*1000+tim1.millitm-tim0.millitm); } return(0); /* timeout */ OnError: return(-1); } struct CocClient *CocGetNextCmd() { struct CocClient *cl; cl=cLastCmd; while (cl!=NULL) { if (cl->cmd[0]!='\0') { cLastCmd=cl->next; return(cl); } cl=cl->next; } cl=cList->next; while (cl!=NULL && cl!=cLastCmd) { if (cl->cmd[0]!='\0') { cLastCmd=cl->next; return(cl); } cl=cl->next; } return(NULL); } void CocCloseServer() { struct CocClient *cl, *cl0; cl=cList->next; while (cl!=NULL) { close(cl->fd); cl0=cl; cl=cl->next; FREE(cl0); } FREE(cList); close(mainFd); str_free_buf(buf); str_free_buf(bufo); logfileClose(); }