drive_wapbox.c
资源名称:gateway-1.2.1 [点击查看]
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:15k
源码类别:
手机WAP编程
开发平台:
WINDOWS
- /* drive_wapbox.c - test wapbox through its bearerbox and http interfaces
- *
- * This program starts a wapbox and pretends to be both the bearer box
- * and the http server, so that it can test and benchmark the wapbox in
- * isolation.
- *
- * Richard Braakman
- */
- #include <string.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <errno.h>
- #include <signal.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include "gwlib/gwlib.h"
- #include "gw/msg.h"
- /* These should really be in a header file */
- enum wsp_types {
- Bad_PDU = -1,
- Connect_PDU = 0x01,
- ConnectReply_PDU = 0x02,
- Redirect_PDU = 0x03,
- Reply_PDU = 0x04,
- Disconnect_PDU = 0x05,
- Push_PDU = 0x06,
- ConfirmedPush_PDU = 0x07,
- Suspend_PDU = 0x08,
- Resume_PDU = 0x09,
- Get_PDU = 0x40,
- Options_PDU = 0x41,
- Head_PDU = 0x42,
- Delete_PDU = 0x43,
- Trace_PDU = 0x44,
- Post_PDU = 0x60,
- Put_PDU = 0x61
- };
- enum wtp_types {
- INVOKE = 1,
- RESULT = 2,
- ACK = 3
- };
- #define WSP_VERSION 0x10
- #define TIMEOUT 10.0 /* seconds */
- static long max_requests = 1;
- static long max_clients = 1;
- static long req_per_session = 1;
- static unsigned short http_port;
- static int wapbox_port = 30188;
- static Octstr *http_url = NULL;
- static int verbose_debug = 0;
- static int user_ack = 0;
- static long requests_complete = 0;
- static volatile sig_atomic_t dying = 0;
- enum WTP_type {
- TR_Invoke = 1,
- TR_Result = 2,
- TR_Ack = 3,
- TR_Abort = 4
- };
- struct client_status {
- /* True if we expect a WTP reply */
- int wtp_invoked;
- /* Transaction number for WTP level */
- int wtp_tid; /* current tid if wtp_invoked, else next tid to use */
- /* True if we're connected at the WSP level */
- /* Equal to 2 if we're trying to disconnect */
- int wsp_connected;
- /* -1 if we're not connected */
- long wsp_session_id;
- /* Number of successful page fetches this session */
- int pages_fetched;
- /* Source port to use for this client; should be unique. */
- unsigned short port;
- };
- typedef struct client_status Client;
- static Client *clients;
- List *ready_clients;
- static unsigned long get_varint(Octstr *pdu, int pos) {
- int c;
- long result = 0;
- do {
- c = octstr_get_char(pdu, pos++);
- result = (result << 7) | (c & 0x7f);
- } while (c & 0x80);
- return c;
- }
- static void http_thread(void *arg) {
- HTTPClient *client;
- Octstr *ip;
- Octstr *url;
- List *headers;
- Octstr *body;
- List *cgivars;
- Octstr *reply_body = octstr_create(
- "<?xml version="1.0"?>n"
- "<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"n"
- " "http://www.wapforum.org/DTD/wml_1.1.xml">n"
- "<wml>n"
- "<card id="main" title="Hello, world" newcontext="true">n"
- " <p>Hello, world.</p>n"
- "</card></wml>n");
- List *reply_headers = list_create();
- int port;
- port = *(int *) arg;
- gw_free(arg);
- list_append(reply_headers,
- octstr_create("Content-Type: text/vnd.wap.wml"));
- for (;!dying;) {
- client = http_accept_request(port, &ip, &url, &headers,
- &body, &cgivars);
- if (client == NULL)
- break;
- http_send_reply(client, HTTP_OK, reply_headers, reply_body);
- http_destroy_headers(headers);
- octstr_destroy(ip);
- octstr_destroy(url);
- octstr_destroy(body);
- http_destroy_cgiargs(cgivars);
- }
- octstr_destroy(reply_body);
- http_destroy_headers(reply_headers);
- }
- static long http_thread_id;
- static int start_http_thread(void) {
- unsigned short port;
- int *port_copy;
- int ssl = 0; /* indicate if SSL-enabled server should be used */
- for (port = 40000; port < 41000; port += 13) {
- if (http_open_port(port, ssl) != -1)
- break;
- }
- if (port == 41000)
- panic(0, "No ports available for http server");
- port_copy = gw_malloc(sizeof(*port_copy));
- *port_copy = port;
- http_thread_id = gwthread_create(http_thread, port_copy);
- if (http_thread_id == -1)
- panic(0, "Cannot start http thread");
- return port;
- }
- static Connection *start_wapbox(void) {
- int wap_socket;
- int wapbox;
- wap_socket = make_server_socket(wapbox_port, NULL);
- if (wap_socket < 0)
- panic(0, "Couldn't make wapbox portn");
- wapbox = accept(wap_socket, NULL, NULL);
- if (wapbox < 0)
- panic(errno, "Wapbox could not connectn");
- close(wap_socket);
- return conn_wrap_fd(wapbox, 0);
- }
- static void initialize_clients(void) {
- long i;
- ready_clients = list_create();
- clients = gw_malloc(max_clients * sizeof(*clients));
- for (i = 0; i < max_clients; i++) {
- clients[i].wtp_invoked = 0;
- clients[i].wtp_tid = 0;
- clients[i].wsp_connected = 0;
- clients[i].wsp_session_id = -1;
- clients[i].pages_fetched = 0;
- clients[i].port = i;
- list_append(ready_clients, &clients[i]);
- }
- }
- static void destroy_clients(void) {
- gw_free(clients);
- list_destroy(ready_clients, NULL);
- }
- static Client *find_client(unsigned short port) {
- /* It's easy and fast since we assign ports in linear order */
- if (port >= max_clients)
- return NULL;
- return clients + port;
- }
- static void client_done(Client *client) {
- requests_complete++;
- list_append(ready_clients, client);
- }
- static void increment_tid(Client *client) {
- if (client->wtp_tid == 0x7fff)
- client->wtp_tid = 0;
- else
- client->wtp_tid++;
- }
- /* Set the U/P flag on an Invoke PDU */
- static void set_user_ack(Octstr *pdu) {
- octstr_set_bits(pdu, 3 * 8 + 3, 1, 1);
- }
- static Octstr *wtp_invoke_create(int class) {
- Octstr *pdu;
- /* data describes a TR-Invoke PDU, with GTR=1 and TTR=1 (segmentation
- * not supported), and Transaction class 0 (which we replace below) */
- static unsigned char data[] = { 0x0e, 0x00, 0x00, 0x00 };
- gw_assert(class >= 0);
- gw_assert(class <= 2);
- pdu = octstr_create_from_data(data, sizeof(data));
- octstr_set_char(pdu, 3, class);
- if (user_ack)
- set_user_ack(pdu);
- return pdu;
- }
- static Octstr *wtp_ack_create(void) {
- static unsigned char data[] = { 0x18, 0x00, 0x00 };
- return octstr_create_from_data(data, sizeof(data));
- }
- static void add_wsp_connect(Octstr *pdu) {
- static unsigned char data[] = { Connect_PDU, WSP_VERSION, 68, 0x00,
- 0x03, 0x80, 0x90, 0x00, 0x03, 0x81, 0x90, 0x00,
- 0x02, 0x82, 0x30, 0x02, 0x83, 0x01, 0x02, 0x84,
- 0x01, 0x28, 0x85, 0x50, 0x58, 0x2d, 0x55, 0x50,
- 0x2d, 0x41, 0x47, 0x45, 0x54, 0x00, 0x51, 0x58,
- 0x2d, 0x55, 0x50, 0x2d, 0x47, 0x45, 0x54, 0x4e,
- 0x4f, 0x54, 0x49, 0x46, 0x59, 0x00, 0x70, 0x58,
- 0x2d, 0x55, 0x50, 0x2d, 0x41, 0x50, 0x4f, 0x53,
- 0x54, 0x00, 0x09, 0x86, 0x02, 0x78, 0x2d, 0x75,
- 0x70, 0x2d, 0x31, 0x00 };
- octstr_append_data(pdu, data, sizeof(data));
- }
- static void add_wsp_get(Octstr *pdu) {
- Octstr *urlbuf;
- octstr_append_char(pdu, Get_PDU);
- if (http_url) {
- octstr_append_uintvar(pdu, octstr_len(http_url));
- octstr_append(pdu, http_url);
- } else {
- urlbuf = octstr_format("http://localhost:%ld/hello.wml",
- (long) http_port);
- octstr_append_uintvar(pdu, octstr_len(urlbuf));
- octstr_append(pdu, urlbuf);
- octstr_destroy(urlbuf);
- }
- }
- static void add_wsp_disconnect(Octstr *pdu, long session_id) {
- octstr_append_char(pdu, Disconnect_PDU);
- octstr_append_uintvar(pdu, session_id);
- }
- static void set_tid(Octstr *pdu, int tid) {
- int c;
- /* Tid wraps at 15 bits. */
- tid &= 0x7fff;
- c = octstr_get_char(pdu, 1);
- c = (tid >> 8) | (c & 0x80);
- octstr_set_char(pdu, 1, c);
- octstr_set_char(pdu, 2, tid & 0xff);
- }
- static int get_tid(Octstr *pdu) {
- return octstr_get_bits(pdu, 8, 16);
- }
- static int wtp_type(Octstr *pdu) {
- return octstr_get_bits(pdu, 1, 4);
- }
- static Msg *wdp_create(Octstr *data, Client *client) {
- Msg *msg;
- msg = msg_create(wdp_datagram);
- msg->wdp_datagram.source_address = octstr_create("127.0.0.1");
- msg->wdp_datagram.source_port = client->port;
- msg->wdp_datagram.destination_address = octstr_create("127.0.0.1");
- msg->wdp_datagram.destination_port = 9201;
- msg->wdp_datagram.user_data = octstr_duplicate(data);
- return msg;
- }
- static void send_pdu(Octstr *pdu, Connection *boxc, Client *client) {
- Msg *msg;
- Octstr *data;
- if (verbose_debug) {
- debug("test", 0, "Sending:");
- octstr_dump(pdu, 0);
- }
- msg = wdp_create(pdu, client);
- data = msg_pack(msg);
- conn_write_withlen(boxc, data);
- octstr_destroy(data);
- msg_destroy(msg);
- }
- static void send_invoke_connect(Connection *boxc, Client *client) {
- Octstr *pdu;
- gw_assert(client != NULL);
- gw_assert(client->wtp_invoked == 0);
- gw_assert(client->wsp_connected == 0);
- pdu = wtp_invoke_create(2);
- set_tid(pdu, client->wtp_tid);
- add_wsp_connect(pdu);
- send_pdu(pdu, boxc, client);
- octstr_destroy(pdu);
- client->wtp_invoked = 1;
- }
- static void send_invoke_get(Connection *boxc, Client *client) {
- Octstr *pdu;
- gw_assert(client != NULL);
- gw_assert(client->wtp_invoked == 0);
- gw_assert(client->wsp_connected == 1);
- pdu = wtp_invoke_create(2);
- set_tid(pdu, client->wtp_tid);
- add_wsp_get(pdu);
- send_pdu(pdu, boxc, client);
- octstr_destroy(pdu);
- client->wtp_invoked = 1;
- }
- static void record_disconnect(Client *client) {
- client->wsp_connected = 0;
- client->wsp_session_id = -1;
- client->pages_fetched = 0;
- increment_tid(client);
- }
- static void send_invoke_disconnect(Connection *boxc, Client *client) {
- Octstr *pdu;
- gw_assert(client != NULL);
- gw_assert(client->wtp_invoked == 0);
- gw_assert(client->wsp_connected == 1);
- /* Kannel can't handle it as class 1 yet, so send class 0 */
- pdu = wtp_invoke_create(0);
- set_tid(pdu, client->wtp_tid);
- add_wsp_disconnect(pdu, client->wsp_session_id);
- send_pdu(pdu, boxc, client);
- octstr_destroy(pdu);
- record_disconnect(client);
- client_done(client);
- }
- static void handle_connect_reply(Connection *boxc, Client *client, Octstr *pdu) {
- Octstr *ack;
- gw_assert(client);
- gw_assert(client->wtp_invoked);
- gw_assert(!client->wsp_connected);
- if (octstr_get_char(pdu, 3) != ConnectReply_PDU) {
- error(0, "Unexpected CONNECT reply");
- octstr_dump(pdu, 0);
- return;
- }
- ack = wtp_ack_create();
- set_tid(ack, client->wtp_tid);
- send_pdu(ack, boxc, client);
- octstr_destroy(ack);
- client->wtp_invoked = 0;
- increment_tid(client);
- client->wsp_connected = 1;
- client->wsp_session_id = get_varint(pdu, 4);
- send_invoke_get(boxc, client);
- }
- static void handle_get_reply(Connection *boxc, Client *client, Octstr *pdu) {
- Octstr *ack;
- gw_assert(client);
- gw_assert(client->wtp_invoked);
- gw_assert(client->wsp_connected);
- if (octstr_get_char(pdu, 3) != Reply_PDU) {
- error(0, "Unexpected GET reply");
- octstr_dump(pdu, 0);
- return;
- }
- ack = wtp_ack_create();
- set_tid(ack, client->wtp_tid);
- send_pdu(ack, boxc, client);
- octstr_destroy(ack);
- client->wtp_invoked = 0;
- increment_tid(client);
- client->pages_fetched++;
- if (client->pages_fetched == req_per_session) {
- send_invoke_disconnect(boxc, client);
- } else {
- client_done(client);
- }
- }
- static void handle_reply(Connection *boxc, Msg *reply) {
- Client *client;
- Octstr *wtp;
- int type;
- int dumped = 0;
- gw_assert(reply != NULL);
- gw_assert(reply->type == wdp_datagram);
- client = find_client(reply->wdp_datagram.destination_port);
- if (client == NULL)
- panic(0, "got packet for nonexisting client %ld",
- (long) reply->wdp_datagram.destination_port);
- wtp = reply->wdp_datagram.user_data;
- type = wtp_type(wtp);
- if (verbose_debug) {
- debug("test", 0, "Received:");
- octstr_dump(wtp, 0);
- dumped = 1;
- }
- if (client->wtp_invoked == 0) {
- error(0, "Got packet for client that wasn't waiting");
- if (!dumped) {
- octstr_dump(wtp, 0);
- dumped = 1;
- }
- return;
- }
- /* Server should invert the MSB of the tid in its replies */
- if (get_tid(wtp) != (client->wtp_tid ^ 0x8000)) {
- error(0, "Got packet with wrong tid %d, expected %d.",
- get_tid(wtp), client->wtp_tid ^ 0x8000);
- if (!dumped) {
- octstr_dump(wtp, 0);
- dumped = 1;
- }
- return;
- }
- /* We're going to be stupid here, and assume that replies that
- * look vaguely like what we expect are actually what we wanted. */
- if (client->wsp_connected == 0 && type == RESULT) {
- handle_connect_reply(boxc, client, wtp);
- } else if (client->wsp_connected == 1 && type == RESULT) {
- handle_get_reply(boxc, client, wtp);
- } else if (client->wsp_connected == 2 && type == ACK) {
- record_disconnect(client);
- client_done(client);
- } else {
- error(0, "Got unexpected packet");
- if (!dumped) {
- octstr_dump(wtp, 0);
- dumped = 1;
- }
- }
- }
- static void start_request(Connection *boxc, Client *client) {
- gw_assert(client != NULL);
- gw_assert(client->wsp_connected != 2);
- gw_assert(client->wtp_invoked == 0);
- if (client->wsp_connected == 0) {
- send_invoke_connect(boxc, client);
- } else {
- send_invoke_get(boxc, client);
- }
- }
- static long run_requests(Connection *boxc) {
- int requests_sent;
- Octstr *data;
- Msg *msg;
- int ret;
- requests_sent = 0;
- requests_complete = 0;
- while (requests_complete < max_requests) {
- data = conn_read_withlen(boxc);
- if (!data) {
- Client *client;
- if (requests_sent < max_requests
- && (client = list_extract_first(ready_clients))) {
- start_request(boxc, client);
- requests_sent++;
- }
- ret = conn_wait(boxc, TIMEOUT);
- if (ret < 0 || conn_eof(boxc))
- panic(0, "Wapbox dead.");
- if (ret == 1)
- break; /* Timed out. */
- } else {
- msg = msg_unpack(data);
- if (!msg) {
- octstr_dump(data, 0);
- panic(0, "Received bad data from wapbox.");
- }
- if (msg->type == wdp_datagram)
- handle_reply(boxc, msg);
- msg_destroy(msg);
- }
- octstr_destroy(data);
- }
- if (requests_complete < max_requests)
- info(0, "Timeout. %ld requests unsatisfied.",
- max_requests - requests_complete);
- return requests_complete;
- }
- static void help(void) {
- info(0, "Usage: drive_wapbox [options...]n");
- info(0, " -r requests Stop after this many; default 1.");
- info(0, " -c clients # of concurrent clients; default 1.");
- info(0, " -w wapport Port wapbox should connect to; default 30188");
- info(0, " -u url Use this url instead of internal http server");
- info(0, " -g requests Number of requests per WSP session; default 1");
- info(0, " -U Set the User ack flag on all WTP transactions");
- }
- int main(int argc, char **argv) {
- int opt;
- struct timeval start, end;
- Connection *boxc;
- long completed;
- double run_time;
- gwlib_init();
- while ((opt = getopt(argc, argv, "hv:r:c:w:du:Ug:")) != EOF) {
- switch (opt) {
- case 'v':
- log_set_output_level(atoi(optarg));
- break;
- case 'r':
- max_requests = atol(optarg);
- break;
- case 'c':
- max_clients = atol(optarg);
- break;
- case 'w':
- wapbox_port = atoi(optarg);
- break;
- case 'u':
- http_url = octstr_create(optarg);
- break;
- case 'U':
- user_ack = 1;
- break;
- case 'h':
- help();
- exit(0);
- case 'd':
- verbose_debug = 1;
- break;
- case 'g':
- req_per_session = atoi(optarg);
- break;
- case '?':
- default:
- error(0, "Invalid option %c", opt);
- help();
- panic(0, "Stopping.");
- }
- }
- if (!http_url)
- http_port = start_http_thread();
- boxc = start_wapbox();
- initialize_clients();
- if (gettimeofday(&start, NULL) < 0)
- panic(errno, "gettimeofday failed");
- completed = run_requests(boxc);
- if (gettimeofday(&end, NULL) < 0)
- panic(errno, "gettimeofday failed");
- conn_destroy(boxc);
- run_time = end.tv_sec - start.tv_sec;
- run_time += (double) (end.tv_usec - start.tv_usec) / 1000000.0;
- /* We must have timed out. Don't count the waiting time. */
- if (completed < max_requests)
- run_time -= TIMEOUT;
- info(0, "%ld request%s in %0.1f seconds, %0.1f requests/s.",
- completed, completed != 1 ? "s" : "",
- run_time, max_requests / run_time);
- dying = 1;
- http_close_all_ports();
- if (!http_url)
- gwthread_join(http_thread_id);
- destroy_clients();
- octstr_destroy(http_url);
- gwlib_shutdown();
- return 0;
- }