1/*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2020 Andy Green <andy@warmcat.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 *
24 * C++ classes for Secure Streams - file transaction
25 */
26
27#include <libwebsockets.hxx>
28
29#include <stdlib.h>
30#include <fcntl.h>
31#include <unistd.h>
32
33static lws_ss_state_return_t
34lssfile_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
35{
36	lssFile *lf = (lssFile *)userobj_to_lss(userobj);
37
38	return lf->write(buf, len, flags);
39}
40
41static lws_ss_state_return_t
42lssfile_tx(void *userobj, lws_ss_tx_ordinal_t ord,uint8_t *buf, size_t *len,
43   int *flags)
44{
45	/*
46	 * TODO: we don't know how to send things yet
47	 */
48	return LWSSSSRET_TX_DONT_SEND;
49}
50
51static lws_ss_state_return_t
52lssfile_state(void *userobj, void *h_src, lws_ss_constate_t state,
53      lws_ss_tx_ordinal_t ack)
54{
55	lssFile *lf = (lssFile *)userobj_to_lss(userobj);
56
57	lwsl_info("%s: state %s\n", __func__, lws_ss_state_name(state));
58
59	switch (state) {
60
61	/*
62	 * These reflect some kind of final disposition for the transaction,
63	 * that we want to report along with the completion.  If no other chance
64	 * we'll report DESTROYING
65	 */
66
67	case LWSSSCS_DESTROYING:
68	case LWSSSCS_ALL_RETRIES_FAILED:
69	case LWSSSCS_QOS_ACK_REMOTE:
70	case LWSSSCS_QOS_NACK_REMOTE:
71		lf->call_completion(state);
72
73		if (state == LWSSSCS_DESTROYING) {
74			/*
75			 * we get DESTROYING because we are already in the
76			 * middle of destroying the m_ss, unlink the C++ lss
77			 * from the ss handle so it won't recursively try to
78			 * destroy it
79			 */
80			lf->m_ss = NULL;
81			delete lf;
82		}
83
84		break;
85	}
86
87	return LWSSSSRET_OK;
88}
89
90lws_ss_state_return_t lssFile::write(const uint8_t *buf, size_t len, int flags)
91{
92	if (fd == LWS_INVALID_FILE) {
93
94		fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0640);
95		if (fd == LWS_INVALID_FILE)
96			return LWSSSSRET_DESTROY_ME;
97	}
98
99	if (::write(fd, buf, len) != len) {
100		close(fd);
101		fd = LWS_INVALID_FILE;
102
103		return LWSSSSRET_DESTROY_ME;
104	}
105
106	rxlen += len;
107
108	if (flags & LWSSS_FLAG_EOM) {
109		close(fd);
110		fd = LWS_INVALID_FILE;
111	}
112
113	return LWSSSSRET_OK;
114}
115
116lssFile::lssFile(lws_ctx_t ctx, std::string uri, std::string _path,
117		 lsscomp_t comp, bool _psh) :
118	 lss(ctx, uri, comp, _psh, lssfile_rx, lssfile_tx, lssfile_state)
119{
120	path = _path;
121	push = _psh;
122	fd = LWS_INVALID_FILE;
123}
124
125lssFile::~lssFile()
126{
127	if (fd == LWS_INVALID_FILE)
128		return;
129
130	close(fd);
131	fd = LWS_INVALID_FILE;
132}
133