3
A brief file description
5
@section license License
7
Licensed to the Apache Software Foundation (ASF) under one
8
or more contributor license agreements. See the NOTICE file
9
distributed with this work for additional information
10
regarding copyright ownership. The ASF licenses this file
11
to you under the Apache License, Version 2.0 (the
12
"License"); you may not use this file except in compliance
13
with the License. You may obtain a copy of the License at
15
http://www.apache.org/licenses/LICENSE-2.0
17
Unless required by applicable law or agreed to in writing, software
18
distributed under the License is distributed on an "AS IS" BASIS,
19
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
See the License for the specific language governing permissions and
21
limitations under the License.
24
/* http_connect_bridge.c - Test program for TSHttpConnect() interface.
25
* Listens on a port and forwards all traffic to http system
26
* allowing the use all existing test & load tools
36
#include <sys/types.h>
41
#define DEBUG_TAG "http_connect_bridge-dbg"
44
/**************************************************
45
Log macros for error code return verification
46
**************************************************/
47
#define PLUGIN_NAME "http_connect_bridge"
48
#define VALID_POINTER(X) ((X != NULL) && (X != TS_ERROR_PTR))
49
#define LOG_SET_FUNCTION_NAME(NAME) const char * FUNCTION_NAME = NAME
50
#define LOG_ERROR(API_NAME) { \
51
TSDebug(PLUGIN_NAME, "%s: %s %s %s File %s, line number %d", PLUGIN_NAME, API_NAME, "APIFAIL", \
52
FUNCTION_NAME, __FILE__, __LINE__); \
54
#define LOG_ERROR_NEG(API_NAME) { \
55
TSDebug(PLUGIN_NAME, "%s: %s %s %s File %s, line number %d", PLUGIN_NAME, API_NAME, "NEGAPIFAIL", \
56
FUNCTION_NAME, __FILE__, __LINE__); \
58
#define LOG_ERROR_AND_RETURN(API_NAME) { \
59
LOG_ERROR(API_NAME); \
62
#define LOG_ERROR_AND_CLEANUP(API_NAME) { \
63
LOG_ERROR(API_NAME); \
66
#define LOG_ERROR_AND_REENABLE(API_NAME) { \
67
LOG_ERROR(API_NAME); \
68
TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); \
71
/* Global variables */
72
TSAction *accept_action;
73
static int plugin_port = 2499;
74
static unsigned int plugin_ip = 0;
76
/* static char* doc_buf = NULL; */
77
/* static int doc_size; */
90
TSIOBuffer req_buffer;
91
TSIOBufferReader req_reader;
93
TSIOBuffer resp_buffer;
94
TSIOBufferReader resp_reader;
100
typedef struct pvc_state_t pvc_state;
103
pvc_cleanup(TSCont contp, pvc_state * my_state)
105
LOG_SET_FUNCTION_NAME("pvc_cleanup");
107
if (my_state->req_buffer) {
108
if (TSIOBufferDestroy(my_state->req_buffer) == TS_ERROR) {
109
LOG_ERROR("TSIOBufferDestroy");
111
my_state->req_buffer = NULL;
114
if (my_state->resp_buffer) {
115
if (TSIOBufferDestroy(my_state->resp_buffer) == TS_ERROR) {
116
LOG_ERROR("TSIOBufferDestroy");
118
my_state->resp_buffer = NULL;
122
if (TSContDestroy(contp) == TS_ERROR) {
123
LOG_ERROR("TSContDestroy");
128
pvc_check_done(TSCont contp, pvc_state * my_state)
130
LOG_SET_FUNCTION_NAME("pvc_check_done");
132
if (my_state->req_finished && my_state->resp_finished) {
133
if (TSVConnClose(my_state->http_vc) == TS_ERROR) {
134
LOG_ERROR("TSVConnClose");
136
if (TSVConnClose(my_state->net_vc) == TS_ERROR) {
137
LOG_ERROR("TSVConnClose");
139
pvc_cleanup(contp, my_state);
144
pvc_process_n_read(TSCont contp, TSEvent event, pvc_state * my_state)
146
LOG_SET_FUNCTION_NAME("pvc_process_n_read");
150
TSDebug(DEBUG_TAG, "plugin called: pvc_process_n_read with event %d", event);
153
case TS_EVENT_VCONN_READ_READY:
154
if (TSVIOReenable(my_state->h_write_vio) == TS_ERROR) {
155
LOG_ERROR("TSVIOReenable");
158
case TS_EVENT_VCONN_READ_COMPLETE:
159
case TS_EVENT_VCONN_EOS:
162
/* We're finished reading from the net vc */
163
int ndone = TSVIONDoneGet(my_state->n_read_vio);
166
if (ndone == TS_ERROR) {
167
LOG_ERROR("TSVIONDoneGet");
169
my_state->n_read_vio = NULL;
170
if (TSVIONBytesSet(my_state->h_write_vio, ndone) == TS_ERROR) {
171
LOG_ERROR("TSVIONBytesSet");
173
if (TSVConnShutdown(my_state->net_vc, 1, 0) == TS_ERROR) {
174
LOG_ERROR("TSVConnShutdown");
177
todo = TSVIONTodoGet(my_state->h_write_vio);
178
if (todo == TS_ERROR) {
179
LOG_ERROR("TSVIONTodoGet");
180
/* Error so set it to 0 to cleanup */
185
my_state->req_finished = 1;
186
if (TSVConnShutdown(my_state->http_vc, 0, 1) == TS_ERROR) {
187
LOG_ERROR("TSVConnShutdown");
189
pvc_check_done(contp, my_state);
191
if (TSVIOReenable(my_state->h_write_vio) == TS_ERROR) {
192
LOG_ERROR("TSVIOReenable");
199
TSReleaseAssert(!"Unexpected Event");
205
pvc_process_h_write(TSCont contp, TSEvent event, pvc_state * my_state)
207
LOG_SET_FUNCTION_NAME("pvc_process_h_write");
211
TSDebug(DEBUG_TAG, "plugin called: pvc_process_h_write with event %d", event);
214
case TS_EVENT_VCONN_WRITE_READY:
215
if (my_state->n_read_vio) {
216
if (TSVIOReenable(my_state->n_read_vio) == TS_ERROR) {
217
LOG_ERROR("TSVIOReenable");
222
if (my_state->n_read_vio) {
223
if (TSVConnShutdown(my_state->net_vc, 1, 0) == TS_ERROR) {
224
LOG_ERROR("TSVConnShutdown");
226
my_state->n_read_vio = NULL;
229
case TS_EVENT_VCONN_WRITE_COMPLETE:
230
/* We should have already shutdown read pvc side */
231
TSAssert(my_state->n_read_vio == NULL);
232
if (TSVConnShutdown(my_state->http_vc, 0, 1) == TS_ERROR) {
233
LOG_ERROR("TSVConnShutdown");
235
my_state->req_finished = 1;
236
pvc_check_done(contp, my_state);
239
TSReleaseAssert(!"Unexpected Event");
245
pvc_process_h_read(TSCont contp, TSEvent event, pvc_state * my_state)
247
LOG_SET_FUNCTION_NAME("pvc_process_h_read");
251
TSDebug(DEBUG_TAG, "plugin called: pvc_process_h_read with event %d", event);
254
case TS_EVENT_VCONN_READ_READY:
255
if (TSVIOReenable(my_state->n_write_vio) == TS_ERROR) {
256
LOG_ERROR("TSVIOReenable");
259
case TS_EVENT_VCONN_READ_COMPLETE:
260
case TS_EVENT_VCONN_EOS:
263
/* We're finished reading from the http vc */
267
if ((ndone = TSVIONDoneGet(my_state->h_read_vio)) == TS_ERROR) {
268
LOG_ERROR("TSVIONDoneGet");
271
my_state->h_read_vio = NULL;
272
if (TSVIONBytesSet(my_state->n_write_vio, ndone) == TS_ERROR) {
273
LOG_ERROR("TSVIONBytesSet");
275
if (TSVConnShutdown(my_state->http_vc, 1, 0) == TS_ERROR) {
276
LOG_ERROR("TSVConnShutdown");
279
todo = TSVIONTodoGet(my_state->n_write_vio);
280
if (todo == TS_ERROR) {
281
LOG_ERROR("TSVIONTodoGet");
282
/* Error so set it to 0 to cleanup */
287
my_state->resp_finished = 1;
288
if (TSVConnShutdown(my_state->net_vc, 0, 1) == TS_ERROR) {
289
LOG_ERROR("TSVConnShutdown");
291
pvc_check_done(contp, my_state);
293
if (TSVIOReenable(my_state->n_write_vio) == TS_ERROR) {
294
LOG_ERROR("TSVIOReenable");
301
TSReleaseAssert(!"Unexpected Event");
307
pvc_process_n_write(TSCont contp, TSEvent event, pvc_state * my_state)
309
LOG_SET_FUNCTION_NAME("pvc_process_n_write");
313
TSDebug(DEBUG_TAG, "plugin called: pvc_process_n_write with event %d", event);
316
case TS_EVENT_VCONN_WRITE_READY:
317
if (my_state->h_read_vio) {
318
if (TSVIOReenable(my_state->h_read_vio) == TS_ERROR) {
319
LOG_ERROR("TSVIOReenable");
324
if (my_state->h_read_vio) {
325
if (TSVConnShutdown(my_state->http_vc, 1, 0) == TS_ERROR) {
326
LOG_ERROR("TSVConnShutdown");
328
my_state->h_read_vio = NULL;
331
case TS_EVENT_VCONN_WRITE_COMPLETE:
332
/* We should have already shutdown read http side */
333
TSAssert(my_state->h_read_vio == NULL);
334
if (TSVConnShutdown(my_state->net_vc, 0, 1) == TS_ERROR) {
335
LOG_ERROR("TSVConnShutdown");
337
my_state->resp_finished = 1;
338
pvc_check_done(contp, my_state);
341
TSReleaseAssert(!"Unexpected Event");
347
pvc_plugin(TSCont contp, TSEvent event, void *edata)
349
LOG_SET_FUNCTION_NAME("pvc_plugin");
351
pvc_state *my_state = TSContDataGet(contp);
352
if (my_state == TS_ERROR_PTR) {
353
LOG_ERROR("TSContDataGet");
356
if (edata == my_state->h_read_vio) {
357
pvc_process_h_read(contp, event, my_state);
358
} else if (edata == my_state->h_write_vio) {
359
pvc_process_h_write(contp, event, my_state);
360
} else if (edata == my_state->n_read_vio) {
361
pvc_process_n_read(contp, event, my_state);
362
} else if (edata == my_state->n_write_vio) {
363
pvc_process_n_write(contp, event, my_state);
372
pvc_process_accept(TSVConn net_vc)
374
LOG_SET_FUNCTION_NAME("pvc_process_accept");
378
pvc_state *my_state = (pvc_state *) TSmalloc(sizeof(pvc_state));
379
unsigned int remote_ip;
381
mutexp = TSMutexCreate();
382
if (mutexp == TS_ERROR_PTR) {
383
LOG_ERROR("TSMutexCreate");
386
contp = TSContCreate(pvc_plugin, mutexp);
387
if (contp == TS_ERROR_PTR) {
388
LOG_ERROR("TSContCreate");
392
/* We need to lock the mutex to prevent I/O callbacks before
393
we set everything up */
394
if (TSMutexLock(mutexp) == TS_ERROR) {
395
LOG_ERROR("TSMutexLock");
398
my_state->net_vc = net_vc;
400
my_state->req_finished = 0;
401
my_state->resp_finished = 0;
403
my_state->req_buffer = TSIOBufferCreate();
404
my_state->req_reader = TSIOBufferReaderAlloc(my_state->req_buffer);
405
my_state->resp_buffer = TSIOBufferCreate();
406
my_state->resp_reader = TSIOBufferReaderAlloc(my_state->resp_buffer);
407
if ((my_state->req_buffer == TS_ERROR_PTR) || (my_state->req_reader == TS_ERROR_PTR) ||
408
(my_state->resp_buffer == TS_ERROR_PTR) || (my_state->resp_reader == TS_ERROR_PTR)) {
409
if (TSVConnClose(my_state->net_vc) == TS_ERROR) {
410
LOG_ERROR("TSVConnClose");
412
pvc_cleanup(contp, my_state);
413
LOG_ERROR_AND_CLEANUP("TSIOBufferCreate || TSIOBufferReaderAlloc");
416
if (TSNetVConnRemoteIPGet(my_state->net_vc, &remote_ip) == TS_ERROR) {
417
LOG_ERROR_AND_CLEANUP("TSNetVConnRemoteIPGet");
419
/* if (TSHttpConnect(ntohl(remote_ip), 0, &(my_state->http_vc)) == TS_ERROR) { */
420
/* LOG_ERROR_AND_CLEANUP("TSHttpConnect"); */
422
if (TSHttpConnect(remote_ip, plugin_port, &(my_state->http_vc)) == TS_ERROR) {
423
LOG_ERROR_AND_CLEANUP("TSHttpConnect");
426
/* Negative test for TSHttpConnect */
428
if (TSHttpConnect(plugin_ip, plugin_port, NULL) != TS_ERROR) {
429
LOG_ERROR_NEG("TSHttpConnect");
433
if (TSContDataSet(contp, my_state) == TS_ERROR) {
434
LOG_ERROR_AND_CLEANUP("TSHttpConnect");
437
my_state->h_read_vio = TSVConnRead(my_state->http_vc, contp, my_state->resp_buffer, INT64_MAX);
438
if (my_state->h_read_vio == TS_ERROR_PTR) {
439
LOG_ERROR_AND_CLEANUP("TSVConnRead");
441
my_state->h_write_vio = TSVConnWrite(my_state->http_vc, contp, my_state->req_reader, INT64_MAX);
442
if (my_state->h_write_vio == TS_ERROR_PTR) {
443
LOG_ERROR_AND_CLEANUP("TSVConnWrite");
446
my_state->n_read_vio = TSVConnRead(my_state->net_vc, contp, my_state->req_buffer, INT64_MAX);
447
if (my_state->n_read_vio == TS_ERROR_PTR) {
448
LOG_ERROR_AND_CLEANUP("TSVConnRead");
450
my_state->n_write_vio = TSVConnWrite(my_state->net_vc, contp, my_state->resp_reader, INT64_MAX);
451
if (my_state->n_write_vio == TS_ERROR_PTR) {
452
LOG_ERROR_AND_CLEANUP("TSVConnWrite");
456
if (TSMutexUnlock(mutexp) == TS_ERROR) {
457
LOG_ERROR("TSMutexUnlock");
463
accept_func(TSCont contp, TSEvent event, void *edata)
465
LOG_SET_FUNCTION_NAME("accept_func");
468
case TS_EVENT_NET_ACCEPT:
469
pvc_process_accept((TSVConn) edata);
472
case TS_EVENT_NET_ACCEPT_FAILED:
473
LOG_ERROR("TS_EVENT_NET_ACCEPT_FAILED");
474
TSError("Accept failed\n");
478
TSDebug(PLUGIN_NAME, "Bad event %d", event);
479
TSReleaseAssert(!"Unexpected event");
490
const char *ts_version = TSTrafficServerVersionGet();
494
int major_ts_version = 0;
495
int minor_ts_version = 0;
496
int patch_ts_version = 0;
498
if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &patch_ts_version) != 3) {
502
/* Since this is an TS-SDK 2.0 plugin, we need at
503
least Traffic Server 2.0 to run */
504
if (major_ts_version >= 2) {
513
TSPluginInit(int argc, const char *argv[])
515
LOG_SET_FUNCTION_NAME("TSPluginInit");
520
TSPluginRegistrationInfo info;
525
info.plugin_name = "test-pos";
526
info.vendor_name = "MyCompany";
527
info.support_email = "ts-api-support@MyCompany.com";
529
if (!TSPluginRegister(TS_SDK_VERSION_3_0, &info)) {
530
TSError("Plugin registration failed.\n");
533
if (!check_ts_version()) {
534
TSError("Plugin requires Traffic Server 3.0 or later\n");
539
TSError("No accept port specified\n");
542
port = atoi(argv[1]);
545
TSError("Bad port specified\n");
546
} else if (port <= 1024) {
547
TSError("Priveledged port specified\n");
550
mutex = TSMutexCreate();
551
if (mutex == TS_ERROR_PTR) {
552
LOG_ERROR("TSMutexCreate");
555
accept_cont = TSContCreate(accept_func, mutex);
556
if (accept_cont == TS_ERROR_PTR) {
557
LOG_ERROR("TSContCreate");
560
accept_action = TSNetAccept(accept_cont, port);
561
if (accept_action == TS_ERROR_PTR) {
562
LOG_ERROR("TSNetAccept");