| /*
* sai-builder com-warmcat-sai client protocol implementation
*
* Copyright (C) 2019 - 2026 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* This deals with POSTing artifacts to the related sai-server, using a secret
* that was passed to the builder as part of the task that was allocated
*/
#include <libwebsockets.h>
#include "b-private.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#ifdef _MSC_VER
/* don't complain about our use of open */
#pragma warning(disable:4996)
#endif
static lws_ss_state_return_t
saib_artifact_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
{
// sai_artifact_t *ap = (sai_artifact_t *)userobj;
return LWSSSSRET_OK;
}
static lws_ss_state_return_t
saib_artifact_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf,
size_t *len, int *flags)
{
sai_artifact_t *ap = (sai_artifact_t *)userobj;
lws_ss_state_return_t r;
lws_struct_serialize_t *js;
size_t w;
int n;
*flags = 0;
if (!ap->sent_json) {
*flags |= LWSSS_FLAG_SOM;
js = lws_struct_json_serialize_create(
lsm_schema_json_map_artifact,
LWS_ARRAY_SIZE(lsm_schema_json_map_artifact),
0, ap);
if (!js)
return LWSSSSRET_DESTROY_ME;
lws_struct_json_serialize(js, buf, *len, &w);
*len = w;
ap->sent_json = 1;
r = lws_ss_request_tx(ap->ss);
if (r)
return r;
lwsl_notice("%s: sent JSON %s\n", __func__, (const char *)buf);
return LWSSSSRET_OK;
}
if (ap->fd == -1) {
lwsl_info("%s: completion with fd = -1\n", __func__);
lws_ss_start_timeout(ap->ss, 5 * LWS_US_PER_SEC);
return LWSSSSRET_OK;
}
n = (int)read(ap->fd, buf,
#if defined(WIN32)
(unsigned int)
#endif
*len);
if (n < 0) {
lwsl_err("%s: artifact read failed: fd: %d, errno: %d\n",
__func__, ap->fd, errno);
*len = 0;
close(ap->fd);
ap->fd = -1;
return LWSSSSRET_DESTROY_ME;
}
if (!n) {
lwsl_notice("%s: file EOF\n", __func__);
return LWSSSSRET_TX_DONT_SEND; /* nothing to send */
}
ap->ofs = ap->ofs + (unsigned int)n;
lwsl_info("%s: %p: writing %d at +%llu / %llu (0x%02X)\n", __func__, ap->ss, n,
(unsigned long long)ap->ofs, (unsigned long long)ap->len, buf[0]);
*len = (size_t)n;
if (ap->ofs == ap->len) {
lwsl_notice("%s: reached logical end of artifact\n", __func__);
*flags |= LWSSS_FLAG_EOM;
close(ap->fd);
ap->fd = -1;
}
/* even if we finished, we want to come back to close */
return lws_ss_request_tx(ap->ss);
}
static lws_ss_state_return_t
saib_artifact_state(void *userobj, void *sh, lws_ss_constate_t state,
lws_ss_tx_ordinal_t ack)
{
sai_artifact_t *ap = (sai_artifact_t *)userobj;
struct stat s;
lwsl_info("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name(state),
(unsigned int)ack);
switch (state) {
case LWSSSCS_CREATING:
// lwsl_notice("%s: CREATING '%s'\n", __func__, ap->path);
ap->fd = open((const char *)ap->opaque_data, O_RDONLY
#if defined(WIN32)
/* ugh */
| _O_BINARY
#endif
);
if (ap->fd == -1)
return -1;
if (fstat(ap->fd, &s)) {
close(ap->fd);
ap->fd = -1;
return -1;
}
ap->len = (size_t)s.st_size;
break;
case LWSSSCS_DESTROYING:
// lwsl_notice("%s: LWSSSCS_DESTROYING\n", __func__);
/*
* We clean up everything about the upload here
*/
lws_dll2_remove(&ap->list);
if (ap->fd != -1) {
close(ap->fd);
ap->fd = -1;
}
unlink(ap->path);
ap->ns->count_artifacts--;
if (!ap->ns->count_artifacts) {
lwsl_notice("%s: last artifact completed, destroying ns now\n", __func__);
saib_task_destroy(ap->ns);
}
break;
case LWSSSCS_CONNECTED:
// lwsl_user("%s: CONNECTED: %p\n", __func__, ap->ss);
return lws_ss_request_tx_len(ap->ss, (unsigned long)ap->len);
case LWSSSCS_TIMEOUT:
lwsl_info("%s: timeout\n", __func__);
return LWSSSSRET_DESTROY_ME;
case LWSSSCS_DISCONNECTED:
// lwsl_notice("%s: LWSSSCS_DISCONNECTED\n", __func__);
/* don't retry */
return LWSSSSRET_DESTROY_ME;
default:
break;
}
return LWSSSSRET_OK;
}
const lws_ss_info_t ssi_sai_artifact = {
.handle_offset = offsetof(sai_artifact_t, ss),
.opaque_user_data_offset = offsetof(sai_artifact_t, opaque_data),
.rx = saib_artifact_rx,
.tx = saib_artifact_tx,
.state = saib_artifact_state,
.user_alloc = sizeof(sai_artifact_t),
.streamtype = "sai_artifact"
};
|