Epoll bleibt hängen



  • Moin,

    habe epoll interface implementiert in meinen kleinen http server leider bleibt chrome beim recv hängen so weit ich das verstehe muss bei connection close etwas schief gehen da chrome mit mehreren verbindungen arbeitet.

    gdb ausgabe:

    HTTP Note: switch to recv mode!
    HTTP Note: switch to recv m^C
    Program received signal SIGINT, Interrupt.
    0x00007ffff756ca10 in __write_nocancel () at ../sysdeps/unix/syscall-template.S:84
    84      ../sysdeps/unix/syscall-template.S: Datei oder Verzeichnis nicht gefunden.
    (gdb) bt
    #0  0x00007ffff756ca10 in __write_nocancel () at ../sysdeps/unix/syscall-template.S:84
    #1  0x00007ffff74eeb2f in _IO_new_file_write (f=0x7ffff783a620 <_IO_2_1_stdout_>, data=0x61f360, n=33)
        at fileops.c:1263
    #2  0x00007ffff74f0339 in new_do_write (to_do=33, 
        data=0x61f360 "HTTP Note: switch to recv mode!\r\nermination not found\r\n", fp=0x7ffff783a620 <_IO_2_1_stdout_>)
        at fileops.c:518
    #3  _IO_new_do_write (fp=0x7ffff783a620 <_IO_2_1_stdout_>, 
        data=0x61f360 "HTTP Note: switch to recv mode!\r\nermination not found\r\n", to_do=33) at fileops.c:494
    #4  0x00007ffff74ef3ad in _IO_new_file_xsputn (f=0x7ffff783a620 <_IO_2_1_stdout_>, data=<optimized out>, n=33)
        at fileops.c:1331
    #5  0x00007ffff74c44cb in _IO_vfprintf_internal (s=0x7ffff783a620 <_IO_2_1_stdout_>, format=<optimized out>, 
        ap=ap@entry=0x7fffffffd3e8) at vfprintf.c:1632
    #6  0x00007ffff74cb849 in __printf (format=<optimized out>) at printf.c:33
    #7  0x0000000000405091 in libhttppp::HTTPException::ErrorTemplate<char const*, char const*> (this=0x61ef00, 
        type=0x61f007, buffer=0x61ef08 "HTTP Note: switch to recv mode!\r\n", printstyle=0x408f69 "HTTP Note: %s\r\n", 
        message=0x4095fd "switch to recv mode!") at /home/jan/projects/libhttppp/libhttppp/test/../src/exception.h:109
    #8  0x0000000000404d51 in libhttppp::HTTPException::Note (this=0x61ef00, msg=0x4095fd "switch to recv mode!")
        at /home/jan/projects/libhttppp/libhttppp/test/../src/exception.h:80
    #9  0x000000000040730f in libhttppp::Queue::Queue (this=0x61edd0, socket=0x61ec20)
        at /home/jan/projects/libhttppp/libhttppp/src/queues/epoll.cpp:134
    #10 0x0000000000406b88 in libhttppp::HttpD::runDaemon (this=0x7fffffffd800)
        at /home/jan/projects/libhttppp/libhttppp/src/httpd.cpp:74
    #11 0x0000000000404f83 in HttpConD::HttpConD (this=0x7fffffffd800, argc=4, argv=0x7fffffffde28)
        at /home/jan/projects/libhttppp/libhttppp/test/httpcon.cpp:51
    #12 0x0000000000404beb in main (argc=4, argv=0x7fffffffde28)
        at /home/jan/projects/libhttppp/libhttppp/test/httpcon.cpp:60
    

    https://github.com/Tuxist/libhttppp

    /*******************************************************************************
    Copyright (c) 2014, Jan Koester jan.koester@gmx.net
    All rights reserved.
    
    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
        * Redistributions of source code must retain the above copyright
          notice, this list of conditions and the following disclaimer.
        * Redistributions in binary form must reproduce the above copyright
          notice, this list of conditions and the following disclaimer in the
          documentation and/or other materials provided with the distribution.
        * Neither the name of the <organization> nor the
          names of its contributors may be used to endorse or promote products
          derived from this software without specific prior written permission.
    
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    *******************************************************************************/
    
    #include <fcntl.h>
    #include <sys/epoll.h>
    #include <cstdlib>
    #include <config.h>
    #include <errno.h>
    
    #define READEVENT 0
    #define SENDEVENT 1
    
    #include "../queue.h"
    
    using namespace libhttppp;
    
    Queue::Queue(ServerSocket *socket) : ConnectionPool(socket) {
      struct epoll_event *events;
      struct epoll_event  event = {0};
      events = new epoll_event[(socket->getMaxconnections()*sizeof(struct epoll_event))];
      for(int i=0; i<socket->getMaxconnections(); i++)
        events[i].data.fd = -1;
      int epollfd = epoll_create(socket->getMaxconnections());
    
      if (epollfd == -1){
        _httpexception.Cirtical("can't create epoll");
        throw _httpexception;
      }
    
      event.events = EPOLLIN | EPOLLRDHUP;
      event.data.fd = socket->getSocket();
      if (epoll_ctl(epollfd, EPOLL_CTL_ADD, socket->getSocket(), &event) < 0){
        _httpexception.Cirtical("can't create epoll");
        throw _httpexception;
      }
    
      for(;;){
        int n = epoll_wait(epollfd, events, socket->getMaxconnections(), EPOLLWAIT);
        for(int i=0; i<n; i++) {
          Connection *curcon=NULL;
          if(events[i].data.fd == socket->getSocket()) {
            try{
              /*will create warning debug mode that normally because the check already connection
               * with this socket if getconnection throw they will be create a new one
               */
    	  curcon=addConnection();
    	  ClientSocket *clientsocket=curcon->getClientSocket();
    	  clientsocket->setnonblocking();
              event.data.fd =_ServerSocket->acceptEvent(clientsocket);
              event.events = EPOLLIN | EPOLLRDHUP;
    
              if(epoll_ctl(epollfd, EPOLL_CTL_ADD, event.data.fd, &event)==-1 && errno==EEXIST)
                epoll_ctl(epollfd, EPOLL_CTL_MOD, events[i].data.fd, &event);
            }catch(HTTPException &e){
              if(e.isCritical())
                throw e;
            }
            continue;
          }else{
    	curcon=getConnection(events[i].data.fd);
          }
    
          if(events[i].events & EPOLLIN){
              try{
                char buf[BLOCKSIZE];
                int rcvsize=_ServerSocket->recvData(curcon->getClientSocket(),buf,BLOCKSIZE);
                printf("recvsize: %d\n",rcvsize);
    	    if(rcvsize==-1){
                   if (errno == EAGAIN)
                     continue;
                   else
                     goto CloseConnection;
                }
                curcon->addRecvQueue(buf,rcvsize);
                RequestEvent(curcon);
                if(curcon->getSendData()){
                  event.events = EPOLLOUT | EPOLLRDHUP;
                  epoll_ctl(epollfd, EPOLL_CTL_MOD, events[i].data.fd, &event);
    	      _httpexception.Note("switch to send mode!");
                }
              }catch(HTTPException &e){
                if(e.isCritical()){
                  throw e;
                }
                if(e.isError())
                 goto CloseConnection;
              }
          }
    
          if(events[i].events & EPOLLOUT) {
            try{
              if(curcon && curcon->getSendData()){
                ssize_t sended=_ServerSocket->sendData(curcon->getClientSocket(),
                                                       (void*)curcon->getSendData()->getData(),
                                                        curcon->getSendData()->getDataSize());
                if(sended==-1){
                  _httpexception.Note("Sending Failed");
                  if (errno == EAGAIN){
                    continue;
                  }else{
    		curcon->cleanSendData();
                    goto CloseConnection;
    	      }
                }else{
                  curcon->resizeSendQueue(sended); 
                }
              }else{
                  event.events = EPOLLIN | EPOLLRDHUP;
                  epoll_ctl(epollfd, EPOLL_CTL_MOD, events[i].data.fd, &event);
    	      _httpexception.Note("switch to recv mode!");
              }
            }catch(HTTPException &e){
               goto CloseConnection;
            }
          }
    
          if(events[i].events & EPOLLRDHUP || events[i].events & EPOLLERR) {
              CloseConnection:
                try{
                  delConnection(curcon);
                  epoll_ctl(epollfd, EPOLL_CTL_DEL, events[i].data.fd, &event);
    	      _httpexception.Note("Connection shutdown!");
    	      continue;
                }catch(HTTPException &e){
                  _httpexception.Note("Can't do Connection shutdown!");
                }
              ;
          }
        }
      }
      delete events;
    
    }
    
    Queue::~Queue(){
    
    }
    


  • Zunächst mal implementierst du nicht epoll , sondern du verwendest das epoll -Interface.

    Und ansonsten: ist das dein Scheißernst? Du klatschst einfach zwei Blöcke Code hin, sagst nicht mal wage "Hier irgendwo muss der Fehler sein", und erwartest, dass sich die Leute noch deinen Code herunterladen und ein Nicht-Standard-Buildsystem verwenden, um deinen Server zu bauen (brauchst du cmake für irgendwas besonderes? Kann ich mir nicht vorstellen). Dann baue ich den Server zähneknirschend, aber dieses cmake sagt mir nicht, wo er gebaut hat. Ich habe auch ohne Anleitung keinen Bock, danach zu suchen. Nee, so läuft das nicht.



  • cmake baut in dem Verzeichnis von dem aus cmake getstartet wurden ist.

    mkdir libhttppp/build
    cd build
    cmake ../
    make

    dann starten einer demo:

    ./test/httpcon --httpaddr=0.0.0.0 --httpport=8080 --rootpath=/tmp



  • habe jetzt auf epollet umgestellt hängt jetzt aber bei recv und somit läuft der loop nicht durch die sockets nonblock gesetzt.

    for(;;){
                  char buf[BLOCKSIZE];
                  int rcvsize=_ServerSocket->recvData(curcon->getClientSocket(),buf,BLOCKSIZE);
                  printf("recvsize: %d\n",rcvsize);
    	      if(rcvsize==-1){
                    if (errno == EAGAIN){
                      break;
    		}else{
                      goto CloseConnection;
    		}
                  }else if(rcvsize==0){	
    		break;
    	      }
                  curcon->addRecvQueue(buf,rcvsize);
    	    }
    


  • habe es hin bekommen war blöder fehler setnonblocking aus veresehen vor accept event gesetzt.



  • @dachschaden. Also cmake können ist eigentlich pflichtprogramm ^^.



  • 5cript schrieb:

    @dachschaden. Also cmake können ist eigentlich pflichtprogramm ^^.

    cmake ist das schlechteste Build-System, das ich je gesehen habe.

    Hey, lasst uns eine CMakeCache.txt erstellen, die nicht aktualisiert wird, wenn der User eigene Bibliotheksverzeichnisse angibt, sodass wir auf keinen Fall speziell für diese Architektur kompilierte Binaries finden. Soll der Nutzer doch raten, dass diese Datei erst gelöscht werden muss, damit wir seine neuen Optionen anerkennen.

    Oder:

    Hey, lasst uns -DCMAKE_INSTALL_PREFIX manchmal nicht zum Makefile durchreichen, sodass der User am Ende make install aufruft und die ganze Scheiße in einem Verzeichnis installiert wird, in dass sie nicht rein soll.

    Oder, der Kracher:

    Hey, lasst uns irgendwelche Spastis nicht dazu zwingen, ein verdammtes make uninstall anzulegen, damit der User, wenn er denn merkt, dass ihr's nicht hinbekommen habt, -DCMAKE_INSTALL_PREFIX durchzureichen, es auch nicht wieder automatisiert entfernen kann. Das soll der dann mal schön selbermachen woot LOL rofl

    GNU Make ist nicht perfekt, aber es ist bei weitem besser als alles, was diese Hipster-Spacken von cmake je rausgebracht haben. Die haben's auf Lebenszeit bei mir verkackt mit ihrer unfertigen Gülle. Und dabei habe ich noch nicht mal eine Cross-Compilierung versucht *schauder*.


Log in to reply