• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

ProtocolProbeSessionAccept.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   ProtocolProbeSessionAccept
00004 
00005   @section license License
00006 
00007   Licensed to the Apache Software Foundation (ASF) under one
00008   or more contributor license agreements.  See the NOTICE file
00009   distributed with this work for additional information
00010   regarding copyright ownership.  The ASF licenses this file
00011   to you under the Apache License, Version 2.0 (the
00012   "License"); you may not use this file except in compliance
00013   with the License.  You may obtain a copy of the License at
00014 
00015       http://www.apache.org/licenses/LICENSE-2.0
00016 
00017   Unless required by applicable law or agreed to in writing, software
00018   distributed under the License is distributed on an "AS IS" BASIS,
00019   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020   See the License for the specific language governing permissions and
00021   limitations under the License.
00022  */
00023 
00024 #include "P_Net.h"
00025 #include "I_Machine.h"
00026 #include "ProtocolProbeSessionAccept.h"
00027 #include "Error.h"
00028 #include "http2/HTTP2.h"
00029 
00030 static bool
00031 proto_is_spdy(IOBufferReader * reader)
00032 {
00033   // SPDY clients have to start by sending a control frame (the high bit is set). Let's assume
00034   // that no other protocol could possibly ever set this bit!
00035   return ((uint8_t)(*reader)[0]) == 0x80u;
00036 }
00037 
00038 static bool
00039 proto_is_http2(IOBufferReader * reader)
00040 {
00041   char buf[HTTP2_CONNECTION_PREFACE_LEN];
00042   char * end;
00043   ptrdiff_t nbytes;
00044 
00045   end = reader->memcpy(buf, sizeof(buf), 0 /* offset */);
00046   nbytes = end - buf;
00047 
00048   // Client must send at least 4 bytes to get a reasonable match.
00049   if (nbytes < 4) {
00050     return false;
00051   }
00052 
00053   ink_assert(nbytes <= (int64_t)HTTP2_CONNECTION_PREFACE_LEN);
00054   return memcmp(HTTP2_CONNECTION_PREFACE, buf, nbytes) == 0;
00055 }
00056 
00057 struct ProtocolProbeTrampoline : public Continuation, public ProtocolProbeSessionAcceptEnums
00058 {
00059   static const size_t minimum_read_size = 1;
00060   static const unsigned buffer_size_index = CLIENT_CONNECTION_FIRST_READ_BUFFER_SIZE_INDEX;
00061   IOBufferReader *  reader;
00062 
00063   explicit
00064   ProtocolProbeTrampoline(const ProtocolProbeSessionAccept * probe, ProxyMutex * mutex)
00065     : Continuation(mutex), probeParent(probe)
00066   {
00067     this->iobuf = new_MIOBuffer(buffer_size_index);
00068     reader = iobuf->alloc_reader(); // reader must be allocated only on a new MIOBuffer.
00069     SET_HANDLER(&ProtocolProbeTrampoline::ioCompletionEvent);
00070   }
00071 
00072   int ioCompletionEvent(int event, void * edata)
00073   {
00074     VIO *             vio;
00075     NetVConnection *  netvc;
00076     ProtoGroupKey  key = N_PROTO_GROUPS; // use this as an invalid value.
00077 
00078     vio = static_cast<VIO *>(edata);
00079     netvc = static_cast<NetVConnection *>(vio->vc_server);
00080 
00081     switch (event) {
00082     case VC_EVENT_EOS:
00083     case VC_EVENT_ERROR:
00084     case VC_EVENT_ACTIVE_TIMEOUT:
00085     case VC_EVENT_INACTIVITY_TIMEOUT:
00086       // Error ....
00087       netvc->do_io_close();
00088       goto done;
00089     case VC_EVENT_READ_READY:
00090     case VC_EVENT_READ_COMPLETE:
00091       break;
00092     default:
00093       return EVENT_ERROR;
00094     }
00095 
00096     ink_assert(netvc != NULL);
00097 
00098     if (!reader->is_read_avail_more_than(minimum_read_size - 1)) {
00099       // Not enough data read. Well, that sucks.
00100       netvc->do_io_close();
00101       goto done;
00102     }
00103 
00104     // SPDY clients have to start by sending a control frame (the high bit is set). Let's assume
00105     // that no other protocol could possibly ever set this bit!
00106     if (proto_is_spdy(reader)) {
00107       key = PROTO_SPDY;
00108     } else if (proto_is_http2(reader)) {
00109       key = PROTO_HTTP2;
00110     } else {
00111       key = PROTO_HTTP;
00112     }
00113 
00114     netvc->do_io_read(this, 0, NULL); // Disable the read IO that we started.
00115 
00116     if (probeParent->endpoint[key] == NULL) {
00117       Warning("Unregistered protocol type %d", key);
00118       netvc->do_io_close();
00119       goto done;
00120     }
00121 
00122     // Directly invoke the session acceptor, letting it take ownership of the input buffer.
00123     probeParent->endpoint[key]->accept(netvc, this->iobuf, reader);
00124     delete this;
00125     return EVENT_CONT;
00126 
00127 done:
00128     free_MIOBuffer(this->iobuf);
00129     delete this;
00130     return EVENT_CONT;
00131   }
00132 
00133   MIOBuffer * iobuf;
00134   const ProtocolProbeSessionAccept * probeParent;
00135 };
00136 
00137 int
00138 ProtocolProbeSessionAccept::mainEvent(int event, void *data)
00139 {
00140   if (event == NET_EVENT_ACCEPT) {
00141     ink_assert(data);
00142 
00143     VIO * vio;
00144     NetVConnection * netvc = static_cast<NetVConnection*>(data);
00145     ProtocolProbeTrampoline * probe = new ProtocolProbeTrampoline(this, netvc->mutex);
00146 
00147     // XXX we need to apply accept inactivity timeout here ...
00148 
00149     vio = netvc->do_io_read(probe,
00150                     BUFFER_SIZE_FOR_INDEX(ProtocolProbeTrampoline::buffer_size_index), probe->iobuf);
00151     vio->reenable();
00152     return EVENT_CONT;
00153   }
00154 
00155   MachineFatal("Protocol probe received a fatal error: errno = %d", -((int)(intptr_t)data));
00156   return EVENT_CONT;
00157 }
00158 
00159 void
00160 ProtocolProbeSessionAccept::accept(NetVConnection *, MIOBuffer *, IOBufferReader *)
00161 {
00162   ink_release_assert(0);
00163 }
00164 
00165 void
00166 ProtocolProbeSessionAccept::registerEndpoint(ProtoGroupKey key, SessionAccept * ap)
00167 {
00168   ink_release_assert(endpoint[key] == NULL);
00169   this->endpoint[key] = ap;
00170 }

Generated by  doxygen 1.7.1