//------------------------------------------------------------------------- // Webserver-Thread for each connection //------------------------------------------------------------------------- void *WebThread(void *args) { TWebserverConnectionArgs *newConn = (TWebserverConnectionArgs *) args; if (!newConn) { dperror("WebThread called without arguments!\n"); return NULL; } bool is_threaded = newConn->is_treaded; if (is_threaded) log_level_printf(1, "++ Thread 0x06%X gestartet\n", (int) pthread_self()); // (1) create & init Connection CWebserver *ws = newConn->WebserverBackref; if (!ws) { dperror("WebThread CWebserver error!\n"); return NULL; } CWebserverConnection *con = new CWebserverConnection(ws); if (!con) { dperror("WebThread CWebserverConnection error!\n"); return NULL; } con->Request.UrlData["clientaddr"] = newConn->ySock->get_client_ip(); // TODO:here? con->sock = newConn->ySock; // give socket reference newConn->ySock->handling = true; // dont handle this socket now be webserver main loop // (2) handle the connection con->HandleConnection(); // (3) end connection handling #ifdef Y_CONFIG_FEATURE_KEEP_ALIVE if(!con->keep_alive) log_level_printf(2,"FD SHOULD CLOSE sock:%d!!!\n",con->sock->get_socket()); else ws->addSocketToMasterSet(con->sock->get_socket()); // add to master set #endif if (!con->keep_alive) con->sock->isValid = false; con->sock->handling = false; // socket can be handled by webserver main loop (select) again #ifndef Y_CONFIG_FEATURE_KEEP_ALIVE delete newConn->ySock; newConn->ySock = NULL; #endif // (4) end thread delete con; int thread_number = newConn->thread_number; delete newConn; if (is_threaded) { log_level_printf(1, "-- Thread 0x06%X beendet\n", (int) pthread_self()); ws->clear_Thread_List_Number(thread_number); pthread_exit( NULL); } return NULL; }
//----------------------------------------------------------------------------- // A new Connection is established to newSock. Create a (threaded) Connection // and handle the Request. //----------------------------------------------------------------------------- bool CWebserver::handle_connection(CySocket *newSock) { void *WebThread(void *args); //forward declaration // create arguments TWebserverConnectionArgs *newConn = new TWebserverConnectionArgs; if (!newConn) { dperror("CWebserver TWebserverConnectionArgs error!\n"); return false; } newConn->ySock = newSock; newConn->ySock->handling = true; newConn->WebserverBackref = this; #ifdef Y_CONFIG_FEATURE_THREADING newConn->is_treaded = is_threading; #else newConn->is_treaded = false; #endif int index = -1; #ifdef Y_CONFIG_FEATURE_THREADING if(is_threading) { pthread_mutex_lock( &mutex ); // look for free Thread slot for(int i=0;i<HTTPD_MAX_CONNECTIONS;i++) if(Connection_Thread_List[i] == (pthread_t)NULL) { index = i; break; } if(index == -1) { dperror("Maximum Connection-Threads reached\n"); pthread_mutex_unlock( &mutex ); return false; } newConn->thread_number = index; //remember Index of Thread slot (for clean up) // Create an orphan Thread. It is not joinable anymore pthread_mutex_unlock( &mutex ); // start connection Thread if(pthread_create(&Connection_Thread_List[index], &attr, WebThread, (void *)newConn) != 0) dperror("Could not create Connection-Thread\n"); } else // non threaded #endif WebThread((void *) newConn); return ((index != -1) || !is_threading); }
//------------------------------------------------------------------------- int CWebserverRequest::OpenFile(string path, string filename) { struct stat statbuf; //tmpint als file und //tmpstring als pathfilename missbraucht tmpint = -1; if(path[path.length()-1] != '/') tmpstring = path + "/" + filename; else tmpstring = path + filename; if(tmpstring.length() > 0) { tmpint = open( tmpstring.c_str(), O_RDONLY ); if (tmpint<=0) { aprintf("cannot open file %s\n", tmpstring.c_str()); dperror(""); } fstat(tmpint,&statbuf); if (!S_ISREG(statbuf.st_mode)) { close(tmpint); tmpint = -1; } } return tmpint; }
//----------------------------------------------------------------------------- // Set Re-Use Option for Address. //----------------------------------------------------------------------------- void CySocket::set_reuse_addr() { #ifdef SO_REUSEADDR if(!set_option(SOL_SOCKET, SO_REUSEADDR)) dperror("setsockopt(SO_REUSEADDR)\n"); #endif }
//----------------------------------------------------------------------------- // Set Re-Use Option for Port. //----------------------------------------------------------------------------- void CySocket::set_reuse_port() { #ifdef SO_REUSEPORT if(!set_option(SOL_SOCKET, SO_REUSEPORT)) dperror("setsockopt(SO_REUSEPORT)\n"); #endif }
//----------------------------------------------------------------------------- // Set Keep-Alive Option for Socket. //----------------------------------------------------------------------------- void CySocket::set_keep_alive() { #ifdef SO_KEEPALIVE if(!set_option(SOL_SOCKET, SO_KEEPALIVE)) dperror("setsockopt(SO_KEEPALIVE)\n"); #endif }
//----------------------------------------------------------------------------- // Set Keep-Alive Option for Socket. //----------------------------------------------------------------------------- void CySocket::set_tcp_nodelay() { #ifdef TCP_NODELAY if(!set_option(IPPROTO_TCP, TCP_NODELAY)) dperror("setsockopt(SO_KEEPALIVE)\n"); #endif }
//============================================================================= // SocketList Handler //============================================================================= //----------------------------------------------------------------------------- // Accept new Connection //----------------------------------------------------------------------------- int CWebserver::AcceptNewConnectionSocket() { int slot = -1; CySocket *connectionSock = NULL; if (!(connectionSock = listenSocket.accept())) // Blocking wait { dperror("Socket accept error. Continue.\n"); delete connectionSock; return -1; } #ifdef Y_CONFIG_USE_OPEN_SSL if(Cyhttpd::ConfigList["SSL"]=="true") connectionSock->initAsSSL(); // make it a SSL-socket #endif log_level_printf(2, "FD: new con fd:%d on port:%d\n", connectionSock->get_socket(), connectionSock->get_accept_port()); // Add Socket to List slot = SL_GetFreeSlot(); if (slot < 0) { connectionSock->close(); aprintf("No free Slot in SocketList found. Open:%d\n", open_connections); } else { SocketList[slot] = connectionSock; // put it to list fcntl(connectionSock->get_socket(), F_SETFD, O_NONBLOCK); // set non-blocking open_connections++; // count open connectins int newfd = connectionSock->get_socket(); if (newfd > fdmax) // keep track of the maximum fd fdmax = newfd; } return slot; }
// Frees memory allocated with ecg_alloc_buf int ecg_free_buf(uint8_t *buffer, size_t size) { #ifdef _MSC_VER if (HeapFree(ecg_hheap, 0, buffer) == 0) return -1; #endif #ifdef _POSIX_SOURCE if (munmap(buffer, size) != 0) { dperror("munmap"); return -1; } #endif return 0; }
//----------------------------------------------------------------------------- // Send File: Open File and check file type //----------------------------------------------------------------------------- int CmodSendfile::OpenFile(CyhookHandler */*hh*/, std::string fullfilename) { int fd= -1; std::string tmpstring; if (!fullfilename.empty()) { fd = open( fullfilename.c_str(), O_RDONLY ); if (fd<=0) { aprintf("cannot open file %s: ", fullfilename.c_str()); dperror(""); } } return fd; }
bool save_preferences (void) { FILE* fs; dmsg (D_MISC, "save preferences to %s", preferences_file ()); fs = fopen (preferences_file (), "wt"); if (fs == 0) { wmsg ("cannot save preferences to %s", preferences_file ()); dperror ("fopen"); return true; } output_preferences (fs); fclose (fs); return false; }
static int getcurtime (struct timeval *tvp) { #ifdef _WIN32 struct _timeb tb; _ftime(&tb); tvp->tv_sec = tb.time; tvp->tv_usec = tb.millitm * 1000; /* Can _ftime fail? */ return 0; #else if (gettimeofday(tvp, 0)) { dperror("gettimeofday"); return errno; } return 0; #endif }
/* Return 0 if we sent something, non-0 otherwise. If 0 is returned, the caller should delay waiting for a response. Otherwise, the caller should immediately move on to process the next connection. */ static int maybe_send(krb5_context context, struct conn_state *conn, struct select_state *selstate, struct sendto_callback_info *callback_info) { sg_buf *sg; ssize_t ret; dprint("maybe_send(@%p) state=%s type=%s\n", conn, state_strings[conn->state], conn->is_udp ? "udp" : "tcp"); if (conn->state == INITIALIZING) return start_connection(context, conn, selstate, callback_info); /* Did we already shut down this channel? */ if (conn->state == FAILED) { dprint("connection already closed\n"); return -1; } if (conn->socktype == SOCK_STREAM) { dprint("skipping stream socket\n"); /* The select callback will handle flushing any data we haven't written yet, and we only write it once. */ return -1; } /* UDP - retransmit after a previous attempt timed out. */ sg = &conn->x.out.sgbuf[0]; TRACE_SENDTO_KDC_UDP_SEND_RETRY(context, conn); dprint("sending %d bytes on fd %d\n", SG_LEN(sg), conn->fd); ret = send(conn->fd, SG_BUF(sg), SG_LEN(sg), 0); if (ret < 0 || (size_t) ret != SG_LEN(sg)) { TRACE_SENDTO_KDC_UDP_ERROR_SEND_RETRY(context, conn, SOCKET_ERRNO); dperror("send"); /* Keep connection alive, we'll try again next pass. Is this likely to catch any errors we didn't get from the select callbacks? */ return -1; } /* Yay, it worked. */ return 0; }
static void read_level_dir (const char *dirname) { DIR *dir; struct dirent* de; int n = 0; dmsg (D_FILE | D_SECTION, "reading level list from %s", dirname); dir = opendir (dirname); if (!dir) { dperror ("opendir"); emsg (_("cannot open directory %s"), dirname); } while ((de = readdir (dir))) if (select_file_lvl (de)) { char *filename; a_level tmp_lvl; if (level_list_size >= level_list_max) { level_list_max += 32; XREALLOC_ARRAY (level_list, level_list_max); } filename = xmalloc (strlen (dirname) + 1 + strlen (de->d_name) + 1); sprintf (filename, "%s/%s", dirname, de->d_name); level_list[level_list_size].name = filename; dmsg (D_FILE, "loading header from %s", filename); lvl_load_file (filename, &tmp_lvl, false); level_list[level_list_size].wrapped = (tmp_lvl.tile_width_wrap != DONT_WRAP && tmp_lvl.tile_height_wrap != DONT_WRAP); lvl_free (&tmp_lvl); ++level_list_size; } closedir (dir); dmsg (D_FILE, "... %d files", n); }
//----------------------------------------------------------------------------- CySocket* CySocket::accept() { init(); SOCKET newSock = ::accept(sock, (sockaddr *) &addr, &addr_len); if (newSock == INVALID_SOCKET) { dperror("accept: invalid socket\n"); return NULL; } CySocket *new_ySocket = new CySocket(newSock); if (new_ySocket != NULL) { new_ySocket->setAddr(addr); #ifdef TCP_CORK new_ySocket->set_option(IPPROTO_TCP, TCP_CORK); #else set_tcp_nodelay(); #endif } new_ySocket->isOpened = true; // handling = true; return new_ySocket; }
// Allocates an executable buffer on the heap. size_t ecg_alloc_buf(uint8_t **buffer, size_t size) { #ifdef _MSC_VER *buffer = (uint8_t*) HeapAlloc(ecg_hheap, 0, size); #endif #ifdef _POSIX_SOURCE int prot = PROT_READ | PROT_WRITE | PROT_EXEC; int flags = MAP_SHARED; // Allocate full pages only since we're going // to allocate pages at page boundaries anyways. size = (size + ecg_page_size) & ~(ecg_page_size - 1); *buffer = (uint8_t*) mmap(NULL, size, prot, flags, ecg_zero_page, 0); if (*buffer == MAP_FAILED) { dperror("mmap"); return 0; } #endif return size; }
int CWebserverRequest::OpenFile(std::string path, std::string filename) { struct stat statbuf; int fd= -1; tmpstring = GetFileName(path, filename); if(tmpstring.length() > 0) { fd = open( tmpstring.c_str(), O_RDONLY ); if (fd<=0) { aprintf("cannot open file %s: ", filename.c_str()); dperror(""); } fstat(fd,&statbuf); if (!S_ISREG(statbuf.st_mode)) { close(fd); fd = -1; } } return fd; }
static int start_connection(krb5_context context, struct conn_state *state, struct select_state *selstate, struct sendto_callback_info *callback_info) { int fd, e; dprint("start_connection(@%p)\ngetting %s socket in family %d...", state, state->socktype == SOCK_STREAM ? "stream" : "dgram", state->family); fd = socket(state->family, state->socktype, 0); if (fd == INVALID_SOCKET) { state->err = SOCKET_ERRNO; dprint("socket: %m creating with af %d\n", state->err, state->family); return -1; /* try other hosts */ } #ifndef _WIN32 /* On Windows FD_SETSIZE is a count, not a max value. */ if (fd >= FD_SETSIZE) { closesocket(fd); state->err = EMFILE; dprint("socket: fd %d too high\n", fd); return -1; } #endif set_cloexec_fd(fd); /* Make it non-blocking. */ if (state->socktype == SOCK_STREAM) { static const int one = 1; static const struct linger lopt = { 0, 0 }; if (ioctlsocket(fd, FIONBIO, (const void *) &one)) dperror("sendto_kdc: ioctl(FIONBIO)"); if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &lopt, sizeof(lopt))) dperror("sendto_kdc: setsockopt(SO_LINGER)"); TRACE_SENDTO_KDC_TCP_CONNECT(context, state); } /* Start connecting to KDC. */ e = connect(fd, (struct sockaddr *)&state->addr, state->addrlen); if (e != 0) { /* * This is the path that should be followed for non-blocking * connections. */ if (SOCKET_ERRNO == EINPROGRESS || SOCKET_ERRNO == EWOULDBLOCK) { state->state = CONNECTING; state->fd = fd; } else { dprint("connect failed: %m\n", SOCKET_ERRNO); (void) closesocket(fd); state->err = SOCKET_ERRNO; state->state = FAILED; return -2; } } else { /* * Connect returned zero even though we made it non-blocking. This * happens normally for UDP sockets, and can perhaps also happen for * TCP sockets connecting to localhost. */ state->state = WRITING; state->fd = fd; } dprint("new state = %s\n", state_strings[state->state]); /* * Here's where KPASSWD callback gets the socket information it needs for * a kpasswd request */ if (callback_info) { e = callback_info->pfn_callback(state, callback_info->context, &state->callback_buffer); if (e != 0) { dprint("callback failed: %m\n", e); (void) closesocket(fd); state->err = e; state->fd = INVALID_SOCKET; state->state = FAILED; return -3; } set_conn_state_msg_length(state, &state->callback_buffer); } if (state->socktype == SOCK_DGRAM) { /* Send it now. */ ssize_t ret; sg_buf *sg = &state->x.out.sgbuf[0]; TRACE_SENDTO_KDC_UDP_SEND_INITIAL(context, state); dprint("sending %d bytes on fd %d\n", SG_LEN(sg), state->fd); ret = send(state->fd, SG_BUF(sg), SG_LEN(sg), 0); if (ret < 0 || (size_t) ret != SG_LEN(sg)) { TRACE_SENDTO_KDC_UDP_ERROR_SEND_INITIAL(context, state, SOCKET_ERRNO); dperror("sendto"); (void) closesocket(state->fd); state->fd = INVALID_SOCKET; state->state = FAILED; return -4; } else { state->state = READING; } } FD_SET(state->fd, &selstate->rfds); if (state->state == CONNECTING || state->state == WRITING) FD_SET(state->fd, &selstate->wfds); FD_SET(state->fd, &selstate->xfds); if (selstate->max <= state->fd) selstate->max = state->fd + 1; selstate->nfds++; dprint("new select vectors: %F\n", &selstate->rfds, &selstate->wfds, &selstate->xfds, selstate->max); return 0; }
//----------------------------------------------------------------------------- // POST multipart ! FILE UPLOAD! // // No 'Content-type: multipart/mixed' now supported // designed for recursion for different boundaries. // // from RFC 1867: // 2. HTML forms with file submission // // The current HTML specification defines eight possible values for the // attribute TYPE of an INPUT element: CHECKBOX, HIDDEN, IMAGE, // PASSWORD, RADIO, RESET, SUBMIT, TEXT. // // In addition, it defines the default ENCTYPE attribute of the FORM // element using the POST METHOD to have the default value // "application/x-www-form-urlencoded" // // 6. Examples // // Suppose the server supplies the following HTML: // // <FORM ACTION="http://server.dom/cgi/handle" // ENCTYPE="multipart/form-data" // METHOD=POST> // What is your name? <INPUT TYPE=TEXT NAME=submitter> // What files are you sending? <INPUT TYPE=FILE NAME=pics> // </FORM> // // and the user types "Joe Blow" in the name field, and selects a text // file "file1.txt" for the answer to 'What files are you sending?' // // The client might send back the following data: // // Content-type: multipart/form-data, boundary=AaB03x // // --AaB03x // content-disposition: form-data; name="field1" // // Joe Blow // --AaB03x // content-disposition: form-data; name="pics"; filename="file1.txt" // Content-Type: text/plain // // ... contents of file1.txt ... // --AaB03x-- // // 7. Registration of multipart/form-data // // The media-type multipart/form-data follows the rules of all multipart // MIME data streams as outlined in RFC 1521. It is intended for use in // returning the data that comes about from filling out a form. In a // form (in HTML, although other applications may also use forms), there // are a series of fields to be supplied by the user who fills out the // form. Each field has a name. Within a given form, the names are // unique. // // multipart/form-data contains a series of parts. Each part is expected // to contain a content-disposition header where the value is "form- // data" and a name attribute specifies the field name within the form, // e.g., 'content-disposition: form-data; name="xxxxx"', where xxxxx is // the field name corresponding to that field. Field names originally in // non-ASCII character sets may be encoded using the method outlined in // RFC 1522. // // As with all multipart MIME types, each part has an optional Content- // Type which defaults to text/plain. If the contents of a file are // returned via filling out a form, then the file input is identified as // application/octet-stream or the appropriate media type, if known. If // multiple files are to be returned as the result of a single form // entry, they can be returned as multipart/mixed embedded within the // multipart/form-data. // // Each part may be encoded and the "content-transfer-encoding" header // supplied if the value of that part does not conform to the default // encoding. // // File inputs may also identify the file name. The file name may be // described using the 'filename' parameter of the "content-disposition" // header. This is not required, but is strongly recommended in any case // where the original filename is known. This is useful or necessary in // many applications. //----------------------------------------------------------------------------- unsigned int CWebserverRequest::HandlePostBoundary(std::string boundary, unsigned int content_len) { std::string tmp_line; // read boundary tmp_line = Connection->sock->ReceiveLine(); content_len -= tmp_line.length(); log_level_printf(2,"<POST Boundary> Start\n"); if(tmp_line.find(boundary) != std::string::npos) { // is it the boudary end? if(tmp_line.find(boundary+"--") != std::string::npos) { log_level_printf(7,"<POST Boundary> Boundary END found\n"); return 0; } log_level_printf(7,"<POST Boundary> Boundary START found\n"); // read content-disposition: ... tmp_line = Connection->sock->ReceiveLine(); content_len -= tmp_line.length(); if(tmp_line.find("Content-Disposition:") == std::string::npos) { log_level_printf(7,"<POST Boundary> no content-disposition found. line:(%s)\n", tmp_line.c_str()); return 0; } if(tmp_line.find("filename") != std::string::npos) { #ifdef Y_CONFIG_FEATURE_UPLOAD // this part is a file log_level_printf(2,"<POST Boundary> disposition !!this is a file!! found. line:(%s)\n", tmp_line.c_str()); // get para from 'content-disposition: form-data; name="pics"; filename="file1.txt"' // set to ParameterList["<name>"]="<filename>" std::string left, right, var_name, var_value; if(!ySplitStringExact(tmp_line, "name=\"", left, right)) { log_level_printf(7,"<POST Boundary> no var_name START found. line:(%s)\n", tmp_line.c_str()); return 0; } if(!ySplitStringExact(right, "\"", var_name, right)) { log_level_printf(7,"<POST Boundary> no var_name END found. line:(%s)\n", tmp_line.c_str()); return 0; } if(!ySplitStringExact(right, "filename=\"", left, right)) { log_level_printf(7,"<POST Boundary> no filename START found. line:(%s)\n", tmp_line.c_str()); return 0; } if(!ySplitStringExact(right, "\"", var_value, right)) { log_level_printf(7,"<POST Boundary> no filename END found. line:(%s)\n", tmp_line.c_str()); return 0; } var_value = trim(var_value); ParameterList[var_name] = var_value; log_level_printf(7,"<POST Boundary> filename found. name:(%s) value:(%s)\n", var_name.c_str(), var_value.c_str()); //read 'Content-Type: <mime>' tmp_line = Connection->sock->ReceiveLine(); content_len -= tmp_line.length(); // Get Content-Type: put it to ParameterList["<name>_mime"]="<mime>" if(!ySplitStringExact(tmp_line, "Content-Type:", left, right)) { log_level_printf(7,"<POST Boundary> no Content-Type found. line:(%s)\n", tmp_line.c_str()); return 0; } var_value = trim(right); ParameterList[var_name+"_mime"] = var_value; log_level_printf(7,"<POST Boundary> Content-Type found. name:(%s_mime) value:(%s)\n", var_name.c_str(), var_value.c_str()); //read empty line as separator tmp_line = Connection->sock->ReceiveLine(); content_len -= tmp_line.length(); if(tmp_line != "\r\n") { log_level_printf(7,"<POST Boundary> no empty line found. line:(%s)\n", tmp_line.c_str()); return 0; } log_level_printf(7,"<POST Boundary> read file Start\n"); std::string upload_filename; upload_filename = UPLOAD_TMP_FILE; // Hook for Filename naming Connection->HookHandler.Hooks_UploadSetFilename(upload_filename); // Set upload filename to ParameterList["<name>_upload_filename"]="<upload_filename>" ParameterList[var_name+"_upload_filename"] = upload_filename; // open file for write int fd = open(upload_filename.c_str(), O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR); if (fd<=0) { aprintf("cannot open file %s: ", upload_filename.c_str()); dperror(""); return 0; } // ASSUMPTION: the complete multipart has no more then SEARCH_BOUNDARY_LEN bytes after the file. // It only works, if no multipart/mixed is used (e.g. in file attachments). Not nessesary in embedded systems. // To speed up uploading, read content_len - SEARCH_BOUNDARY_LEN bytes in blockmode. // To save memory, write them direct into the file. #define SEARCH_BOUNDARY_LEN 2*RECEIVE_BLOCK_LEN // >= RECEIVE_BLOCK_LEN in ySocket unsigned int _readbytes = 0; if((int)content_len - SEARCH_BOUNDARY_LEN >0) { _readbytes = Connection->sock->ReceiveFileGivenLength(fd, content_len - SEARCH_BOUNDARY_LEN); content_len -= _readbytes; log_level_printf(8,"<POST Boundary> read block (already:%d all:%d)\n", _readbytes, content_len); } // read rest of file and check for boundary end _readbytes = 0; bool is_CRLF = false; bool found_end_boundary = false; do { // read line by line tmp_line = Connection->sock->ReceiveLine(); _readbytes += tmp_line.length(); // is this line a boundary? if(tmp_line.find(boundary) != std::string::npos) { if(tmp_line.find(boundary+"--") != std::string::npos) found_end_boundary = true; // it is the end! of POST request! break; // boundary found. end of file. } else // no Boundary: write CRFL if found in last line { if(is_CRLF) if ((unsigned int)write(fd, "\r\n", 2) != 2) { perror("write file failed\n"); return 0; } } // normal line: write it to file // CRLF at end? Maybe CRLF before boundary. Can not decide yet is_CRLF = (tmp_line.length()>=2 && tmp_line[tmp_line.length()-2]=='\r' && tmp_line[tmp_line.length()-1]=='\n'); int write_len = is_CRLF ? tmp_line.length()-2 : tmp_line.length(); if (write(fd, tmp_line.c_str(), write_len) != write_len) { perror("write file failed\n"); return 0; } log_level_printf(2,"<POST Boundary> read file (already:%d all:%d)\n", _readbytes, content_len); } while((_readbytes < content_len) && (tmp_line.length() != 0)); content_len -= _readbytes; close(fd); log_level_printf(2,"<POST Boundary> read file End\n"); if(found_end_boundary) // upload ok? { Connection->HookHandler.Hooks_UploadReady(upload_filename); return 0; } #endif // Y_CONFIG_FEATURE_UPLOAD } else // this part is a POST variable/parameter { // get var_name from 'content-disposition: form-data; name="var_name"' std::string left, right, var_name, var_value; if(!ySplitStringExact(tmp_line, "name=\"", left, right)) { log_level_printf(7,"<POST Boundary> no var_name START found. line:(%s)\n", tmp_line.c_str()); return 0; } if(!ySplitStringExact(right, "\"", var_name, right)) { log_level_printf(7,"<POST Boundary> no var_name END found. line:(%s)\n", tmp_line.c_str()); return 0; } //read empty line as separator tmp_line = Connection->sock->ReceiveLine(); content_len -= tmp_line.length(); if(tmp_line != "\r\n") { log_level_printf(7,"<POST Boundary> no empty line found. line:(%s)\n", tmp_line.c_str()); return 0; } //read var_value line // ASSUMPTION!!!! Only one Line for value, new line is a boundary again // ATTENTION!! var_name must not be unique. So Parameters are store by number too. var_value = Connection->sock->ReceiveLine(); content_len -= tmp_line.length(); var_value = trim(decodeString(var_value)); ParameterList[var_name] = var_value; log_level_printf(7,"<POST Boundary> Parameter found. name:(%s) value:(%s)\n", var_name.c_str(), var_value.c_str()); } } return content_len; }
bool load_preferences (void) { FILE* fs; int endline = 0; char* buf = 0; size_t bufsize = 0; firstline = 0; reinit_preferences (); dmsg (D_FILE, "reading option from %s", preferences_file ()); fs = fopen (preferences_file (), "rb"); if (fs == NULL) { /* Don't warn, the file doesn't exists the first time. */ dmsg (D_FILE, "cannot open preferences file %s", preferences_file ()); dperror ("fopen"); return true; } XFREE0 (ignored_lines); while (getshline_numbered (&firstline, &endline, &buf, &bufsize, fs) != -1) { char* token; char* line = xstrdup (buf); token = strtok (buf, " \t.:"); if (!strcasecmp ("heroes", token)) { token = strtok (0, " \t.:"); if (!strcasecmp ("screen", token)) { token = strtok (0, " \t.:"); if (!strcasecmp ("display_radar", token)) { token = strtok (0, "\n"); opt.radar_map = parse_bool (token, false, true); } else if (!strcasecmp ("display_infos", token)) { token = strtok (0, "\n"); opt.display_infos = parse_bool (token, false, true); } else if (!strcasecmp ("gamma", token)) { token = strtok (0, "\n"); opt.luminance = parse_unsigned (token, 0, 12); } else if (!strcasecmp ("inertia", token)) { token = strtok (0, "\n"); opt.inertia = parse_bool (token, false, true); } else { append_ignored (line); } } else if (!strcasecmp ("sound", token)) { token = strtok (0, " \t.:"); if (!strcasecmp ("music_enable", token)) { token = strtok (0, "\n"); opt.music = parse_bool (token, false, true); } else if (!strcasecmp ("music_volume", token)) { token = strtok (0, "\n"); opt.music_volume = parse_unsigned (token, 0, 12); } else if (!strcasecmp ("sfx_enable", token)) { token = strtok (0, "\n"); opt.sfx = parse_bool (token, false, true); } else if (!strcasecmp ("sfx_volume", token)) { token = strtok (0, "\n"); opt.sfx_volume = parse_unsigned (token, 0, 12); } else { append_ignored (line); } } else if (!strcasecmp ("control", token)) { token = strtok (0, " \t.:"); if (!strcasecmp ("player1", token)) { token = strtok (0, "\n"); opt.ctrl_one = parse_unsigned (token, 0, 1); } else if (!strcasecmp ("autopilot1", token)) { token = strtok (0, "\n"); opt.autopilot_one = parse_bool (token, false, true); } else if (!strcasecmp ("player2", token)) { token = strtok (0, "\n"); opt.ctrl_two = parse_unsigned (token, 0, 1); } else if (!strcasecmp ("autopilot2", token)) { token = strtok (0, "\n"); opt.autopilot_two = parse_bool (token, false, true); } else { append_ignored (line); } } else if (!strcasecmp ("game", token)) { token = strtok (0, " \t.:"); if (!strcasecmp ("speed", token)) { token = strtok (0, "\n"); opt.speed = parse_unsigned (token, 0, 2); } else if (!strcasecmp ("gamerounds", token)) { token = strtok (0, "\n"); opt.gamerounds = parse_unsigned (token, 0, 15); } else if (!strcasecmp ("player_colors", token)) { token = strtok (0, " \t"); opt.player_color[0] = parse_unsigned (token, 0, 4); token = strtok (0, " \t"); opt.player_color[1] = parse_unsigned (token, 0, 4); token = strtok (0, " \t"); opt.player_color[2] = parse_unsigned (token, 0, 4); token = strtok (0, " \t"); opt.player_color[3] = parse_unsigned (token, 0, 4); } else { append_ignored (line); } } else if (!strcasecmp ("extras", token)) { token = strtok (0, " \t.:"); if (!strcasecmp ("mode", token)) { token = strtok (0, "\n"); opt.extras = parse_unsigned (token, 0, 2); } else { append_ignored (line); } } else if (!strcasecmp (keys_pref_group (), token)) { token = strtok (0, " \t.:"); if (!strcasecmp ("player1_keys", token)) { token = strtok (0, " \t"); opt.player_keys[0][0] = parse_unsigned (token, 0, HKEYCODE_MAX); token = strtok (0, " \t"); opt.player_keys[0][1] = parse_unsigned (token, 0, HKEYCODE_MAX); token = strtok (0, " \t"); opt.player_keys[0][2] = parse_unsigned (token, 0, HKEYCODE_MAX); token = strtok (0, " \t"); opt.player_keys[0][3] = parse_unsigned (token, 0, HKEYCODE_MAX); token = strtok (0, " \t"); opt.player_keys[0][4] = parse_unsigned (token, 0, HKEYCODE_MAX); token = strtok (0, " \t"); opt.player_keys[0][5] = parse_unsigned (token, 0, HKEYCODE_MAX); } else if (!strcasecmp ("player2_keys", token)) { token = strtok (0, " \t"); opt.player_keys[1][0] = parse_unsigned (token, 0, HKEYCODE_MAX); token = strtok (0, " \t"); opt.player_keys[1][1] = parse_unsigned (token, 0, HKEYCODE_MAX); token = strtok (0, " \t"); opt.player_keys[1][2] = parse_unsigned (token, 0, HKEYCODE_MAX); token = strtok (0, " \t"); opt.player_keys[1][3] = parse_unsigned (token, 0, HKEYCODE_MAX); token = strtok (0, " \t"); opt.player_keys[1][4] = parse_unsigned (token, 0, HKEYCODE_MAX); token = strtok (0, " \t"); opt.player_keys[1][5] = parse_unsigned (token, 0, HKEYCODE_MAX); } else { append_ignored (line); } } else { append_ignored (line); } } else { append_ignored (line); } free (line); } free (buf); fclose (fs); return false; }
int main(int argc, char **argv) { aprintf("Webserver %s\n", WEBSERVERNAME); bool do_fork = true; yhttpd = new Cyhttpd(); if(!yhttpd) { aprintf("Error initializing WebServer\n"); return EXIT_FAILURE; } for (int i = 1; i < argc; i++) { if ((!strncmp(argv[i], "-d", 2)) || (!strncmp(argv[i], "--debug", 7))) { CLogging::getInstance()->setDebug(true); do_fork = false; } else if ((!strncmp(argv[i], "-f", 2)) || (!strncmp(argv[i], "--fork", 6))) { do_fork = false; } else if ((!strncmp(argv[i], "-h", 2)) || (!strncmp(argv[i], "--help", 6))) { yhttpd->usage(stdout); return EXIT_SUCCESS; } else if ((!strncmp(argv[i], "-v", 2)) || (!strncmp(argv[i],"--version", 9))) { yhttpd->version(stdout); return EXIT_SUCCESS; } else if ((!strncmp(argv[i], "-t", 2)) || (!strncmp(argv[i],"--thread-off", 12))) { yhttpd->flag_threading_off = true; } else if ((!strncmp(argv[i], "-l", 2)) ) { if(argv[i][2] >= '0' && argv[i][2] <= '9') CLogging::getInstance()->LogLevel = (argv[i][2]-'0'); } else { yhttpd->usage(stderr); return EXIT_FAILURE; } } // setup signal catching (subscribing) signal(SIGPIPE, sig_catch); signal(SIGINT, sig_catch); signal(SIGHUP, sig_catch); signal(SIGUSR1, sig_catch); signal(SIGTERM, sig_catch); signal(SIGCLD, SIG_IGN); // signal(SIGALRM, sig_catch); yhttpd->hooks_attach(); yhttpd->ReadConfig(); if(yhttpd->Configure()) { // Start Webserver: fork ist if not in debug mode aprintf("Webserver starting...\n"); if (do_fork) { log_level_printf(9,"do fork\n"); switch (fork()) { case -1: dperror("fork"); return -1; case 0: break; default: return EXIT_SUCCESS; } if (setsid() == -1) { dperror("Error setsid"); return EXIT_FAILURE; } } dprintf("Start in Debug-Mode\n"); // non forked debugging loop yhttpd->run(); } delete yhttpd; aprintf("Main end\n"); return EXIT_SUCCESS; }
//----------------------------------------------------------------------------- // Change to Root //----------------------------------------------------------------------------- bool Cyhttpd::Configure() { if (!getuid()) // you must be root to do that! { // Get user and group data #ifdef Y_CONFIG_FEATURE_HTTPD_USER struct passwd *pwd = NULL; struct group *grp = NULL; std::string username = ConfigList["server.user_name"]; std::string groupname= ConfigList["server.group_name"]; // get user data if(!username.empty()) { if((pwd = getpwnam(username.c_str())) == NULL) { dperror("Dont know user to set uid\n"); return false; } } // get group data if(!groupname.empty()) { if((grp = getgrnam(groupname.c_str())) == NULL) { aprintf("Can not get Group-Information. Group: %s\n", groupname.c_str()); return false; } } #endif // change root directory #ifdef Y_CONFIG_FEATURE_CHROOT if(!ConfigList["server.chroot"].empty()) { log_level_printf(2, "do chroot to dir:%s\n", ConfigList["server.chroot"].c_str() ); // do change Root if(chroot(ConfigList["server.chroot"].c_str()) == -1) { dperror("Change Root failed\n"); return false; } // Set Working Dir if(chdir("/") == -1) { dperror("Change Directory to Root failed\n"); return false; } } #endif #ifdef Y_CONFIG_FEATURE_HTTPD_USER if(!username.empty() && pwd != NULL && grp != NULL) { log_level_printf(2, "set user and groups\n"); // drop root privileges setgid(grp->gr_gid); setgroups(0, NULL); // set user group if(!groupname.empty()) initgroups(username.c_str(), grp->gr_gid); // set user if(setuid(pwd->pw_uid) == -1) { dperror("Change User Context failed\n"); return false; } } #endif } return true; }
void parse_command(int connfd, CBasicMessage::Header * rmessage) { if(rmessage->version!=CTimerd::ACTVERSION) { dperror("command with unknown version\n"); return; } // CTimerEvent_NextProgram::EventMap::iterator it = NULL; CTimerEventMap events; CTimerd::commandModifyTimer msgModifyTimer; CTimerd::responseGetSleeptimer rspGetSleeptimer; CTimerEventMap::iterator pos; switch(rmessage->cmd) { case CTimerd::CMD_REGISTEREVENT : CTimerManager::getInstance()->getEventServer()->registerEvent( connfd ); break; case CTimerd::CMD_UNREGISTEREVENT : CTimerManager::getInstance()->getEventServer()->unRegisterEvent( connfd ); break; case CTimerd::CMD_GETSLEEPTIMER: rspGetSleeptimer.eventID = 0; if(CTimerManager::getInstance()->listEvents(events)) { if(events.size() > 0) { for(pos = events.begin();(pos != events.end());pos++) { printf("ID: %u type: %u\n",pos->second->eventID,pos->second->eventType); if(pos->second->eventType == CTimerd::TIMER_SLEEPTIMER) { rspGetSleeptimer.eventID = pos->second->eventID; break; } } } } write( connfd, &rspGetSleeptimer, sizeof(rspGetSleeptimer)); break; case CTimerd::CMD_GETTIMER: // timer daten abfragen CTimerd::commandGetTimer msgGetTimer; CTimerd::responseGetTimer resp; read(connfd,&msgGetTimer, sizeof(msgGetTimer)); if(CTimerManager::getInstance()->listEvents(events)) { if(events[msgGetTimer.eventID]) { CTimerEvent *event = events[msgGetTimer.eventID]; resp.eventID = event->eventID; resp.eventState = event->eventState; resp.eventType = event->eventType; resp.eventRepeat = event->eventRepeat; resp.announceTime = event->announceTime; resp.alarmTime = event->alarmTime; resp.stopTime = event->stopTime; if(event->eventType == CTimerd::TIMER_STANDBY) resp.standby_on = static_cast<CTimerEvent_Standby*>(event)->standby_on; else if(event->eventID == CTimerd::TIMER_NEXTPROGRAM) { resp.epgID = static_cast<CTimerEvent_NextProgram*>(event)->eventInfo.epgID; resp.channel_id = static_cast<CTimerEvent_NextProgram*>(event)->eventInfo.channel_id; } else if(event->eventID == CTimerd::TIMER_RECORD) { resp.epgID = static_cast<CTimerEvent_Record*>(event)->eventInfo.epgID; resp.channel_id = static_cast<CTimerEvent_Record*>(event)->eventInfo.channel_id; resp.apid = static_cast<CTimerEvent_Record*>(event)->eventInfo.apid; } else if(event->eventID == CTimerd::TIMER_ZAPTO) { resp.epgID = static_cast<CTimerEvent_Zapto*>(event)->eventInfo.epgID; resp.channel_id = static_cast<CTimerEvent_Zapto*>(event)->eventInfo.channel_id; } else if(event->eventID == CTimerd::TIMER_REMIND) { memset(resp.message, 0, sizeof(resp.message)); strncpy(resp.message, static_cast<CTimerEvent_Remind*>(event)->message, sizeof(resp.message)-1); } } } write( connfd, &resp, sizeof(CTimerd::responseGetTimer)); break; case CTimerd::CMD_GETTIMERLIST: // liste aller timer if(CTimerManager::getInstance()->listEvents(events)) { for(CTimerEventMap::iterator pos = events.begin();pos != events.end();pos++) { CTimerd::responseGetTimer resp; CTimerEvent *event = pos->second; resp.eventID = event->eventID; resp.eventState = event->eventState; resp.eventType = event->eventType; resp.eventRepeat = event->eventRepeat; resp.announceTime = event->announceTime; resp.alarmTime = event->alarmTime; resp.stopTime = event->stopTime; if(event->eventType == CTimerd::TIMER_STANDBY) resp.standby_on = static_cast<CTimerEvent_Standby*>(event)->standby_on; else if(event->eventType == CTimerd::TIMER_NEXTPROGRAM) { resp.epgID = static_cast<CTimerEvent_NextProgram*>(event)->eventInfo.epgID; resp.channel_id = static_cast<CTimerEvent_NextProgram*>(event)->eventInfo.channel_id; } else if(event->eventType == CTimerd::TIMER_RECORD) { resp.epgID = static_cast<CTimerEvent_Record*>(event)->eventInfo.epgID; resp.channel_id = static_cast<CTimerEvent_Record*>(event)->eventInfo.channel_id; resp.apid = static_cast<CTimerEvent_Record*>(event)->eventInfo.apid; } else if(event->eventType == CTimerd::TIMER_ZAPTO) { resp.epgID = static_cast<CTimerEvent_Zapto*>(event)->eventInfo.epgID; resp.channel_id = static_cast<CTimerEvent_Zapto*>(event)->eventInfo.channel_id; } else if(event->eventType == CTimerd::TIMER_REMIND) { strcpy(resp.message, static_cast<CTimerEvent_Remind*>(event)->message); } write( connfd, &resp, sizeof(CTimerd::responseGetTimer)); } } break; case CTimerd::CMD_RESCHEDULETIMER: // event nach vorne oder hinten schieben { read(connfd,&msgModifyTimer, sizeof(msgModifyTimer)); int ret=CTimerManager::getInstance()->rescheduleEvent(msgModifyTimer.eventID,msgModifyTimer.announceTime,msgModifyTimer.alarmTime, msgModifyTimer.stopTime); CTimerd::responseStatus rspStatus; rspStatus.status = (ret!=0); write( connfd, &rspStatus, sizeof(rspStatus)); break; } case CTimerd::CMD_MODIFYTIMER: // neue zeiten setzen { read(connfd,&msgModifyTimer, sizeof(msgModifyTimer)); int ret=CTimerManager::getInstance()->modifyEvent(msgModifyTimer.eventID,msgModifyTimer.announceTime,msgModifyTimer.alarmTime, msgModifyTimer.stopTime, msgModifyTimer.eventRepeat ); CTimerd::responseStatus rspStatus; rspStatus.status = (ret!=0); write( connfd, &rspStatus, sizeof(rspStatus)); break; } case CTimerd::CMD_ADDTIMER: // neuen timer hinzufügen CTimerd::commandAddTimer msgAddTimer; read(connfd,&msgAddTimer, sizeof(msgAddTimer)); CTimerd::responseAddTimer rspAddTimer; CTimerEvent* event; CTimerd::EventInfo evInfo; switch(msgAddTimer.eventType) { case CTimerd::TIMER_STANDBY : CTimerd::commandSetStandby standby; read( connfd, &standby, sizeof(CTimerd::commandSetStandby)); event = new CTimerEvent_Standby( msgAddTimer.announceTime, msgAddTimer.alarmTime, standby.standby_on, msgAddTimer.eventRepeat); rspAddTimer.eventID = CTimerManager::getInstance()->addEvent( event); break; case CTimerd::TIMER_SHUTDOWN : event = new CTimerEvent_Shutdown( msgAddTimer.announceTime, msgAddTimer.alarmTime, msgAddTimer.eventRepeat); rspAddTimer.eventID = CTimerManager::getInstance()->addEvent( event); break; case CTimerd::TIMER_SLEEPTIMER : event = new CTimerEvent_Sleeptimer( msgAddTimer.announceTime, msgAddTimer.alarmTime, msgAddTimer.eventRepeat); rspAddTimer.eventID = CTimerManager::getInstance()->addEvent( event); break; case CTimerd::TIMER_RECORD : read( connfd, &evInfo, sizeof(CTimerd::EventInfo)); event = new CTimerEvent_Record( msgAddTimer.announceTime, msgAddTimer.alarmTime, msgAddTimer.stopTime, evInfo.channel_id, evInfo.epgID, evInfo.apid, msgAddTimer.eventRepeat); rspAddTimer.eventID = CTimerManager::getInstance()->addEvent( event); break; case CTimerd::TIMER_ZAPTO : read( connfd, &evInfo, sizeof(CTimerd::EventInfo)); if(evInfo.channel_id > 0) { event = new CTimerEvent_Zapto( msgAddTimer.announceTime, msgAddTimer.alarmTime, evInfo.channel_id, evInfo.epgID, msgAddTimer.eventRepeat); rspAddTimer.eventID = CTimerManager::getInstance()->addEvent( event); } break; case CTimerd::TIMER_NEXTPROGRAM : // CTimerd::EventInfo evInfo; read( connfd, &evInfo, sizeof(CTimerd::EventInfo)); /* it = CTimerEvent_NextProgram::events.find( evInfo.uniqueKey); if (it == CTimerEvent_NextProgram::events.end()) { event = new CTimerEvent_NextProgram( msgAddTimer.announceTime, msgAddTimer.alarmTime, msgAddTimer.stopTime, msgAddTimer.eventRepeat); static_cast<CTimerEvent_NextProgram*>(event)->eventInfo = evInfo; CTimerEvent_NextProgram::events.insert(make_pair(static_cast<CTimerEvent_NextProgram*>(event)->eventInfo.uniqueKey, static_cast<CTimerEvent_NextProgram*>(event))); rspAddTimer.eventID = CTimerManager::getInstance()->addEvent( event); } else { event = it->second; static_cast<CTimerEvent_NextProgram*>(event)->eventInfo = evInfo; event->alarmtime.tm_mon = msgAddTimer.month; event->alarmtime.tm_mday = msgAddTimer.day; event->alarmtime.tm_hour = msgAddTimer.hour; event->alarmtime.tm_min = msgAddTimer.min; rspAddTimer.eventID = event->eventID; } */ break; case CTimerd::TIMER_REMIND : CTimerd::commandRemind remind; read( connfd, &remind, sizeof(CTimerd::commandRemind)); event = new CTimerEvent_Remind(msgAddTimer.announceTime, msgAddTimer.alarmTime, remind.message, msgAddTimer.eventRepeat); rspAddTimer.eventID = CTimerManager::getInstance()->addEvent( event); break; default: printf("[timerd] Unknown TimerType\n"); } write( connfd, &rspAddTimer, sizeof(rspAddTimer)); break; case CTimerd::CMD_REMOVETIMER: // timer entfernen dprintf("TIMERD: command remove\n"); CTimerd::commandRemoveTimer msgRemoveTimer; read(connfd,&msgRemoveTimer, sizeof(msgRemoveTimer)); dprintf("TIMERD: command remove %d\n",msgRemoveTimer.eventID ); CTimerManager::getInstance()->removeEvent( msgRemoveTimer.eventID); break; case CTimerd::CMD_TIMERDAVAILABLE: // testen ob server läuft ;) { CTimerd::responseAvailable rspAvailable; rspAvailable.available = true; write( connfd, &rspAvailable, sizeof(rspAvailable)); } break; case CTimerd::CMD_SHUTDOWN: { bool ret=CTimerManager::getInstance()->shutdown(); CTimerd::responseStatus rspStatus; rspStatus.status = ret; write( connfd, &rspStatus, sizeof(rspStatus)); doLoop=false; } break; case CTimerd::CMD_SETAPID: // apid setzen { CTimerd::commandSetAPid data; read(connfd,&data, sizeof(data)); CTimerManager::getInstance()->modifyEvent(data.eventID , data.apid ); } break; default: dprintf("unknown command\n"); } }
int main(int argc, char **argv) { int listenfd, connfd; struct sockaddr_un servaddr; int clilen; bool do_fork = true; bool no_wait = false; doLoop=true; dprintf("startup!!!\n\n"); if(argc > 1) { for(int i = 1; i < argc; i++) { if(strncmp(argv[i], "-f", 2) == 0) { do_fork = false; } else if(strncmp(argv[i], "-w", 2) == 0) { no_wait=true; } } } if(do_fork) { switch(fork()) { case -1: perror("[timerd] fork"); return -1; case 0: break; default: return 0; } if(setsid() == -1) { perror("[timerd] setsid"); return -1; } } memset(&servaddr, 0, sizeof(struct sockaddr_un)); servaddr.sun_family = AF_UNIX; strcpy(servaddr.sun_path, TIMERD_UDS_NAME); clilen = sizeof(servaddr.sun_family) + strlen(servaddr.sun_path); unlink(TIMERD_UDS_NAME); //network-setup if((listenfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { dperror("error while socket create"); } if( bind(listenfd, (struct sockaddr*) &servaddr, clilen) <0 ) { dperror("bind failed..."); exit(-1); } if(listen(listenfd, 15) !=0) { perror("listen failed..."); exit( -1 ); } if(!no_wait) { // wait for correct date to be set... CSectionsdClient sectionsd; while(!sectionsd.getIsTimeSet()) sleep(1); } loadTimersFromConfig(); //startup Timer try { CBasicMessage::Header rmessage; while(doLoop) // wait for incomming messages { connfd = accept(listenfd, (struct sockaddr*) &servaddr, (socklen_t*) &clilen); memset(&rmessage, 0, sizeof(rmessage)); read(connfd,&rmessage,sizeof(rmessage)); parse_command(connfd, &rmessage); close(connfd); } } catch(std::exception& e) { dprintf("caught std-exception in main-thread %s!\n", e.what()); } catch(...) { dprintf("caught exception in main-thread!\n"); } }
bool CWebserver::run(void) { set_threadname(__func__); if (!listenSocket.listen(port, HTTPD_MAX_CONNECTIONS)) { if (port != 80) { fprintf(stderr, "[yhttpd] Socket cannot bind and listen on port %d Abort.\n", port); return false; } fprintf(stderr, "[yhttpd] cannot bind and listen on port 80, retrying on port 8080.\n"); port = 8080; if (!listenSocket.listen(port, HTTPD_MAX_CONNECTIONS)) { fprintf(stderr, "[yhttpd] Socket cannot bind and listen on port %d Abort.\n", port); return false; } } #ifdef Y_CONFIG_FEATURE_KEEP_ALIVE // initialize values for select int listener = listenSocket.get_socket();// Open Listener struct timeval tv; // timeout struct FD_SET(listener, &master); // add the listener to the master set fdmax = listener; // init max fd fcntl(listener, F_SETFD , O_NONBLOCK); // listener master socket non-blocking int timeout_counter = 0; // Counter for Connection Timeout checking int test_counter = 0; // Counter for Testing long running Connections // main Webserver Loop while(!terminate) { // select : init vars read_fds = master; // copy it tv.tv_usec = 10000; // microsec: Timeout for select ! for re-use / keep-alive socket tv.tv_sec = 0; // seconds int fd = -1; // select : wait for socket activity if(open_connections <= 0) // No open Connection. Wait in select. fd = select(fdmax+1,&read_fds, NULL, NULL, NULL);// wait for socket activity else fd = select(fdmax+1,&read_fds, NULL, NULL, &tv);// wait for socket activity or timeout // too much to do : sleep if(open_connections >= HTTPD_MAX_CONNECTIONS-1) sleep(1); // Socket Error? if(fd == -1 && errno != EINTR) { perror("select"); return false; } // Socket Timeout? if(fd == 0) { // Testoutput for long living threads if(++test_counter >= MAX_TIMEOUTS_TO_TEST) { for(int j=0;j < HTTPD_MAX_CONNECTIONS;j++) if(SocketList[j] != NULL) // here is a socket log_level_printf(2,"FD-TEST sock:%d handle:%d open:%d\n",SocketList[j]->get_socket(), SocketList[j]->handling,SocketList[j]->isOpened); test_counter=0; } // some connection closing previous missed? if(++timeout_counter >= MAX_TIMEOUTS_TO_CLOSE) { CloseConnectionSocketsByTimeout(); timeout_counter=0; } continue; // main loop again } //---------------------------------------------------------------------------------------- // Check all observed descriptors & check new or re-use Connections //---------------------------------------------------------------------------------------- for(int i = listener; i <= fdmax; i++) { int slot = -1; if(FD_ISSET(i, &read_fds)) // Socket observed? { // we got one!! if (i == listener) // handle new connections slot = AcceptNewConnectionSocket(); else // Connection on an existing open Socket = reuse (keep-alive) { slot = SL_GetExistingSocket(i); if(slot>=0) log_level_printf(2,"FD: reuse con fd:%d\n",SocketList[slot]->get_socket()); } // prepare Connection handling if(slot>=0) if(SocketList[slot] != NULL && !SocketList[slot]->handling && SocketList[slot]->isValid) { log_level_printf(2,"FD: START CON HANDLING con fd:%d\n",SocketList[slot]->get_socket()); FD_CLR(SocketList[slot]->get_socket(), &master); // remove from master set SocketList[slot]->handling = true; // prepares for thread-handling if(!handle_connection(SocketList[slot]))// handle this activity { // Can not handle more threads char httpstr[]=HTTP_PROTOCOL " 503 Service Unavailable\r\n\r\n"; SocketList[slot]->Send(httpstr, strlen(httpstr)); SL_CloseSocketBySlot(slot); } } } }// for CloseConnectionSocketsByTimeout(); // Check connections to close }//while #else while (!terminate) { CySocket *newConnectionSock; if (!(newConnectionSock = listenSocket.accept())) //Now: Blocking wait { pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_testcancel(); dperror("Socket accept error. Continue.\n"); continue; } log_level_printf(3, "Socket connect from %s\n", (listenSocket.get_client_ip()).c_str()); #ifdef Y_CONFIG_USE_OPEN_SSL if(Cyhttpd::ConfigList["SSL"]=="true") newConnectionSock->initAsSSL(); // make it a SSL-socket #endif handle_connection(newConnectionSock); } #endif return true; }