connection_https.c

Go to the documentation of this file.
00001 /*
00002      This file is part of libmicrohttpd
00003      (C) 2007, 2008 Daniel Pittman and Christian Grothoff
00004 
00005      This library is free software; you can redistribute it and/or
00006      modify it under the terms of the GNU Lesser General Public
00007      License as published by the Free Software Foundation; either
00008      version 2.1 of the License, or (at your option) any later version.
00009 
00010      This library is distributed in the hope that it will be useful,
00011      but WITHOUT ANY WARRANTY; without even the implied warranty of
00012      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013      Lesser General Public License for more details.
00014 
00015      You should have received a copy of the GNU Lesser General Public
00016      License along with this library; if not, write to the Free Software
00017      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00018 
00019 */
00020 
00029 #include "internal.h"
00030 #include "connection.h"
00031 #include "memorypool.h"
00032 #include "response.h"
00033 #include "reason_phrase.h"
00034 
00035 /* get opaque type */
00036 #include "gnutls_int.h"
00037 #include "gnutls_record.h"
00038 
00039 /* TODO #include rm "gnutls_errors.h" */
00040 #include "gnutls_errors.h"
00041 
00052 static void
00053 MHD_tls_connection_close (struct MHD_Connection *connection,
00054                           enum MHD_RequestTerminationCode termination_code)
00055 {
00056   MHD__gnutls_bye (connection->tls_session, GNUTLS_SHUT_WR);
00057   connection->tls_session->internals.read_eof = 1;
00058   MHD_connection_close (connection, termination_code);
00059 }
00060 
00071 static int
00072 MHD_tls_connection_handle_idle (struct MHD_Connection *connection)
00073 {
00074   unsigned int timeout;
00075 
00076 #if DEBUG_STATES
00077   MHD_DLOG (connection->daemon, "%s: state: %s\n",
00078             __FUNCTION__, MHD_state_to_string (connection->state));
00079 #endif
00080   timeout = connection->daemon->connection_timeout;
00081   if ((connection->socket_fd != -1) && (timeout != 0)
00082       && (time (NULL) - timeout > connection->last_activity))
00083     {
00084       MHD_tls_connection_close (connection,
00085                                 MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
00086       return MHD_NO;
00087     }
00088   switch (connection->state)
00089     {
00090       /* on newly created connections we might reach here before any reply has been received */
00091     case MHD_TLS_CONNECTION_INIT:
00092       return MHD_YES;
00093       /* close connection if necessary */
00094     case MHD_CONNECTION_CLOSED:
00095       if (connection->socket_fd != -1)
00096         MHD_tls_connection_close (connection,
00097                                   MHD_REQUEST_TERMINATED_COMPLETED_OK);
00098       return MHD_NO;
00099     case MHD_TLS_HANDSHAKE_FAILED:
00100       MHD_tls_connection_close (connection,
00101                                 MHD_REQUEST_TERMINATED_WITH_ERROR);
00102       return MHD_NO;
00103       /* some HTTP state */
00104     default:
00105       return MHD_connection_handle_idle (connection);
00106     }
00107   return MHD_YES;
00108 }
00109 
00127 static int
00128 MHD_tls_connection_handle_read (struct MHD_Connection *connection)
00129 {
00130   int ret;
00131   unsigned char msg_type;
00132 
00133   connection->last_activity = time (NULL);
00134   if (connection->state == MHD_CONNECTION_CLOSED ||
00135       connection->state == MHD_TLS_HANDSHAKE_FAILED)
00136     return MHD_NO;
00137 
00138 #if DEBUG_STATES
00139   MHD_DLOG (connection->daemon, "%s: state: %s\n",
00140             __FUNCTION__, MHD_state_to_string (connection->state));
00141 #endif
00142 
00143   /* discover content type */
00144   if (RECV (connection->socket_fd, &msg_type, 1, MSG_PEEK) == -1)
00145     {
00146 #if HAVE_MESSAGES
00147       MHD_DLOG (connection->daemon, "Failed to peek into TLS content type\n");
00148 #endif
00149       return MHD_NO;
00150     }
00151 
00152   switch (msg_type)
00153     {
00154       /* check for handshake messages first */
00155     case GNUTLS_HANDSHAKE:
00156       /* negotiate handshake only while in INIT & HELLO_REQUEST states */
00157       if (connection->state == MHD_TLS_CONNECTION_INIT ||
00158           connection->state == MHD_TLS_HELLO_REQUEST)
00159         {
00160           ret = MHD__gnutls_handshake (connection->tls_session);
00161           if (ret == 0)
00162             {
00163               /* set connection state to enable HTTP processing */
00164               connection->state = MHD_CONNECTION_INIT;
00165               break;
00166             }
00167           /* set connection as closed */
00168           else
00169             {
00170 #if HAVE_MESSAGES
00171               MHD_DLOG (connection->daemon,
00172                         "Error: Handshake has failed (%d)\n", ret);
00173 #endif
00174               connection->state = MHD_TLS_HANDSHAKE_FAILED;
00175               return MHD_NO;
00176             }
00177         }
00178       /* a handshake message has been received out of bound */
00179       else
00180         {
00181 #if HAVE_MESSAGES
00182           MHD_DLOG (connection->daemon,
00183                     "Error: received handshake message out of context\n");
00184 #endif
00185           MHD_tls_connection_close (connection,
00186                                     MHD_REQUEST_TERMINATED_WITH_ERROR);
00187           return MHD_NO;
00188         }
00189 
00190       /* ignore any out of bound change chiper spec messages */
00191     case GNUTLS_CHANGE_CIPHER_SPEC:
00192       MHD_tls_connection_close (connection,
00193                                 MHD_REQUEST_TERMINATED_WITH_ERROR);
00194       return MHD_NO;
00195 
00196     case GNUTLS_ALERT:
00197       /*
00198        * this call of MHD_gtls_recv_int expects 0 bytes read.
00199        * done to decrypt alert message
00200        */
00201       MHD_gtls_recv_int (connection->tls_session, GNUTLS_ALERT,
00202                          GNUTLS_HANDSHAKE_FINISHED, 0, 0);
00203 
00204       /* CLOSE_NOTIFY */
00205       if (connection->tls_session->internals.last_alert ==
00206           GNUTLS_A_CLOSE_NOTIFY)
00207         {
00208           connection->state = MHD_CONNECTION_CLOSED;
00209           return MHD_YES;
00210         }
00211       /* non FATAL or WARNING */
00212       else if (connection->tls_session->internals.last_alert_level !=
00213                GNUTLS_AL_FATAL)
00214         {
00215 #if HAVE_MESSAGES
00216           MHD_DLOG (connection->daemon,
00217                     "Received TLS alert: %s\n",
00218                     MHD__gnutls_alert_get_name ((int)
00219                                                 connection->tls_session->
00220                                                 internals.last_alert));
00221 #endif
00222           return MHD_YES;
00223         }
00224       /* FATAL */
00225       else if (connection->tls_session->internals.last_alert_level ==
00226                GNUTLS_AL_FATAL)
00227         {
00228           MHD_tls_connection_close (connection,
00229                                     MHD_REQUEST_TERMINATED_WITH_ERROR);
00230           return MHD_NO;
00231         }
00232       /* this should never execute */
00233       else
00234         {
00235 #if HAVE_MESSAGES
00236           MHD_DLOG (connection->daemon,
00237                     "Received unrecognized alert: %d\n",
00238                     connection->tls_session->internals.last_alert);
00239 #endif
00240           return MHD_NO;
00241         }
00242 
00243 
00244       /* forward application level content to MHD */
00245     case GNUTLS_APPLICATION_DATA:
00246       return MHD_connection_handle_read (connection);
00247 
00248     case GNUTLS_INNER_APPLICATION:
00249       break;
00250     default:
00251 #if HAVE_MESSAGES
00252       MHD_DLOG (connection->daemon,
00253                 "Error: unrecognized TLS message type: %d, connection state: %s. l: %d, f: %s\n",
00254                 msg_type, MHD_state_to_string (connection->state), __LINE__,
00255                 __FUNCTION__);
00256 #endif
00257       /* close connection upon reception of unrecognized message type */
00258       MHD_tls_connection_close (connection,
00259                                 MHD_REQUEST_TERMINATED_WITH_ERROR);
00260       return MHD_NO;
00261     }
00262 
00263   return MHD_YES;
00264 }
00265 
00275 static int
00276 MHD_tls_connection_handle_write (struct MHD_Connection *connection)
00277 {
00278   connection->last_activity = time (NULL);
00279 
00280 #if DEBUG_STATES
00281   MHD_DLOG (connection->daemon, "%s: state: %s\n",
00282             __FUNCTION__, MHD_state_to_string (connection->state));
00283 #endif
00284 
00285   switch (connection->state)
00286     {
00287     case MHD_CONNECTION_CLOSED:
00288     case MHD_TLS_HANDSHAKE_FAILED:
00289       return MHD_NO;
00290       /* some HTTP connection state */
00291     default:
00292       return MHD_connection_handle_write (connection);
00293     }
00294   return MHD_NO;
00295 }
00296 
00301 void
00302 MHD_set_https_calbacks (struct MHD_Connection *connection)
00303 {
00304   connection->read_handler = &MHD_tls_connection_handle_read;
00305   connection->write_handler = &MHD_tls_connection_handle_write;
00306   connection->idle_handler = &MHD_tls_connection_handle_idle;
00307 }
00308 
00309 /* end of connection_https.c */

Generated on Fri Feb 27 18:31:22 2009 for GNU libmicrohttpd by  doxygen 1.5.7.1