1*1c60b9acSAndroid Build Coastguard Worker /*
2*1c60b9acSAndroid Build Coastguard Worker  * S3 Put Object via Secure Streams minimal siv4 example
3*1c60b9acSAndroid Build Coastguard Worker  *
4*1c60b9acSAndroid Build Coastguard Worker  * Written in 2010-2020 by Andy Green <[email protected]>
5*1c60b9acSAndroid Build Coastguard Worker  *			   Amit Pachore <[email protected]>
6*1c60b9acSAndroid Build Coastguard Worker  *                         [email protected]
7*1c60b9acSAndroid Build Coastguard Worker  *
8*1c60b9acSAndroid Build Coastguard Worker  * This file is made available under the Creative Commons CC0 1.0
9*1c60b9acSAndroid Build Coastguard Worker  * Universal Public Domain Dedication.
10*1c60b9acSAndroid Build Coastguard Worker  */
11*1c60b9acSAndroid Build Coastguard Worker 
12*1c60b9acSAndroid Build Coastguard Worker #include <libwebsockets.h>
13*1c60b9acSAndroid Build Coastguard Worker #include <assert.h>
14*1c60b9acSAndroid Build Coastguard Worker #include "ss-s3-put.h"
15*1c60b9acSAndroid Build Coastguard Worker 
16*1c60b9acSAndroid Build Coastguard Worker extern int interrupted, bad;
17*1c60b9acSAndroid Build Coastguard Worker 
18*1c60b9acSAndroid Build Coastguard Worker static lws_ss_state_return_t
ss_s3_rx(void * userobj,const uint8_t * buf,size_t len,int flags)19*1c60b9acSAndroid Build Coastguard Worker ss_s3_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
20*1c60b9acSAndroid Build Coastguard Worker {
21*1c60b9acSAndroid Build Coastguard Worker 	// ss_s3_put_t *m = (ss_s3_put_t *)userobj;
22*1c60b9acSAndroid Build Coastguard Worker 
23*1c60b9acSAndroid Build Coastguard Worker 	if (flags & LWSSS_FLAG_EOM) {
24*1c60b9acSAndroid Build Coastguard Worker 		bad = 0;
25*1c60b9acSAndroid Build Coastguard Worker 		interrupted = 1; /* this example wants to exit after rx */
26*1c60b9acSAndroid Build Coastguard Worker 		return LWSSSSRET_DESTROY_ME;
27*1c60b9acSAndroid Build Coastguard Worker 	}
28*1c60b9acSAndroid Build Coastguard Worker 
29*1c60b9acSAndroid Build Coastguard Worker 	lwsl_user("%s: len %d, flags: %d\n", __func__, (int)len, flags);
30*1c60b9acSAndroid Build Coastguard Worker 	lwsl_hexdump_err(buf, len);
31*1c60b9acSAndroid Build Coastguard Worker 
32*1c60b9acSAndroid Build Coastguard Worker 	return LWSSSSRET_OK;
33*1c60b9acSAndroid Build Coastguard Worker }
34*1c60b9acSAndroid Build Coastguard Worker 
35*1c60b9acSAndroid Build Coastguard Worker static lws_ss_state_return_t
ss_s3_tx(void * userobj,lws_ss_tx_ordinal_t ord,uint8_t * buf,size_t * len,int * flags)36*1c60b9acSAndroid Build Coastguard Worker ss_s3_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
37*1c60b9acSAndroid Build Coastguard Worker 	 int *flags)
38*1c60b9acSAndroid Build Coastguard Worker {
39*1c60b9acSAndroid Build Coastguard Worker 	ss_s3_put_t *m = (ss_s3_put_t *)userobj;
40*1c60b9acSAndroid Build Coastguard Worker 
41*1c60b9acSAndroid Build Coastguard Worker 	if (!m->pos)
42*1c60b9acSAndroid Build Coastguard Worker 		*flags |= LWSSS_FLAG_SOM;
43*1c60b9acSAndroid Build Coastguard Worker 
44*1c60b9acSAndroid Build Coastguard Worker 	lwsl_user("%s: Send... total: %ld, pos: %ld\n", __func__,
45*1c60b9acSAndroid Build Coastguard Worker 		  (long)m->total, (long)m->pos);
46*1c60b9acSAndroid Build Coastguard Worker 
47*1c60b9acSAndroid Build Coastguard Worker 	if (*len > m->total - m->pos)
48*1c60b9acSAndroid Build Coastguard Worker 		*len = m->total - m->pos;
49*1c60b9acSAndroid Build Coastguard Worker 
50*1c60b9acSAndroid Build Coastguard Worker 	if (!*len)
51*1c60b9acSAndroid Build Coastguard Worker 		return LWSSSSRET_TX_DONT_SEND;
52*1c60b9acSAndroid Build Coastguard Worker 
53*1c60b9acSAndroid Build Coastguard Worker 	memcpy(buf, m->buf + m->pos, *len);
54*1c60b9acSAndroid Build Coastguard Worker 	m->pos += *len;
55*1c60b9acSAndroid Build Coastguard Worker 
56*1c60b9acSAndroid Build Coastguard Worker 	if (m->pos == m->total) {
57*1c60b9acSAndroid Build Coastguard Worker 		*flags |= LWSSS_FLAG_EOM;
58*1c60b9acSAndroid Build Coastguard Worker 		// m->pos = 0; /* we only want to send once */
59*1c60b9acSAndroid Build Coastguard Worker 	} else
60*1c60b9acSAndroid Build Coastguard Worker 		return lws_ss_request_tx(m->ss);
61*1c60b9acSAndroid Build Coastguard Worker 
62*1c60b9acSAndroid Build Coastguard Worker 	return LWSSSSRET_OK;
63*1c60b9acSAndroid Build Coastguard Worker }
64*1c60b9acSAndroid Build Coastguard Worker 
65*1c60b9acSAndroid Build Coastguard Worker static const char *awsService	= "s3",
66*1c60b9acSAndroid Build Coastguard Worker 		  *awsRegion	= "us-west-2",
67*1c60b9acSAndroid Build Coastguard Worker 		  *s3bucketName = "sstest2020",
68*1c60b9acSAndroid Build Coastguard Worker #if 1
69*1c60b9acSAndroid Build Coastguard Worker 		  *s3ObjName    = "SSs3upload2.txt";
70*1c60b9acSAndroid Build Coastguard Worker #else
71*1c60b9acSAndroid Build Coastguard Worker 		  /* test huge string sigv4 hashing works */
72*1c60b9acSAndroid Build Coastguard Worker 		  *s3ObjName	= "SSs3uploadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2.txt";
73*1c60b9acSAndroid Build Coastguard Worker #endif
74*1c60b9acSAndroid Build Coastguard Worker static char timestamp[32], payload_hash[65];
75*1c60b9acSAndroid Build Coastguard Worker static uint8_t jpl[1 * 1024];
76*1c60b9acSAndroid Build Coastguard Worker 
77*1c60b9acSAndroid Build Coastguard Worker 
78*1c60b9acSAndroid Build Coastguard Worker static void
create_payload(uint8_t * buf,size_t s)79*1c60b9acSAndroid Build Coastguard Worker create_payload(uint8_t *buf, size_t s)
80*1c60b9acSAndroid Build Coastguard Worker {
81*1c60b9acSAndroid Build Coastguard Worker 	int i;
82*1c60b9acSAndroid Build Coastguard Worker 
83*1c60b9acSAndroid Build Coastguard Worker 	for (i = 0; i < (int)s; i++)
84*1c60b9acSAndroid Build Coastguard Worker 		buf[i] = (uint8_t)('a' + i % 16);
85*1c60b9acSAndroid Build Coastguard Worker }
86*1c60b9acSAndroid Build Coastguard Worker 
set_time(char * t)87*1c60b9acSAndroid Build Coastguard Worker static void set_time(char *t)
88*1c60b9acSAndroid Build Coastguard Worker {
89*1c60b9acSAndroid Build Coastguard Worker 	/*20150830T123600Z*/
90*1c60b9acSAndroid Build Coastguard Worker 	time_t ti = time(NULL);
91*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_HAVE_GMTIME_R)
92*1c60b9acSAndroid Build Coastguard Worker 	struct tm tmp;
93*1c60b9acSAndroid Build Coastguard Worker 	struct tm *tm = gmtime_r(&ti, &tmp);
94*1c60b9acSAndroid Build Coastguard Worker #else
95*1c60b9acSAndroid Build Coastguard Worker 	struct tm *tm = gmtime(&ti);
96*1c60b9acSAndroid Build Coastguard Worker #endif
97*1c60b9acSAndroid Build Coastguard Worker 	assert(tm);
98*1c60b9acSAndroid Build Coastguard Worker 	strftime(t, 20, "%Y%m%dT%H%M%SZ", tm);
99*1c60b9acSAndroid Build Coastguard Worker }
100*1c60b9acSAndroid Build Coastguard Worker 
bin2hex(uint8_t * in,size_t len,char * out)101*1c60b9acSAndroid Build Coastguard Worker static void bin2hex(uint8_t *in, size_t len, char *out)
102*1c60b9acSAndroid Build Coastguard Worker {
103*1c60b9acSAndroid Build Coastguard Worker 	static const char *hex = "0123456789abcdef";
104*1c60b9acSAndroid Build Coastguard Worker 	size_t n;
105*1c60b9acSAndroid Build Coastguard Worker 
106*1c60b9acSAndroid Build Coastguard Worker 	for (n = 0; n < len; n++) {
107*1c60b9acSAndroid Build Coastguard Worker 		*out++ = hex[(in[n] >> 4) & 0xf];
108*1c60b9acSAndroid Build Coastguard Worker 		*out++ = hex[in[n] & 15];
109*1c60b9acSAndroid Build Coastguard Worker 	}
110*1c60b9acSAndroid Build Coastguard Worker 	*out = '\0';
111*1c60b9acSAndroid Build Coastguard Worker }
112*1c60b9acSAndroid Build Coastguard Worker 
sigv4_sha256hash_payload(uint8_t * payload,size_t len,char * hash)113*1c60b9acSAndroid Build Coastguard Worker static void sigv4_sha256hash_payload(uint8_t *payload, size_t len, char *hash)
114*1c60b9acSAndroid Build Coastguard Worker {
115*1c60b9acSAndroid Build Coastguard Worker 	struct lws_genhash_ctx hash_ctx;
116*1c60b9acSAndroid Build Coastguard Worker 	uint8_t hash_bin[32];
117*1c60b9acSAndroid Build Coastguard Worker 
118*1c60b9acSAndroid Build Coastguard Worker 	if (lws_genhash_init(&hash_ctx, LWS_GENHASH_TYPE_SHA256) ||
119*1c60b9acSAndroid Build Coastguard Worker 		/*
120*1c60b9acSAndroid Build Coastguard Worker 		 * If there is no payload, you must provide the hash of an
121*1c60b9acSAndroid Build Coastguard Worker 		 * empty string...
122*1c60b9acSAndroid Build Coastguard Worker 		 */
123*1c60b9acSAndroid Build Coastguard Worker 	    lws_genhash_update(&hash_ctx,
124*1c60b9acSAndroid Build Coastguard Worker 			       payload ? (void *)payload : (void *)"",
125*1c60b9acSAndroid Build Coastguard Worker 			       payload ? len : 0u) ||
126*1c60b9acSAndroid Build Coastguard Worker 	    lws_genhash_destroy(&hash_ctx, hash_bin))
127*1c60b9acSAndroid Build Coastguard Worker 	{
128*1c60b9acSAndroid Build Coastguard Worker 
129*1c60b9acSAndroid Build Coastguard Worker 		lws_genhash_destroy(&hash_ctx, NULL);
130*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s lws_genhash failed\n", __func__);
131*1c60b9acSAndroid Build Coastguard Worker 
132*1c60b9acSAndroid Build Coastguard Worker 		return;
133*1c60b9acSAndroid Build Coastguard Worker 	}
134*1c60b9acSAndroid Build Coastguard Worker 
135*1c60b9acSAndroid Build Coastguard Worker 	bin2hex(hash_bin, 32, hash);
136*1c60b9acSAndroid Build Coastguard Worker }
137*1c60b9acSAndroid Build Coastguard Worker 
138*1c60b9acSAndroid Build Coastguard Worker static lws_ss_state_return_t
ss_s3_state(void * userobj,void * sh,lws_ss_constate_t state,lws_ss_tx_ordinal_t ack)139*1c60b9acSAndroid Build Coastguard Worker ss_s3_state(void *userobj, void *sh, lws_ss_constate_t state,
140*1c60b9acSAndroid Build Coastguard Worker                     lws_ss_tx_ordinal_t ack)
141*1c60b9acSAndroid Build Coastguard Worker {
142*1c60b9acSAndroid Build Coastguard Worker 	ss_s3_put_t *m = (ss_s3_put_t *)userobj;
143*1c60b9acSAndroid Build Coastguard Worker 
144*1c60b9acSAndroid Build Coastguard Worker 	lwsl_user("%s: %s %s, ord 0x%x\n", __func__, lws_ss_tag(m->ss),
145*1c60b9acSAndroid Build Coastguard Worker 		  lws_ss_state_name((int)state), (unsigned int)ack);
146*1c60b9acSAndroid Build Coastguard Worker 
147*1c60b9acSAndroid Build Coastguard Worker 	switch (state) {
148*1c60b9acSAndroid Build Coastguard Worker 	case LWSSSCS_CREATING:
149*1c60b9acSAndroid Build Coastguard Worker 		create_payload(jpl, sizeof(jpl));
150*1c60b9acSAndroid Build Coastguard Worker 		m->buf = (uint8_t *)jpl;
151*1c60b9acSAndroid Build Coastguard Worker 		m->total = sizeof(jpl);
152*1c60b9acSAndroid Build Coastguard Worker 
153*1c60b9acSAndroid Build Coastguard Worker 		sigv4_sha256hash_payload(m->buf, m->total, payload_hash);
154*1c60b9acSAndroid Build Coastguard Worker 		memset(timestamp, 0, sizeof(timestamp));
155*1c60b9acSAndroid Build Coastguard Worker 		set_time(timestamp);
156*1c60b9acSAndroid Build Coastguard Worker 
157*1c60b9acSAndroid Build Coastguard Worker 		if (lws_ss_set_metadata(m->ss, "s3bucket",
158*1c60b9acSAndroid Build Coastguard Worker 				    s3bucketName, strlen(s3bucketName)) ||
159*1c60b9acSAndroid Build Coastguard Worker 		   lws_ss_set_metadata(m->ss, "s3Obj",
160*1c60b9acSAndroid Build Coastguard Worker 				    s3ObjName, strlen(s3ObjName)) ||
161*1c60b9acSAndroid Build Coastguard Worker 		   lws_ss_set_metadata(m->ss, "ctype",
162*1c60b9acSAndroid Build Coastguard Worker 				    "text/plain", strlen("text/plain")) ||
163*1c60b9acSAndroid Build Coastguard Worker 		   lws_ss_set_metadata(m->ss, "region",
164*1c60b9acSAndroid Build Coastguard Worker 				    awsRegion, strlen(awsRegion)) ||
165*1c60b9acSAndroid Build Coastguard Worker 		   lws_ss_set_metadata(m->ss, "service",
166*1c60b9acSAndroid Build Coastguard Worker 				    awsService, strlen(awsService)) ||
167*1c60b9acSAndroid Build Coastguard Worker 		   lws_ss_set_metadata(m->ss, "xacl",
168*1c60b9acSAndroid Build Coastguard Worker 				    "bucket-owner-full-control",
169*1c60b9acSAndroid Build Coastguard Worker 				    strlen("bucket-owner-full-control")) ||
170*1c60b9acSAndroid Build Coastguard Worker 		   lws_ss_set_metadata(m->ss, "xcsha256",
171*1c60b9acSAndroid Build Coastguard Worker 				    payload_hash, strlen(payload_hash)) ||
172*1c60b9acSAndroid Build Coastguard Worker 		   lws_ss_set_metadata(m->ss, "xdate",
173*1c60b9acSAndroid Build Coastguard Worker 				    timestamp, strlen(timestamp)))
174*1c60b9acSAndroid Build Coastguard Worker 			return LWSSSSRET_DESTROY_ME;
175*1c60b9acSAndroid Build Coastguard Worker 
176*1c60b9acSAndroid Build Coastguard Worker 		return lws_ss_request_tx_len(m->ss, m->total);
177*1c60b9acSAndroid Build Coastguard Worker 
178*1c60b9acSAndroid Build Coastguard Worker 	case LWSSSCS_CONNECTED:
179*1c60b9acSAndroid Build Coastguard Worker 		return lws_ss_request_tx(m->ss);
180*1c60b9acSAndroid Build Coastguard Worker 
181*1c60b9acSAndroid Build Coastguard Worker 	case LWSSSCS_DISCONNECTED:
182*1c60b9acSAndroid Build Coastguard Worker 		return LWSSSSRET_DESTROY_ME;
183*1c60b9acSAndroid Build Coastguard Worker 
184*1c60b9acSAndroid Build Coastguard Worker 	case LWSSSCS_ALL_RETRIES_FAILED:
185*1c60b9acSAndroid Build Coastguard Worker 		/* if we're out of retries, we want to close the app and FAIL */
186*1c60b9acSAndroid Build Coastguard Worker 		bad = 1;
187*1c60b9acSAndroid Build Coastguard Worker 		return LWSSSSRET_DESTROY_ME;
188*1c60b9acSAndroid Build Coastguard Worker 
189*1c60b9acSAndroid Build Coastguard Worker 	case LWSSSCS_QOS_ACK_REMOTE:
190*1c60b9acSAndroid Build Coastguard Worker 		bad = 0;
191*1c60b9acSAndroid Build Coastguard Worker 		break;
192*1c60b9acSAndroid Build Coastguard Worker 
193*1c60b9acSAndroid Build Coastguard Worker 	case LWSSSCS_QOS_NACK_REMOTE:
194*1c60b9acSAndroid Build Coastguard Worker 		bad = 1;
195*1c60b9acSAndroid Build Coastguard Worker 		break;
196*1c60b9acSAndroid Build Coastguard Worker 
197*1c60b9acSAndroid Build Coastguard Worker 	case LWSSSCS_DESTROYING:
198*1c60b9acSAndroid Build Coastguard Worker 		interrupted = 1;
199*1c60b9acSAndroid Build Coastguard Worker 		break;
200*1c60b9acSAndroid Build Coastguard Worker 
201*1c60b9acSAndroid Build Coastguard Worker 	default:
202*1c60b9acSAndroid Build Coastguard Worker 		break;
203*1c60b9acSAndroid Build Coastguard Worker 	}
204*1c60b9acSAndroid Build Coastguard Worker 
205*1c60b9acSAndroid Build Coastguard Worker 	return 0;
206*1c60b9acSAndroid Build Coastguard Worker }
207*1c60b9acSAndroid Build Coastguard Worker 
208*1c60b9acSAndroid Build Coastguard Worker const lws_ss_info_t s3_ssi = {
209*1c60b9acSAndroid Build Coastguard Worker 	.handle_offset		 = offsetof(ss_s3_put_t, ss),
210*1c60b9acSAndroid Build Coastguard Worker 	.opaque_user_data_offset = offsetof(ss_s3_put_t, opaque_data),
211*1c60b9acSAndroid Build Coastguard Worker 	.rx			 = ss_s3_rx,
212*1c60b9acSAndroid Build Coastguard Worker 	.tx			 = ss_s3_tx,
213*1c60b9acSAndroid Build Coastguard Worker 	.state			 = ss_s3_state,
214*1c60b9acSAndroid Build Coastguard Worker 	.user_alloc		 = sizeof(ss_s3_put_t),
215*1c60b9acSAndroid Build Coastguard Worker 	.streamtype		 = "s3PutObj"
216*1c60b9acSAndroid Build Coastguard Worker };
217