1/*
2 * Hotspot 2.0 SPP server - standalone version
3 * Copyright (c) 2012-2013, Qualcomm Atheros, Inc.
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "includes.h"
10#include <time.h>
11#include <sqlite3.h>
12
13#include "common.h"
14#include "xml-utils.h"
15#include "spp_server.h"
16
17
18static void write_timestamp(FILE *f)
19{
20	time_t t;
21	struct tm *tm;
22
23	time(&t);
24	tm = localtime(&t);
25
26	fprintf(f, "%04u-%02u-%02u %02u:%02u:%02u ",
27		tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
28		tm->tm_hour, tm->tm_min, tm->tm_sec);
29}
30
31
32void debug_print(struct hs20_svc *ctx, int print, const char *fmt, ...)
33{
34	va_list ap;
35
36	if (ctx->debug_log == NULL)
37		return;
38
39	write_timestamp(ctx->debug_log);
40	va_start(ap, fmt);
41	vfprintf(ctx->debug_log, fmt, ap);
42	va_end(ap);
43
44	fprintf(ctx->debug_log, "\n");
45}
46
47
48void debug_dump_node(struct hs20_svc *ctx, const char *title, xml_node_t *node)
49{
50	char *str;
51
52	if (ctx->debug_log == NULL)
53		return;
54	str = xml_node_to_str(ctx->xml, node);
55	if (str == NULL)
56		return;
57
58	write_timestamp(ctx->debug_log);
59	fprintf(ctx->debug_log, "%s: '%s'\n", title, str);
60	os_free(str);
61}
62
63
64static int process(struct hs20_svc *ctx)
65{
66	int dmacc = 0;
67	xml_node_t *soap, *spp, *resp;
68	char *user, *realm, *post, *str;
69
70	ctx->addr = getenv("HS20ADDR");
71	if (ctx->addr)
72		debug_print(ctx, 1, "Connection from %s", ctx->addr);
73
74	user = getenv("HS20USER");
75	if (user && strlen(user) == 0)
76		user = NULL;
77	realm = getenv("HS20REALM");
78	if (realm == NULL) {
79		debug_print(ctx, 1, "HS20REALM not set");
80		return -1;
81	}
82	post = getenv("HS20POST");
83	if (post == NULL) {
84		debug_print(ctx, 1, "HS20POST not set");
85		return -1;
86	}
87
88	soap = xml_node_from_buf(ctx->xml, post);
89	if (soap == NULL) {
90		debug_print(ctx, 1, "Could not parse SOAP data");
91		return -1;
92	}
93	debug_dump_node(ctx, "Received SOAP message", soap);
94	spp = soap_get_body(ctx->xml, soap);
95	if (spp == NULL) {
96		debug_print(ctx, 1, "Could not get SPP message");
97		xml_node_free(ctx->xml, soap);
98		return -1;
99	}
100	debug_dump_node(ctx, "Received SPP message", spp);
101
102	resp = hs20_spp_server_process(ctx, spp, user, realm, dmacc);
103	xml_node_free(ctx->xml, soap);
104	if (resp == NULL && user == NULL) {
105		debug_print(ctx, 1, "Request HTTP authentication");
106		return 2; /* Request authentication */
107	}
108	if (resp == NULL) {
109		debug_print(ctx, 1, "No response");
110		return -1;
111	}
112
113	soap = soap_build_envelope(ctx->xml, resp);
114	if (soap == NULL) {
115		debug_print(ctx, 1, "SOAP envelope building failed");
116		return -1;
117	}
118	str = xml_node_to_str(ctx->xml, soap);
119	xml_node_free(ctx->xml, soap);
120	if (str == NULL) {
121		debug_print(ctx, 1, "Could not get node string");
122		return -1;
123	}
124	printf("%s", str);
125	free(str);
126
127	return 0;
128}
129
130
131static void usage(void)
132{
133	printf("usage:\n"
134	       "hs20_spp_server -r<root directory> [-f<debug log>]\n");
135}
136
137
138int main(int argc, char *argv[])
139{
140	struct hs20_svc ctx;
141	int ret;
142
143	os_memset(&ctx, 0, sizeof(ctx));
144	for (;;) {
145		int c = getopt(argc, argv, "f:r:");
146		if (c < 0)
147			break;
148		switch (c) {
149		case 'f':
150			if (ctx.debug_log)
151				break;
152			ctx.debug_log = fopen(optarg, "a");
153			if (ctx.debug_log == NULL) {
154				printf("Could not write to %s\n", optarg);
155				return -1;
156			}
157			break;
158		case 'r':
159			ctx.root_dir = optarg;
160			break;
161		default:
162			usage();
163			return -1;
164		}
165	}
166	if (ctx.root_dir == NULL) {
167		usage();
168		return -1;
169	}
170	ctx.xml = xml_node_init_ctx(&ctx, NULL);
171	if (ctx.xml == NULL)
172		return -1;
173	if (hs20_spp_server_init(&ctx) < 0) {
174		xml_node_deinit_ctx(ctx.xml);
175		return -1;
176	}
177
178	ret = process(&ctx);
179	debug_print(&ctx, 1, "process() --> %d", ret);
180
181	xml_node_deinit_ctx(ctx.xml);
182	hs20_spp_server_deinit(&ctx);
183	if (ctx.debug_log)
184		fclose(ctx.debug_log);
185
186	return ret;
187}
188