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

InkAPITestTool.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   Implements unit test for SDK APIs
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 "Regression.h"
00025 #include "api/ts/ts.h"
00026 
00027 #include <arpa/inet.h>          /* For htonl */
00028 #include "P_Net.h"
00029 #include <records/I_RecHttp.h>
00030 
00031 #define SDBG_TAG "SockServer"
00032 #define CDBG_TAG "SockClient"
00033 
00034 #define IP(a,b,c,d) htonl((a) << 24 | (b) << 16 | (c) << 8 | (d))
00035 
00036 #define SET_TEST_HANDLER(_d, _s) {_d = _s;}
00037 
00038 #define MAGIC_ALIVE 0xfeedbaba
00039 #define MAGIC_DEAD  0xdeadbeef
00040 
00041 #define SYNSERVER_LISTEN_PORT  3300
00042 
00043 #define PROXY_CONFIG_NAME_HTTP_PORT "proxy.config.http.server_port"
00044 #define PROXY_HTTP_DEFAULT_PORT 8080
00045 
00046 #define REQUEST_MAX_SIZE  4095
00047 #define RESPONSE_MAX_SIZE 4095
00048 
00049 #define HTTP_REQUEST_END "\r\n\r\n"
00050 
00051 // each request/response includes an identifier as a Mime field
00052 #define X_REQUEST_ID  "X-Request-ID"
00053 #define X_RESPONSE_ID "X-Response-ID"
00054 
00055 #define ERROR_BODY "TESTING ERROR PAGE"
00056 #define TRANSFORM_APPEND_STRING "This is a transformed response"
00057 
00058 //////////////////////////////////////////////////////////////////////////////
00059 // STRUCTURES
00060 //////////////////////////////////////////////////////////////////////////////
00061 
00062 typedef int (*TxnHandler) (TSCont contp, TSEvent event, void *data);
00063 
00064 /* Server transaction structure */
00065 typedef struct
00066 {
00067   TSVConn vconn;
00068 
00069   TSVIO read_vio;
00070   TSIOBuffer req_buffer;
00071   TSIOBufferReader req_reader;
00072 
00073   TSVIO write_vio;
00074   TSIOBuffer resp_buffer;
00075   TSIOBufferReader resp_reader;
00076 
00077   char request[REQUEST_MAX_SIZE + 1];
00078   int request_len;
00079 
00080   TxnHandler current_handler;
00081   unsigned int magic;
00082 } ServerTxn;
00083 
00084 /* Server structure */
00085 typedef struct
00086 {
00087   int accept_port;
00088   TSAction accept_action;
00089   TSCont accept_cont;
00090   unsigned int magic;
00091 } SocketServer;
00092 
00093 typedef enum
00094 {
00095   REQUEST_SUCCESS,
00096   REQUEST_INPROGRESS,
00097   REQUEST_FAILURE
00098 } RequestStatus;
00099 
00100 /* Client structure */
00101 typedef struct
00102 {
00103   TSVConn vconn;
00104 
00105   TSVIO read_vio;
00106   TSIOBuffer req_buffer;
00107   TSIOBufferReader req_reader;
00108 
00109   TSVIO write_vio;
00110   TSIOBuffer resp_buffer;
00111   TSIOBufferReader resp_reader;
00112 
00113   char *request;
00114   char response[RESPONSE_MAX_SIZE + 1];
00115   int response_len;
00116 
00117   RequestStatus status;
00118 
00119   int connect_port;
00120   int local_port;
00121   uint64_t connect_ip;
00122   TSAction connect_action;
00123 
00124   TxnHandler current_handler;
00125 
00126   unsigned int magic;
00127 } ClientTxn;
00128 
00129 
00130 //////////////////////////////////////////////////////////////////////////////
00131 // DECLARATIONS
00132 //////////////////////////////////////////////////////////////////////////////
00133 
00134 /* utility */
00135 static char *get_body_ptr(const char *request);
00136 static char *generate_request(int test_case);
00137 static char *generate_response(const char *request);
00138 static int get_request_id(TSHttpTxn txnp);
00139 
00140 
00141 /* client side */
00142 static ClientTxn *synclient_txn_create(void);
00143 static int synclient_txn_delete(ClientTxn * txn);
00144 static int synclient_txn_close(TSCont contp);
00145 static int synclient_txn_send_request(ClientTxn * txn, char *request);
00146 static int synclient_txn_send_request_to_vc(ClientTxn * txn, char *request, TSVConn vc);
00147 static int synclient_txn_read_response(TSCont contp);
00148 static int synclient_txn_read_response_handler(TSCont contp, TSEvent event, void *data);
00149 static int synclient_txn_write_request(TSCont contp);
00150 static int synclient_txn_write_request_handler(TSCont contp, TSEvent event, void *data);
00151 static int synclient_txn_connect_handler(TSCont contp, TSEvent event, void *data);
00152 static int synclient_txn_main_handler(TSCont contp, TSEvent event, void *data);
00153 
00154 /* Server side */
00155 SocketServer *synserver_create(int port);
00156 static int synserver_start(SocketServer * s);
00157 static int synserver_stop(SocketServer * s);
00158 static int synserver_delete(SocketServer * s);
00159 static int synserver_accept_handler(TSCont contp, TSEvent event, void *data);
00160 static int synserver_txn_close(TSCont contp);
00161 static int synserver_txn_write_response(TSCont contp);
00162 static int synserver_txn_write_response_handler(TSCont contp, TSEvent event, void *data);
00163 static int synserver_txn_read_request(TSCont contp);
00164 static int synserver_txn_read_request_handler(TSCont contp, TSEvent event, void *data);
00165 static int synserver_txn_main_handler(TSCont contp, TSEvent event, void *data);
00166 
00167 //////////////////////////////////////////////////////////////////////////////
00168 // REQUESTS/RESPONSES GENERATION
00169 //////////////////////////////////////////////////////////////////////////////
00170 
00171 static char *
00172 get_body_ptr(const char *request)
00173 {
00174   char *ptr = (char *) strstr((const char *) request, (const char *) "\r\n\r\n");
00175   return (ptr != NULL) ? (ptr + 4) : NULL;
00176 }
00177 
00178 
00179 /* Caller must free returned request */
00180 static char *
00181 generate_request(int test_case)
00182 {
00183 
00184 // We define request formats.
00185 // Each format has an X-Request-ID field that contains the id of the testcase
00186 #define HTTP_REQUEST_DEFAULT_FORMAT  "GET http://127.0.0.1:%d/default.html HTTP/1.0\r\n" \
00187                                      "X-Request-ID: %d\r\n" \
00188                                      "\r\n"
00189 
00190 #define HTTP_REQUEST_FORMAT1 "GET http://127.0.0.1:%d/format1.html HTTP/1.0\r\n" \
00191                              "X-Request-ID: %d\r\n" \
00192                              "\r\n"
00193 
00194 #define HTTP_REQUEST_FORMAT2 "GET http://127.0.0.1:%d/format2.html HTTP/1.0\r\n" \
00195                              "X-Request-ID: %d\r\n" \
00196                              "Content-Type: text/html\r\n" \
00197                              "\r\n"
00198 #define HTTP_REQUEST_FORMAT3 "GET http://127.0.0.1:%d/format3.html HTTP/1.0\r\n" \
00199                              "X-Request-ID: %d\r\n" \
00200                              "Response: Error\r\n" \
00201                              "\r\n"
00202 #define HTTP_REQUEST_FORMAT4 "GET http://127.0.0.1:%d/format4.html HTTP/1.0\r\n" \
00203                              "X-Request-ID: %d\r\n" \
00204                              "Request:%d\r\n" \
00205                              "\r\n"
00206 #define HTTP_REQUEST_FORMAT5 "GET http://127.0.0.1:%d/format5.html HTTP/1.0\r\n" \
00207                              "X-Request-ID: %d\r\n" \
00208                              "Request:%d\r\n" \
00209                              "\r\n"
00210 #define HTTP_REQUEST_FORMAT6 "GET http://127.0.0.1:%d/format.html HTTP/1.0\r\n" \
00211                              "X-Request-ID: %d\r\n" \
00212                              "Accept-Language: English\r\n" \
00213                              "\r\n"
00214 #define HTTP_REQUEST_FORMAT7 "GET http://127.0.0.1:%d/format.html HTTP/1.0\r\n" \
00215                              "X-Request-ID: %d\r\n" \
00216                              "Accept-Language: French\r\n" \
00217                              "\r\n"
00218 #define HTTP_REQUEST_FORMAT8 "GET http://127.0.0.1:%d/format.html HTTP/1.0\r\n" \
00219                              "X-Request-ID: %d\r\n" \
00220                              "Accept-Language: English,French\r\n" \
00221                              "\r\n"
00222 #define HTTP_REQUEST_FORMAT9 "GET http://trafficserver.apache.org/format9.html HTTP/1.0\r\n" \
00223                              "X-Request-ID: %d\r\n" \
00224                              "\r\n"
00225 #define HTTP_REQUEST_FORMAT10 "GET http://trafficserver.apache.org/format10.html HTTP/1.0\r\n" \
00226                               "X-Request-ID: %d\r\n" \
00227                               "\r\n"
00228 
00229   char *request = (char *) TSmalloc(REQUEST_MAX_SIZE + 1);
00230 
00231   switch (test_case) {
00232   case 1:
00233     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT1, SYNSERVER_LISTEN_PORT, test_case);
00234     break;
00235   case 2:
00236     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT2, SYNSERVER_LISTEN_PORT, test_case);
00237     break;
00238   case 3:
00239     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT3, SYNSERVER_LISTEN_PORT, test_case);
00240     break;
00241   case 4:
00242     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT4, SYNSERVER_LISTEN_PORT, test_case, 1);
00243     break;
00244   case 5:
00245     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT5, SYNSERVER_LISTEN_PORT, test_case, 2);
00246     break;
00247   case 6:
00248     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT6, SYNSERVER_LISTEN_PORT, test_case);
00249     break;
00250   case 7:
00251     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT7, SYNSERVER_LISTEN_PORT, test_case - 1);
00252     break;
00253   case 8:
00254     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT8, SYNSERVER_LISTEN_PORT, test_case - 2);
00255     break;
00256   case 9:
00257     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT9, test_case);
00258     break;
00259   case 10:
00260     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_FORMAT10, test_case);
00261     break;
00262   default:
00263     snprintf(request, REQUEST_MAX_SIZE + 1, HTTP_REQUEST_DEFAULT_FORMAT, SYNSERVER_LISTEN_PORT, test_case);
00264     break;
00265   }
00266 
00267   return request;
00268 }
00269 
00270 
00271 /* Caller must free returned response */
00272 static char *
00273 generate_response(const char *request)
00274 {
00275 // define format for response
00276 // Each response contains a field X-Response-ID that contains the id of the testcase
00277 #define HTTP_REQUEST_TESTCASE_FORMAT "GET %1024s HTTP/1.%d\r\n" \
00278                                      "X-Request-ID: %d\r\n"
00279 
00280 #define HTTP_RESPONSE_DEFAULT_FORMAT "HTTP/1.0 200 OK\r\n" \
00281                               "X-Response-ID: %d\r\n" \
00282                               "Cache-Control: max-age=86400\r\n" \
00283                               "Content-Type: text/html\r\n" \
00284                               "\r\n" \
00285                               "Default body"
00286 
00287 #define HTTP_RESPONSE_FORMAT1 "HTTP/1.0 200 OK\r\n" \
00288                               "X-Response-ID: %d\r\n" \
00289                               "Content-Type: text/html\r\n" \
00290                               "Cache-Control: no-cache\r\n" \
00291                               "\r\n" \
00292                               "Body for response 1"
00293 
00294 #define HTTP_RESPONSE_FORMAT2 "HTTP/1.0 200 OK\r\n" \
00295                               "X-Response-ID: %d\r\n" \
00296                               "Cache-Control: max-age=86400\r\n" \
00297                               "Content-Type: text/html\r\n" \
00298                               "\r\n" \
00299                               "Body for response 2"
00300 #define HTTP_RESPONSE_FORMAT4 "HTTP/1.0 200 OK\r\n" \
00301                               "X-Response-ID: %d\r\n" \
00302                               "Cache-Control: max-age=86400\r\n" \
00303                               "Content-Type: text/html\r\n" \
00304                               "\r\n" \
00305                               "Body for response 4"
00306 #define HTTP_RESPONSE_FORMAT5 "HTTP/1.0 200 OK\r\n" \
00307                               "X-Response-ID: %d\r\n" \
00308                               "Content-Type: text/html\r\n" \
00309                               "\r\n" \
00310                               "Body for response 5"
00311 #define HTTP_RESPONSE_FORMAT6 "HTTP/1.0 200 OK\r\n" \
00312                               "X-Response-ID: %d\r\n" \
00313                               "Cache-Control: max-age=86400\r\n" \
00314                               "Content-Language: English\r\n" \
00315                               "\r\n" \
00316                               "Body for response 6"
00317 #define HTTP_RESPONSE_FORMAT7 "HTTP/1.0 200 OK\r\n" \
00318                               "X-Response-ID: %d\r\n" \
00319                               "Cache-Control: max-age=86400\r\n" \
00320                               "Content-Language: French\r\n" \
00321                               "\r\n" \
00322                               "Body for response 7"
00323 
00324 #define HTTP_RESPONSE_FORMAT8 "HTTP/1.0 200 OK\r\n" \
00325                               "X-Response-ID: %d\r\n" \
00326                               "Cache-Control: max-age=86400\r\n" \
00327                               "Content-Language: French, English\r\n" \
00328                               "\r\n" \
00329                               "Body for response 8"
00330 
00331 #define HTTP_RESPONSE_FORMAT9 "HTTP/1.0 200 OK\r\n" \
00332                               "Cache-Control: max-age=86400\r\n" \
00333                               "X-Response-ID: %d\r\n" \
00334                               "\r\n" \
00335                               "Body for response 9"
00336 
00337 #define HTTP_RESPONSE_FORMAT10 "HTTP/1.0 200 OK\r\n" \
00338                               "Cache-Control: max-age=86400\r\n" \
00339                               "X-Response-ID: %d\r\n" \
00340                               "\r\n" \
00341                               "Body for response 10"
00342 
00343 
00344   int test_case, match, http_version;
00345 
00346   char *response = (char *) TSmalloc(RESPONSE_MAX_SIZE + 1);
00347   char url[1025];
00348 
00349   // coverity[secure_coding]
00350   match = sscanf(request, HTTP_REQUEST_TESTCASE_FORMAT, url, &http_version, &test_case);
00351   if (match == 3) {
00352     switch (test_case) {
00353     case 1:
00354       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT1, test_case);
00355       break;
00356     case 2:
00357       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT2, test_case);
00358       break;
00359     case 4:
00360       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT4, test_case);
00361       break;
00362     case 5:
00363       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT5, test_case);
00364       break;
00365     case 6:
00366       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT6, test_case);
00367       break;
00368     case 7:
00369       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT7, test_case);
00370       break;
00371     case 8:
00372       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT8, test_case);
00373       break;
00374     case 9:
00375       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT9, test_case);
00376       break;
00377     case 10:
00378       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_FORMAT10, test_case);
00379       break;
00380     default:
00381       snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_DEFAULT_FORMAT, test_case);
00382       break;
00383     }
00384   } else {
00385     /* Didin't recognize a testcase request. send the default response */
00386     snprintf(response, RESPONSE_MAX_SIZE + 1, HTTP_RESPONSE_DEFAULT_FORMAT, test_case);
00387   }
00388 
00389   return response;
00390 }
00391 
00392 
00393 // This routine can be called by tests, from the READ_REQUEST_HDR_HOOK
00394 // to figure out the id of a test message
00395 // Returns id/-1 in case of error
00396 static int
00397 get_request_id(TSHttpTxn txnp)
00398 {
00399   TSMBuffer bufp;
00400   TSMLoc hdr_loc, id_loc;
00401   int id = -1;
00402 
00403   if (TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
00404     return -1;
00405   }
00406 
00407   id_loc = TSMimeHdrFieldFind(bufp, hdr_loc, X_REQUEST_ID, -1);
00408   if (id_loc == TS_NULL_MLOC) {
00409     TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
00410     return -1;
00411   }
00412 
00413   id = TSMimeHdrFieldValueIntGet(bufp, hdr_loc, id_loc, 0);
00414 
00415   TSHandleMLocRelease(bufp, hdr_loc, id_loc);
00416   TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
00417   return id;
00418 }
00419 
00420 
00421 
00422 //////////////////////////////////////////////////////////////////////////////
00423 // SOCKET CLIENT
00424 //////////////////////////////////////////////////////////////////////////////
00425 
00426 static ClientTxn *
00427 synclient_txn_create(void)
00428 {
00429   HttpProxyPort* proxy_port;
00430   
00431   ClientTxn *txn = (ClientTxn *) TSmalloc(sizeof(ClientTxn));
00432   if (0 == (proxy_port = HttpProxyPort::findHttp(AF_INET)))
00433     txn->connect_port = PROXY_HTTP_DEFAULT_PORT;
00434   else
00435     txn->connect_port = proxy_port->m_port;
00436 
00437   txn->local_port = (int) 0;
00438   txn->connect_ip = IP(127, 0, 0, 1);
00439   txn->status = REQUEST_INPROGRESS;
00440   txn->request = NULL;
00441   txn->vconn = NULL;
00442   txn->req_buffer = NULL;
00443   txn->req_reader = NULL;
00444   txn->resp_buffer = NULL;
00445   txn->resp_reader = NULL;
00446   txn->magic = MAGIC_ALIVE;
00447   txn->connect_action = NULL;
00448 
00449   TSDebug(CDBG_TAG, "Connecting to proxy 127.0.0.1 on port %d", txn->connect_port);
00450   return txn;
00451 }
00452 
00453 static int
00454 synclient_txn_delete(ClientTxn * txn)
00455 {
00456   TSAssert(txn->magic == MAGIC_ALIVE);
00457   if (txn->connect_action && !TSActionDone(txn->connect_action)) {
00458     TSActionCancel(txn->connect_action);
00459     txn->connect_action = NULL;
00460   }
00461 
00462   ats_free(txn->request);
00463   txn->magic = MAGIC_DEAD;
00464   TSfree(txn);
00465   return 1;
00466 }
00467 
00468 static int
00469 synclient_txn_close(TSCont contp)
00470 {
00471   ClientTxn *txn = (ClientTxn *) TSContDataGet(contp);
00472   TSAssert(txn->magic == MAGIC_ALIVE);
00473 
00474   if (txn->vconn != NULL) {
00475     TSVConnClose(txn->vconn);
00476   }
00477   if (txn->req_buffer != NULL) {
00478     TSIOBufferDestroy(txn->req_buffer);
00479   }
00480   if (txn->resp_buffer != NULL) {
00481     TSIOBufferDestroy(txn->resp_buffer);
00482   }
00483 
00484   TSContDestroy(contp);
00485 
00486   TSDebug(CDBG_TAG, "Client Txn destroyed");
00487   return TS_EVENT_IMMEDIATE;
00488 }
00489 
00490 static int
00491 synclient_txn_send_request(ClientTxn * txn, char *request)
00492 {
00493   TSCont cont;
00494   sockaddr_in addr;
00495 
00496   TSAssert(txn->magic == MAGIC_ALIVE);
00497   txn->request = ats_strdup(request);
00498   SET_TEST_HANDLER(txn->current_handler, synclient_txn_connect_handler);
00499 
00500   cont = TSContCreate(synclient_txn_main_handler, TSMutexCreate());
00501   TSContDataSet(cont, txn);
00502   
00503   ats_ip4_set(&addr, txn->connect_ip, htons(txn->connect_port));
00504   TSNetConnect(cont, ats_ip_sa_cast(&addr));
00505   return 1;
00506 }
00507 
00508 /* This can be used to send a request to a specific VC */
00509 static int
00510 synclient_txn_send_request_to_vc(ClientTxn * txn, char *request, TSVConn vc)
00511 {
00512   TSCont cont;
00513   TSAssert(txn->magic == MAGIC_ALIVE);
00514   txn->request = ats_strdup(request);
00515   SET_TEST_HANDLER(txn->current_handler, synclient_txn_connect_handler);
00516 
00517   cont = TSContCreate(synclient_txn_main_handler, TSMutexCreate());
00518   TSContDataSet(cont, txn);
00519 
00520   TSContCall(cont, TS_EVENT_NET_CONNECT, vc);
00521   return 1;
00522 }
00523 
00524 
00525 static int
00526 synclient_txn_read_response(TSCont contp)
00527 {
00528   ClientTxn *txn = (ClientTxn *) TSContDataGet(contp);
00529   TSAssert(txn->magic == MAGIC_ALIVE);
00530 
00531   TSIOBufferBlock block = TSIOBufferReaderStart(txn->resp_reader);
00532   while (block != NULL) {
00533     int64_t blocklen;
00534     const char *blockptr = TSIOBufferBlockReadStart(block, txn->resp_reader, &blocklen);
00535 
00536     if (txn->response_len+blocklen <= RESPONSE_MAX_SIZE) {
00537       memcpy((char *) (txn->response + txn->response_len), blockptr, blocklen);
00538       txn->response_len += blocklen;
00539     } else {
00540       TSError("Error: Response length %" PRId64" > response buffer size %d", txn->response_len+blocklen, RESPONSE_MAX_SIZE);
00541     }
00542 
00543     block = TSIOBufferBlockNext(block);
00544   }
00545 
00546   txn->response[txn->response_len + 1] = '\0';
00547   TSDebug(CDBG_TAG, "Response = |%s|, req len = %d", txn->response, txn->response_len);
00548 
00549   return 1;
00550 }
00551 
00552 static int
00553 synclient_txn_read_response_handler(TSCont contp, TSEvent event, void * /* data ATS_UNUSED */)
00554 {
00555   ClientTxn *txn = (ClientTxn *) TSContDataGet(contp);
00556   TSAssert(txn->magic == MAGIC_ALIVE);
00557 
00558   int64_t avail;
00559 
00560   switch (event) {
00561   case TS_EVENT_VCONN_READ_READY:
00562   case TS_EVENT_VCONN_READ_COMPLETE:
00563     if (event == TS_EVENT_VCONN_READ_READY) {
00564       TSDebug(CDBG_TAG, "READ_READY");
00565     } else {
00566       TSDebug(CDBG_TAG, "READ_COMPLETE");
00567     }
00568 
00569     avail = TSIOBufferReaderAvail(txn->resp_reader);
00570     TSDebug(CDBG_TAG, "%" PRId64" bytes available in buffer", avail);
00571 
00572     if (avail > 0) {
00573       synclient_txn_read_response(contp);
00574       TSIOBufferReaderConsume(txn->resp_reader, avail);
00575     }
00576 
00577     TSVIOReenable(txn->read_vio);
00578     break;
00579 
00580   case TS_EVENT_VCONN_EOS:
00581     TSDebug(CDBG_TAG, "READ_EOS");
00582     // Connection closed. In HTTP/1.0 it means we're done for this request.
00583     txn->status = REQUEST_SUCCESS;
00584     return synclient_txn_close(contp);
00585     break;
00586 
00587   case TS_EVENT_ERROR:
00588     TSDebug(CDBG_TAG, "READ_ERROR");
00589     txn->status = REQUEST_FAILURE;
00590     return synclient_txn_close(contp);
00591     break;
00592 
00593   default:
00594     TSAssert(!"Invalid event");
00595     break;
00596   }
00597   return 1;
00598 }
00599 
00600 
00601 static int
00602 synclient_txn_write_request(TSCont contp)
00603 {
00604   ClientTxn *txn = (ClientTxn *) TSContDataGet(contp);
00605   TSAssert(txn->magic == MAGIC_ALIVE);
00606 
00607   TSIOBufferBlock block;
00608   char *ptr_block;
00609   int64_t len, ndone, ntodo, towrite, avail;
00610 
00611   len = strlen(txn->request);
00612 
00613   ndone = 0;
00614   ntodo = len;
00615   while (ntodo > 0) {
00616     block = TSIOBufferStart(txn->req_buffer);
00617     ptr_block = TSIOBufferBlockWriteStart(block, &avail);
00618     towrite = MIN(ntodo, avail);
00619     memcpy(ptr_block, txn->request + ndone, towrite);
00620     TSIOBufferProduce(txn->req_buffer, towrite);
00621     ntodo -= towrite;
00622     ndone += towrite;
00623   }
00624 
00625   /* Start writing the response */
00626   TSDebug(CDBG_TAG, "Writing |%s| (%" PRId64") bytes", txn->request, len);
00627   txn->write_vio = TSVConnWrite(txn->vconn, contp, txn->req_reader, len);
00628 
00629   return 1;
00630 }
00631 
00632 static int
00633 synclient_txn_write_request_handler(TSCont contp, TSEvent event, void * /* data ATS_UNUSED */)
00634 {
00635   ClientTxn *txn = (ClientTxn *) TSContDataGet(contp);
00636   TSAssert(txn->magic == MAGIC_ALIVE);
00637 
00638   switch (event) {
00639   case TS_EVENT_VCONN_WRITE_READY:
00640     TSDebug(CDBG_TAG, "WRITE_READY");
00641     TSVIOReenable(txn->write_vio);
00642     break;
00643 
00644   case TS_EVENT_VCONN_WRITE_COMPLETE:
00645     TSDebug(CDBG_TAG, "WRITE_COMPLETE");
00646     // Weird: synclient should not close the write part of vconn.
00647     // Otherwise some strangeness...
00648 
00649     /* Start reading */
00650     SET_TEST_HANDLER(txn->current_handler, synclient_txn_read_response_handler);
00651     txn->read_vio = TSVConnRead(txn->vconn, contp, txn->resp_buffer, INT64_MAX);
00652     break;
00653 
00654   case TS_EVENT_VCONN_EOS:
00655     TSDebug(CDBG_TAG, "WRITE_EOS");
00656     txn->status = REQUEST_FAILURE;
00657     return synclient_txn_close(contp);
00658     break;
00659 
00660   case TS_EVENT_ERROR:
00661     TSDebug(CDBG_TAG, "WRITE_ERROR");
00662     txn->status = REQUEST_FAILURE;
00663     return synclient_txn_close(contp);
00664     break;
00665 
00666   default:
00667     TSAssert(!"Invalid event");
00668     break;
00669   }
00670   return TS_EVENT_IMMEDIATE;
00671 }
00672 
00673 
00674 static int
00675 synclient_txn_connect_handler(TSCont contp, TSEvent event, void *data)
00676 {
00677   TSAssert((event == TS_EVENT_NET_CONNECT) || (event == TS_EVENT_NET_CONNECT_FAILED));
00678 
00679   ClientTxn *txn = (ClientTxn *) TSContDataGet(contp);
00680   TSAssert(txn->magic == MAGIC_ALIVE);
00681 
00682   if (event == TS_EVENT_NET_CONNECT) {
00683     TSDebug(CDBG_TAG, "NET_CONNECT");
00684 
00685     txn->req_buffer = TSIOBufferCreate();
00686     txn->req_reader = TSIOBufferReaderAlloc(txn->req_buffer);
00687     txn->resp_buffer = TSIOBufferCreate();
00688     txn->resp_reader = TSIOBufferReaderAlloc(txn->resp_buffer);
00689 
00690     txn->response[0] = '\0';
00691     txn->response_len = 0;
00692 
00693     txn->vconn = (TSVConn) data;
00694     txn->local_port = (int) ((NetVConnection *) data)->get_local_port();
00695 
00696     txn->write_vio = NULL;
00697     txn->read_vio = NULL;
00698 
00699     /* start writing */
00700     SET_TEST_HANDLER(txn->current_handler, synclient_txn_write_request_handler);
00701     synclient_txn_write_request(contp);
00702 
00703     return TS_EVENT_IMMEDIATE;
00704   } else {
00705     TSDebug(CDBG_TAG, "NET_CONNECT_FAILED");
00706     txn->status = REQUEST_FAILURE;
00707     synclient_txn_close(contp);
00708   }
00709 
00710   return TS_EVENT_IMMEDIATE;
00711 }
00712 
00713 
00714 static int
00715 synclient_txn_main_handler(TSCont contp, TSEvent event, void *data)
00716 {
00717   ClientTxn *txn = (ClientTxn *) TSContDataGet(contp);
00718   TSAssert(txn->magic == MAGIC_ALIVE);
00719 
00720   TxnHandler handler = txn->current_handler;
00721   return (*handler) (contp, event, data);
00722 }
00723 
00724 
00725 //////////////////////////////////////////////////////////////////////////////
00726 // SOCKET SERVER
00727 //////////////////////////////////////////////////////////////////////////////
00728 
00729 SocketServer *
00730 synserver_create(int port)
00731 {
00732   SocketServer *s = (SocketServer *) TSmalloc(sizeof(SocketServer));
00733   s->magic = MAGIC_ALIVE;
00734   s->accept_port = port;
00735   s->accept_action = NULL;
00736   s->accept_cont = TSContCreate(synserver_accept_handler, TSMutexCreate());
00737   TSContDataSet(s->accept_cont, s);
00738   return s;
00739 }
00740 
00741 static int
00742 synserver_start(SocketServer * s)
00743 {
00744   TSAssert(s->magic == MAGIC_ALIVE);
00745   s->accept_action = TSNetAccept(s->accept_cont, s->accept_port, -1, 0);
00746   return 1;
00747 }
00748 
00749 static int
00750 synserver_stop(SocketServer * s)
00751 {
00752   TSAssert(s->magic == MAGIC_ALIVE);
00753   if (s->accept_action && !TSActionDone(s->accept_action)) {
00754     TSActionCancel(s->accept_action);
00755     s->accept_action = NULL;
00756     TSDebug(SDBG_TAG, "Had to cancel action");
00757   }
00758   TSDebug(SDBG_TAG, "stopped");
00759   return 1;
00760 }
00761 
00762 static int
00763 synserver_delete(SocketServer * s)
00764 {
00765   TSAssert(s->magic == MAGIC_ALIVE);
00766   synserver_stop(s);
00767 
00768   if (s->accept_cont) {
00769     TSContDestroy(s->accept_cont);
00770     s->accept_cont = NULL;
00771     TSDebug(SDBG_TAG, "destroyed accept cont");
00772   }
00773   s->magic = MAGIC_DEAD;
00774   TSfree(s);
00775   TSDebug(SDBG_TAG, "deleted server");
00776   return 1;
00777 }
00778 
00779 static int
00780 synserver_accept_handler(TSCont contp, TSEvent event, void *data)
00781 {
00782   TSAssert((event == TS_EVENT_NET_ACCEPT) || (event == TS_EVENT_NET_ACCEPT_FAILED));
00783 
00784   SocketServer *s = (SocketServer *) TSContDataGet(contp);
00785   TSAssert(s->magic == MAGIC_ALIVE);
00786 
00787   if (event == TS_EVENT_NET_ACCEPT_FAILED) {
00788     Warning("Synserver failed to bind to port %d.", ntohs(s->accept_port));
00789     ink_release_assert(!"Synserver must be able to bind to a port, check system netstat");
00790     TSDebug(SDBG_TAG, "NET_ACCEPT_FAILED");
00791     return TS_EVENT_IMMEDIATE;
00792   }
00793 
00794   TSDebug(SDBG_TAG, "NET_ACCEPT");
00795 
00796   /* Create a new transaction */
00797   ServerTxn *txn = (ServerTxn *) TSmalloc(sizeof(ServerTxn));
00798   txn->magic = MAGIC_ALIVE;
00799 
00800   SET_TEST_HANDLER(txn->current_handler, synserver_txn_read_request_handler);
00801 
00802   TSCont txn_cont = TSContCreate(synserver_txn_main_handler, TSMutexCreate());
00803   TSContDataSet(txn_cont, txn);
00804 
00805   txn->req_buffer = TSIOBufferCreate();
00806   txn->req_reader = TSIOBufferReaderAlloc(txn->req_buffer);
00807 
00808   txn->resp_buffer = TSIOBufferCreate();
00809   txn->resp_reader = TSIOBufferReaderAlloc(txn->resp_buffer);
00810 
00811   txn->request[0] = '\0';
00812   txn->request_len = 0;
00813 
00814   txn->vconn = (TSVConn) data;
00815 
00816   txn->write_vio = NULL;
00817 
00818   /* start reading */
00819   txn->read_vio = TSVConnRead(txn->vconn, txn_cont, txn->req_buffer, INT64_MAX);
00820 
00821   return TS_EVENT_IMMEDIATE;
00822 }
00823 
00824 
00825 static int
00826 synserver_txn_close(TSCont contp)
00827 {
00828   ServerTxn *txn = (ServerTxn *) TSContDataGet(contp);
00829   TSAssert(txn->magic == MAGIC_ALIVE);
00830 
00831   if (txn->vconn != NULL) {
00832     TSVConnClose(txn->vconn);
00833   }
00834   if (txn->req_buffer) {
00835     TSIOBufferDestroy(txn->req_buffer);
00836   }
00837   if (txn->resp_buffer) {
00838     TSIOBufferDestroy(txn->resp_buffer);
00839   }
00840 
00841   txn->magic = MAGIC_DEAD;
00842   TSfree(txn);
00843   TSContDestroy(contp);
00844 
00845   TSDebug(SDBG_TAG, "Server Txn destroyed");
00846   return TS_EVENT_IMMEDIATE;
00847 }
00848 
00849 
00850 static int
00851 synserver_txn_write_response(TSCont contp)
00852 {
00853   ServerTxn *txn = (ServerTxn *) TSContDataGet(contp);
00854   TSAssert(txn->magic == MAGIC_ALIVE);
00855 
00856   SET_TEST_HANDLER(txn->current_handler, synserver_txn_write_response_handler);
00857 
00858   TSIOBufferBlock block;
00859   char *ptr_block;
00860   int64_t len, ndone, ntodo, towrite, avail;
00861   char *response;
00862 
00863   response = generate_response(txn->request);
00864   len = strlen(response);
00865 
00866   ndone = 0;
00867   ntodo = len;
00868   while (ntodo > 0) {
00869     block = TSIOBufferStart(txn->resp_buffer);
00870     ptr_block = TSIOBufferBlockWriteStart(block, &avail);
00871     towrite = MIN(ntodo, avail);
00872     memcpy(ptr_block, response + ndone, towrite);
00873     TSIOBufferProduce(txn->resp_buffer, towrite);
00874     ntodo -= towrite;
00875     ndone += towrite;
00876   }
00877 
00878   /* Start writing the response */
00879   TSDebug(SDBG_TAG, "Writing response: |%s| (%" PRId64") bytes)", response, len);
00880   txn->write_vio = TSVConnWrite(txn->vconn, contp, txn->resp_reader, len);
00881 
00882   /* Now that response is in IOBuffer, free up response */
00883   TSfree(response);
00884 
00885   return TS_EVENT_IMMEDIATE;
00886 }
00887 
00888 
00889 static int
00890 synserver_txn_write_response_handler(TSCont contp, TSEvent event, void * /* data ATS_UNUSED */)
00891 {
00892   ServerTxn *txn = (ServerTxn *) TSContDataGet(contp);
00893   TSAssert(txn->magic == MAGIC_ALIVE);
00894 
00895   switch (event) {
00896   case TS_EVENT_VCONN_WRITE_READY:
00897     TSDebug(SDBG_TAG, "WRITE_READY");
00898     TSVIOReenable(txn->write_vio);
00899     break;
00900 
00901   case TS_EVENT_VCONN_WRITE_COMPLETE:
00902     TSDebug(SDBG_TAG, "WRITE_COMPLETE");
00903     TSVConnShutdown(txn->vconn, 0, 1);
00904     return synserver_txn_close(contp);
00905     break;
00906 
00907   case TS_EVENT_VCONN_EOS:
00908     TSDebug(SDBG_TAG, "WRITE_EOS");
00909     return synserver_txn_close(contp);
00910     break;
00911 
00912   case TS_EVENT_ERROR:
00913     TSDebug(SDBG_TAG, "WRITE_ERROR");
00914     return synserver_txn_close(contp);
00915     break;
00916 
00917   default:
00918     TSAssert(!"Invalid event");
00919     break;
00920   }
00921   return TS_EVENT_IMMEDIATE;
00922 }
00923 
00924 
00925 static int
00926 synserver_txn_read_request(TSCont contp)
00927 {
00928   ServerTxn *txn = (ServerTxn *) TSContDataGet(contp);
00929   TSAssert(txn->magic == MAGIC_ALIVE);
00930 
00931   int end;
00932   TSIOBufferBlock block = TSIOBufferReaderStart(txn->req_reader);
00933 
00934   while (block != NULL) {
00935     int64_t blocklen;
00936     const char *blockptr = TSIOBufferBlockReadStart(block, txn->req_reader, &blocklen);
00937 
00938     if (txn->request_len+blocklen <= REQUEST_MAX_SIZE) {
00939       memcpy((char *) (txn->request + txn->request_len), blockptr, blocklen);
00940       txn->request_len += blocklen;
00941     } else {
00942       TSError("Error: Request length %" PRId64" > request buffer size %d", txn->request_len+blocklen, REQUEST_MAX_SIZE);
00943     }
00944 
00945     block = TSIOBufferBlockNext(block);
00946   }
00947 
00948   txn->request[txn->request_len] = '\0';
00949   TSDebug(SDBG_TAG, "Request = |%s|, req len = %d", txn->request, txn->request_len);
00950 
00951   end = (strstr(txn->request, HTTP_REQUEST_END) != NULL);
00952   TSDebug(SDBG_TAG, "End of request = %d", end);
00953 
00954   return end;
00955 }
00956 
00957 static int
00958 synserver_txn_read_request_handler(TSCont contp, TSEvent event, void * /* data ATS_UNUSED */)
00959 {
00960   ServerTxn *txn = (ServerTxn *) TSContDataGet(contp);
00961   TSAssert(txn->magic == MAGIC_ALIVE);
00962 
00963   int64_t avail;
00964   int end_of_request;
00965 
00966   switch (event) {
00967   case TS_EVENT_VCONN_READ_READY:
00968   case TS_EVENT_VCONN_READ_COMPLETE:
00969     TSDebug(SDBG_TAG, (event == TS_EVENT_VCONN_READ_READY) ? "READ_READY" : "READ_COMPLETE");
00970     avail = TSIOBufferReaderAvail(txn->req_reader);
00971     TSDebug(SDBG_TAG, "%" PRId64" bytes available in buffer", avail);
00972 
00973     if (avail > 0) {
00974       end_of_request = synserver_txn_read_request(contp);
00975       TSIOBufferReaderConsume(txn->req_reader, avail);
00976 
00977       if (end_of_request) {
00978         TSVConnShutdown(txn->vconn, 1, 0);
00979         return synserver_txn_write_response(contp);
00980       }
00981     }
00982 
00983     TSVIOReenable(txn->read_vio);
00984     break;
00985 
00986   case TS_EVENT_VCONN_EOS:
00987     TSDebug(SDBG_TAG, "READ_EOS");
00988     return synserver_txn_close(contp);
00989     break;
00990 
00991   case TS_EVENT_ERROR:
00992     TSDebug(SDBG_TAG, "READ_ERROR");
00993     return synserver_txn_close(contp);
00994     break;
00995 
00996   default:
00997     TSAssert(!"Invalid event");
00998     break;
00999   }
01000   return TS_EVENT_IMMEDIATE;
01001 }
01002 
01003 
01004 static int
01005 synserver_txn_main_handler(TSCont contp, TSEvent event, void *data)
01006 {
01007   ServerTxn *txn = (ServerTxn *) TSContDataGet(contp);
01008   TSAssert(txn->magic == MAGIC_ALIVE);
01009 
01010   TxnHandler handler = txn->current_handler;
01011   return (*handler) (contp, event, data);
01012 }
01013 

Generated by  doxygen 1.7.1