Main Page   Data Structures   File List   Data Fields   Globals   Related Pages  

conn_handler.c

Go to the documentation of this file.
00001 /***************************************************************************
00002                                conn_handler.c
00003                              -------------------
00004     begin                : Thu Nov 15 2001
00005     copyright            : (C) 2001-2002 by Christian Hoenig & Gunter Ohrner
00006     email                : pdepp@CustomCDROM.de
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00024 #include "common.h"
00025 
00026 #include <errno.h>
00027 #include <fcntl.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #include <unistd.h>
00031 
00032 // the following order is required!
00033 #include <sys/types.h>
00034 #include <sys/socket.h>
00035 #include <netinet/in.h>
00036 #include <arpa/inet.h>
00037 
00038 
00039 #include "conn_handler.h"
00040 
00041 #include "xmalloc.h"
00042 #include "buffer.h"
00043 #include "conftable.h"
00044 #include "logger.h"
00045 #include "http.h"
00046 
00047 
00049 #ifndef MSG_NOSIGNAL
00050 # define MSG_NOSIGNAL 0
00051 #endif
00052 
00053 /* prüfe of EAGAIN und/oder EWOULDBLOCK definiert sind und sorge dafür,
00054    dass sie es sind
00055  */
00056 #ifdef EAGAIN
00057 # ifndef EWOULDBLOCK
00058 #  define EWOULDBLOCK EAGAIN
00059 # endif
00060 #else // EAGAIN not defined
00061 # ifdef EWOULDBLOCK
00062 #   define EAGAIN EWOULDBLOCK
00063 # else
00064 #   error Neither EAGAIN nor EWOULDBLOCK defined, aborting!
00065 # endif
00066 #endif
00067 
00069 struct ConnHandler
00070 {
00071   // miscellaneous ch data
00072   int socket;                     
00073   struct sockaddr_in client_addr; 
00074   /*socklen_t*/ int client_addr_len;      
00075   // Is this a fixed value or might it change for a given connection?
00076   //  size_t send_chunk_len;          ///< largest block of data which can be send atomically
00077   int error;                      
00078   time_t stamp;                   
00079 
00080   HttpProtHandler prot_handler;   
00081 
00082   // receive buffer state
00083   struct Buffer recv_buf;  
00084 
00085   // send buffer state
00086   struct Buffer* send_buf; 
00087 };
00088 
00089 // ****************************************************************************
00090 
00091 static size_t recv_buf_size;
00092 
00093 // initialise static values
00094 int chModulePreInit()
00095 {
00096   recv_buf_size = getEntryDeflL(CONFENTRY_KEY_RECVBUFFER, STD_CONFENTRY_VAL_RECVBUFFER);
00097 
00098   return 0;
00099 }
00100 
00101 // free all ressources allocated by the whole module
00102 int chModuleTerminate()
00103 {
00104   return 0;
00105 }
00106 
00107 // ****************************************************************************
00108 
00109 // creates and returns a new ConnHandler object
00110 ConnHandler chInit(int server_socket)
00111 {
00112   ConnHandler this;
00113 
00114   this = (ConnHandler) pd_malloc(sizeof(struct ConnHandler));
00115 
00116   this->client_addr_len = sizeof(this->client_addr);
00117   if ((this->socket = accept(server_socket,
00118                              (struct sockaddr *) &this->client_addr,
00119                              &this->client_addr_len)) == -1)
00120   {
00121     logerr(CONN_HANDLER, NOTICE, errno,
00122            "could not accept connection");
00123     return NULL;
00124   }
00125 
00126   logger(CONN_HANDLER, NOTICE,
00127          "%d: connection to %s established",
00128          this->socket, inet_ntoa(this->client_addr.sin_addr));
00129 
00130   fcntl(this->socket, F_SETFL, O_NONBLOCK);
00131 
00132   logger(CONN_HANDLER, INFO,
00133          "%d: non-blocking mode set on socket", this->socket);
00134 
00135   this->error = E_SUCCESS;
00136   // we only have one kind of ProtHandler so we may as well initialize it here
00137   this->prot_handler = htInit(this);
00138 
00139 
00140   this->recv_buf = bufInit((char*) pd_malloc(recv_buf_size), recv_buf_size, 0);
00141 
00142   // set send_buf to a valid value != NULL
00143   this->send_buf = NULL;
00144 
00145   logger(CONN_HANDLER, NOTICE,
00146          "%d: connection initalised", this->socket);
00147 
00148   this->stamp = time(NULL);
00149 
00150   return this;
00151 }
00152 
00153 // returns a connection handlers communication socket descriptor
00154 int chGetSocket(const ConnHandler this)
00155 {
00156   return this->socket;
00157 }
00158 
00159 // return the last time where data was exchanged
00160 time_t chGetStamp(const ConnHandler this)
00161 {
00162   return this->stamp;
00163 }
00164 
00166 int readData(ConnHandler this)
00167 {
00168   ssize_t recv_len;
00169   errno = 0;
00170 
00171   do {
00172     recv_len = recv(this->socket, this->recv_buf.data,
00173                     this->recv_buf.len, MSG_NOSIGNAL);
00174   } while (recv_len == -1 && errno == EINTR);
00175 
00176   if (recv_len != -1)
00177     this->stamp = time(NULL);
00178   else
00179   {
00180     switch(errno)
00181     {
00182 #if EAGAIN != EWOULDBLOCK
00183       case EAGAIN:
00184 #endif
00185       case EWOULDBLOCK:
00186         return 0;
00187       default:
00188         this->error = errno;
00189         // logerr(CONN_HANDLER, NOTICE, "connection to client broken", errno);
00190         return -1;
00191     }
00192   }
00193   return recv_len;
00194 }
00195 
00196 // handles a request waiting on the connection socket
00197 int chReceive(ConnHandler this)
00198 {
00199   struct Buffer tmp_buf = bufInit(this->recv_buf.data, 0, 0);
00200 
00201   if (this->socket == 0) return -1;
00202 
00203   logger(CONN_HANDLER, DEBUG,
00204          "%d: reading pending data", this->socket);
00205 
00206   tmp_buf.len = readData(this);
00207 
00208   if (tmp_buf.len > 0)
00209     htReceive(this->prot_handler, tmp_buf);
00210   else {
00211     // error reading data
00212     logerr(CONN_HANDLER, NOTICE, this->error,
00213            "%d: error reading pending data", this->socket);
00214     this->error = EPIPE;
00215   }
00216 
00217   return (this->error == E_SUCCESS) ? 0 : -1;
00218 }
00219 
00221 inline int byteInQueue(const ConnHandler this)
00222 {
00223   return this->send_buf->len - this->send_buf->pos;
00224 }
00225 
00226 // is there any data waiting to be send?
00227 int chIsDataPending(const ConnHandler this)
00228 {
00229   if (this == NULL || this->send_buf == NULL)
00230     return false;
00231   return (byteInQueue(this) != 0);
00232 }
00233 
00235 int forwardSendToProtHandler(ConnHandler this)
00236 {
00237   if (!chIsDataPending(this) && htIsDataPending(this->prot_handler))
00238   {
00239     // request ProtocolHandler to send new data
00240     if (htSend(this->prot_handler, &(this->send_buf)) == -1)
00241     {
00242       return -1; // critical error
00243     }
00244 
00245     // are we done?
00246     if (this->send_buf->data == NULL) return 1; // finished
00247   }
00248 
00249   return 0;
00250 }
00251 
00252 // sends some of the data currently in queue
00253 int chSend(ConnHandler this)
00254 {
00255   int data_sent;
00256   size_t data_left = byteInQueue(this);
00257   if (data_left == 0) return 0;
00258 
00259   do
00260   {
00261     errno = 0;
00262     
00263     logger(CONN_HANDLER, DEBUG,
00264            "%d: sending pending data", this->socket);
00265 
00266     data_sent = send(this->socket, this->send_buf->data + this->send_buf->pos,
00267                      data_left, MSG_NOSIGNAL);
00268 
00269     if (data_sent != -1)
00270       this->stamp = time(NULL);
00271     else
00272     {
00273       switch(errno)
00274       {
00275 #if EAGAIN != EWOULDBLOCK
00276         case EAGAIN:
00277 #endif
00278         case EWOULDBLOCK:
00279           data_left /= 2;
00280           break;
00281         default:
00282           this->error = errno;
00283           logerr(CONN_HANDLER, NOTICE, this->error,
00284                  "%d: error sending pending data", this->socket);
00285           return -1;
00286       }
00287     }
00288   } while(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN);
00289 
00290   this->send_buf->pos += data_sent;
00291 
00292   // Still data left to send? Queue if yes.
00293   return forwardSendToProtHandler(this);
00294   // use correct exit status
00295 }
00296 
00297 // do additional data processing and allow the request handler
00298 // to fill its alternative send buffer
00299 int chProcess(ConnHandler this)
00300 {
00301   // request new data to be queued if neccessary and available
00302   forwardSendToProtHandler(this);
00303 
00304   // allow ProtHandler to process data / fill an alternative send buffer
00305   return htProcess(this->prot_handler);
00306 }
00307 
00308 // return current error code
00309 int chGetError(const ConnHandler this)
00310 {
00311   return this->error;
00312 }
00313 
00314 // destruct connection handler
00315 int chTerminate(ConnHandler this)
00316 {
00317   if (this == NULL) return -1;
00318 
00319   logger(CONN_HANDLER, NOTICE,
00320          "%d: terminating connection", this->socket);
00321 
00322   htTerminate(this->prot_handler);
00323 
00324   shutdown(this->socket, 2);
00325   close(this->socket);
00326 
00327   pd_free(this->recv_buf.data);
00328   pd_free(this);
00329 
00330   return 0;
00331 }

Generated on Fri Jan 25 22:40:30 2002 for PDepp Webserver by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001