mirror of
https://github.com/libretro/libretro-common.git
synced 2024-05-12 01:25:31 -04:00
Resync
This commit is contained in:
parent
86d5e4128c
commit
24a9210b56
|
@ -142,6 +142,7 @@ static enum IIRFilter str_to_type(const char *str)
|
|||
|
||||
return LPF; /* Fallback. */
|
||||
}
|
||||
#undef CHECK
|
||||
|
||||
static void make_poly_from_roots(
|
||||
const double *roots, unsigned num_roots, float *poly)
|
||||
|
|
|
@ -1346,9 +1346,9 @@ struct string_list* cdrom_get_available_drives(void)
|
|||
if (string_starts_with_size(dir_list->elems[i].data, "/dev/sg",
|
||||
STRLEN_CONST("/dev/sg")))
|
||||
{
|
||||
char drive_string[33];
|
||||
libretro_vfs_implementation_file *stream;
|
||||
char drive_model[32] = {0};
|
||||
char drive_string[33] = {0};
|
||||
union string_list_elem_attr attr = {0};
|
||||
int dev_index = 0;
|
||||
RFILE *file = filestream_open(
|
||||
|
@ -1380,9 +1380,9 @@ struct string_list* cdrom_get_available_drives(void)
|
|||
attr.i = dev_index;
|
||||
|
||||
if (!string_is_empty(drive_model))
|
||||
strlcat(drive_string, drive_model, sizeof(drive_string));
|
||||
strlcpy(drive_string, drive_model, sizeof(drive_string));
|
||||
else
|
||||
strlcat(drive_string, "Unknown Drive", sizeof(drive_string));
|
||||
strlcpy(drive_string, "Unknown Drive", sizeof(drive_string));
|
||||
|
||||
string_list_append(list, drive_string, attr);
|
||||
}
|
||||
|
@ -1462,10 +1462,10 @@ struct string_list* cdrom_get_available_drives(void)
|
|||
continue;
|
||||
|
||||
{
|
||||
char drive_string[33];
|
||||
libretro_vfs_implementation_file *stream;
|
||||
bool is_cdrom = false;
|
||||
char drive_model[32] = {0};
|
||||
char drive_string[33] = {0};
|
||||
union string_list_elem_attr attr = {0};
|
||||
RFILE *file = filestream_open(cdrom_path, RETRO_VFS_FILE_ACCESS_READ, 0);
|
||||
if (!file)
|
||||
|
@ -1481,9 +1481,9 @@ struct string_list* cdrom_get_available_drives(void)
|
|||
attr.i = path[0];
|
||||
|
||||
if (!string_is_empty(drive_model))
|
||||
strlcat(drive_string, drive_model, sizeof(drive_string));
|
||||
strlcpy(drive_string, drive_model, sizeof(drive_string));
|
||||
else
|
||||
strlcat(drive_string, "Unknown Drive", sizeof(drive_string));
|
||||
strlcpy(drive_string, "Unknown Drive", sizeof(drive_string));
|
||||
|
||||
string_list_append(list, drive_string, attr);
|
||||
}
|
||||
|
|
|
@ -366,8 +366,8 @@ static void config_file_get_realpath(char *s, size_t len,
|
|||
const char *home = getenv("HOME");
|
||||
if (home)
|
||||
{
|
||||
strlcpy(s, home, len);
|
||||
strlcat(s, path + 1, len);
|
||||
size_t _len = strlcpy(s, home, len);
|
||||
strlcpy(s + _len, path + 1, len - _len);
|
||||
}
|
||||
else
|
||||
strlcpy(s, path + 1, len);
|
||||
|
|
|
@ -328,14 +328,16 @@ bool path_is_compressed_file(const char* path)
|
|||
size_t fill_pathname(char *out_path, const char *in_path,
|
||||
const char *replace, size_t size)
|
||||
{
|
||||
size_t _len;
|
||||
char tmp_path[PATH_MAX_LENGTH];
|
||||
char *tok = NULL;
|
||||
strlcpy(tmp_path, in_path, sizeof(tmp_path));
|
||||
if ((tok = (char*)strrchr(path_basename(tmp_path), '.')))
|
||||
*tok = '\0';
|
||||
|
||||
strlcpy(out_path, tmp_path, size);
|
||||
return strlcat(out_path, replace, size);
|
||||
_len = strlcpy(out_path, tmp_path, size);
|
||||
_len += strlcpy(out_path + _len, replace, size - _len);
|
||||
return _len;
|
||||
}
|
||||
|
||||
|
||||
|
@ -381,12 +383,12 @@ void fill_pathname_slash(char *path, size_t size)
|
|||
return;
|
||||
}
|
||||
|
||||
path_len = strlen(path);
|
||||
path_len = strlen(path);
|
||||
/* Try to preserve slash type. */
|
||||
if (last_slash != (path + path_len - 1))
|
||||
{
|
||||
path[path_len] = last_slash[0];
|
||||
path[path_len+1] = '\0';
|
||||
path[ path_len] = last_slash[0];
|
||||
path[++path_len] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1000,14 +1002,14 @@ size_t fill_pathname_join_special(char *out_path,
|
|||
/* Try to preserve slash type. */
|
||||
if (last_slash != (out_path + len - 1))
|
||||
{
|
||||
out_path[len] = last_slash[0];
|
||||
out_path[len+1] = '\0';
|
||||
out_path[ len] = last_slash[0];
|
||||
out_path[++len] = '\0';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
out_path[len] = PATH_DEFAULT_SLASH_C();
|
||||
out_path[len+1] = '\0';
|
||||
out_path[ len] = PATH_DEFAULT_SLASH_C();
|
||||
out_path[++len] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1360,8 +1362,8 @@ void fill_pathname_application_path(char *s, size_t len)
|
|||
if (realpath(s, resolved_bundle_dir_buf))
|
||||
{
|
||||
size_t _len = strlcpy(s, resolved_bundle_dir_buf, len - 1);
|
||||
s[_len ] = '/';
|
||||
s[_len+1] = '\0';
|
||||
s[ _len] = '/';
|
||||
s[++_len] = '\0';
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -407,7 +407,7 @@ int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint
|
|||
decoder->huffnode[curcode].bits = curcode;
|
||||
|
||||
/* scale the weight by the current effective length, ensuring we don't go to 0 */
|
||||
decoder->huffnode[curcode].weight = ((uint64_t)decoder->datahisto[curcode]) * ((uint64_t)totalweight) / ((uint64_t)totaldata);
|
||||
decoder->huffnode[curcode].weight = (uint32_t)(((uint64_t)decoder->datahisto[curcode]) * ((uint64_t)totalweight) / ((uint64_t)totaldata));
|
||||
if (decoder->huffnode[curcode].weight == 0)
|
||||
decoder->huffnode[curcode].weight = 1;
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ static void *lzma_fast_alloc(void *p, size_t size)
|
|||
}
|
||||
|
||||
/* set the low bit of the size so we don't match next time */
|
||||
*addr = size | 1;
|
||||
*addr = (uint32_t)size | 1;
|
||||
|
||||
/* return aligned address */
|
||||
return (void*)vaddr;
|
||||
|
|
|
@ -1809,6 +1809,30 @@ enum retro_mod
|
|||
* even before the microphone driver is ready.
|
||||
*/
|
||||
|
||||
#define RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE 76
|
||||
/* const struct retro_netpacket_callback * --
|
||||
* When set, a core gains control over network packets sent and
|
||||
* received during a multiplayer session. This can be used to
|
||||
* emulate multiplayer games that were originally played on two
|
||||
* or more separate consoles or computers connected together.
|
||||
*
|
||||
* The frontend will take care of connecting players together,
|
||||
* and the core only needs to send the actual data as needed for
|
||||
* the emulation, while handshake and connection management happen
|
||||
* in the background.
|
||||
*
|
||||
* When two or more players are connected and this interface has
|
||||
* been set, time manipulation features (such as pausing, slow motion,
|
||||
* fast forward, rewinding, save state loading, etc.) are disabled to
|
||||
* avoid interrupting communication.
|
||||
*
|
||||
* Should be set in either retro_init or retro_load_game, but not both.
|
||||
*
|
||||
* When not set, a frontend may use state serialization-based
|
||||
* multiplayer, where a deterministic core supporting multiple
|
||||
* input devices does not need to take any action on its own.
|
||||
*/
|
||||
|
||||
/* VFS functionality */
|
||||
|
||||
/* File paths:
|
||||
|
@ -3030,6 +3054,100 @@ struct retro_disk_control_ext_callback
|
|||
retro_get_image_label_t get_image_label; /* Optional - may be NULL */
|
||||
};
|
||||
|
||||
/* Definitions for RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE.
|
||||
* A core can set it if sending and receiving custom network packets
|
||||
* during a multiplayer session is desired.
|
||||
*/
|
||||
|
||||
/* Netpacket flags for retro_netpacket_send_t */
|
||||
#define RETRO_NETPACKET_UNRELIABLE 0 /* Packet to be sent unreliable, depending on network quality it might not arrive. */
|
||||
#define RETRO_NETPACKET_RELIABLE (1 << 0) /* Reliable packets are guaranteed to arrive at the target in the order they were send. */
|
||||
#define RETRO_NETPACKET_UNSEQUENCED (1 << 1) /* Packet will not be sequenced with other packets and may arrive out of order. Cannot be set on reliable packets. */
|
||||
|
||||
/* Used by the core to send a packet to one or more connected players.
|
||||
* A single packet sent via this interface can contain up to 64 KB of data.
|
||||
*
|
||||
* The broadcast flag can be set to true to send to multiple connected clients.
|
||||
* In a broadcast, the client_id argument indicates 1 client NOT to send the
|
||||
* packet to (pass 0xFFFF to send to everyone). Otherwise, the client_id
|
||||
* argument indicates a single client to send the packet to.
|
||||
*
|
||||
* A frontend must support sending reliable packets (RETRO_NETPACKET_RELIABLE).
|
||||
* Unreliable packets might not be supported by the frontend, but the flags can
|
||||
* still be specified. Reliable transmission will be used instead.
|
||||
*
|
||||
* If this function is called passing NULL for buf, it will instead flush all
|
||||
* previously buffered outgoing packets and instantly read any incoming packets.
|
||||
* During such a call, retro_netpacket_receive_t and retro_netpacket_stop_t can
|
||||
* be called. The core can perform this in a loop to do a blocking read, i.e.,
|
||||
* wait for incoming data, but needs to handle stop getting called and also
|
||||
* give up after a short while to avoid freezing on a connection problem.
|
||||
*
|
||||
* This function is not guaranteed to be thread-safe and must be called during
|
||||
* retro_run or any of the netpacket callbacks passed with this interface.
|
||||
*/
|
||||
typedef void (RETRO_CALLCONV *retro_netpacket_send_t)(int flags, const void* buf, size_t len, uint16_t client_id, bool broadcast);
|
||||
|
||||
/* Called by the frontend to signify that a multiplayer session has started.
|
||||
* If client_id is 0 the local player is the host of the session and at this
|
||||
* point no other player has connected yet.
|
||||
*
|
||||
* If client_id is > 0 the local player is a client connected to a host and
|
||||
* at this point is already fully connected to the host.
|
||||
*
|
||||
* The core must store the retro_netpacket_send_t function pointer provided
|
||||
* here and use it whenever it wants to send a packet. This function pointer
|
||||
* remains valid until the frontend calls retro_netpacket_stop_t.
|
||||
*/
|
||||
typedef void (RETRO_CALLCONV *retro_netpacket_start_t)(uint16_t client_id, retro_netpacket_send_t send_fn);
|
||||
|
||||
/* Called by the frontend when a new packet arrives which has been sent from
|
||||
* another player with retro_netpacket_send_t. The client_id argument indicates
|
||||
* who has sent the packet.
|
||||
*/
|
||||
typedef void (RETRO_CALLCONV *retro_netpacket_receive_t)(const void* buf, size_t len, uint16_t client_id);
|
||||
|
||||
/* Called by the frontend when the multiplayer session has ended.
|
||||
* Once this gets called the retro_netpacket_send_t function pointer passed
|
||||
* to retro_netpacket_start_t will not be valid anymore.
|
||||
*/
|
||||
typedef void (RETRO_CALLCONV *retro_netpacket_stop_t)(void);
|
||||
|
||||
/* Called by the frontend every frame (between calls to retro_run while
|
||||
* updating the state of the multiplayer session.
|
||||
* This is a good place for the core to call retro_netpacket_send_t from.
|
||||
*/
|
||||
typedef void (RETRO_CALLCONV *retro_netpacket_poll_t)(void);
|
||||
|
||||
/* Called by the frontend when a new player connects to the hosted session.
|
||||
* This is only called on the host side, not for clients connected to the host.
|
||||
* If this function returns false, the newly connected player gets dropped.
|
||||
* This can be used for example to limit the number of players.
|
||||
*/
|
||||
typedef bool (RETRO_CALLCONV *retro_netpacket_connected_t)(uint16_t client_id);
|
||||
|
||||
/* Called by the frontend when a player leaves or disconnects from the hosted session.
|
||||
* This is only called on the host side, not for clients connected to the host.
|
||||
*/
|
||||
typedef void (RETRO_CALLCONV *retro_netpacket_disconnected_t)(uint16_t client_id);
|
||||
|
||||
/**
|
||||
* A callback interface for giving a core the ability to send and receive custom
|
||||
* network packets during a multiplayer session between two or more instances
|
||||
* of a libretro frontend.
|
||||
*
|
||||
* @see RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE
|
||||
*/
|
||||
struct retro_netpacket_callback
|
||||
{
|
||||
retro_netpacket_start_t start;
|
||||
retro_netpacket_receive_t receive;
|
||||
retro_netpacket_stop_t stop; /* Optional - may be NULL */
|
||||
retro_netpacket_poll_t poll; /* Optional - may be NULL */
|
||||
retro_netpacket_connected_t connected; /* Optional - may be NULL */
|
||||
retro_netpacket_disconnected_t disconnected; /* Optional - may be NULL */
|
||||
};
|
||||
|
||||
enum retro_pixel_format
|
||||
{
|
||||
/* 0RGB1555, native endian.
|
||||
|
|
|
@ -101,6 +101,26 @@ typedef int ssize_t;
|
|||
#define STRING_REP_UINT64 "%" PRIu64
|
||||
#define STRING_REP_USIZE "%" PRIuPTR
|
||||
|
||||
/* Wrap a declaration in RETRO_DEPRECATED() to produce a compiler warning when
|
||||
it's used. This is intended for developer machines, so it won't work on ancient
|
||||
or obscure compilers */
|
||||
#if defined(_MSC_VER)
|
||||
#if _MSC_VER >= 1400 /* Visual C 2005 or later */
|
||||
#define RETRO_DEPRECATED(decl) __declspec(deprecated) decl
|
||||
#endif
|
||||
#elif defined(__GNUC__)
|
||||
#if __GNUC__ >= 3 /* GCC 3 or later */
|
||||
#define RETRO_DEPRECATED(decl) decl __attribute__((deprecated))
|
||||
#endif
|
||||
#elif defined(__clang__)
|
||||
#if __clang_major__ >= 3 /* clang 3 or later */
|
||||
#define RETRO_DEPRECATED(decl) decl __attribute__((deprecated))
|
||||
#endif
|
||||
#endif
|
||||
#ifndef RETRO_DEPRECATED /* Unsupported compilers */
|
||||
#define RETRO_DEPRECATED(decl) decl
|
||||
#endif
|
||||
|
||||
/*
|
||||
I would like to see retro_inline.h moved in here; possibly boolean too.
|
||||
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
#include <psp2/kernel/threadmgr.h>
|
||||
#elif defined(_3DS)
|
||||
#include <3ds.h>
|
||||
#elif defined(EMSCRIPTEN)
|
||||
#include <emscripten/emscripten.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
@ -99,6 +101,8 @@ static int nanosleepDOS(const struct timespec *rqtp, struct timespec *rmtp)
|
|||
#define retro_sleep(msec) (usleep(1000 * (msec)))
|
||||
#elif defined(WIIU)
|
||||
#define retro_sleep(msec) (OSSleepTicks(ms_to_ticks((msec))))
|
||||
#elif defined(EMSCRIPTEN)
|
||||
#define retro_sleep(msec) (emscripten_sleep(msec))
|
||||
#else
|
||||
static INLINE void retro_sleep(unsigned msec)
|
||||
{
|
||||
|
|
|
@ -239,13 +239,9 @@ void file_list_set_alt_at_offset(file_list_t *list, size_t idx,
|
|||
{
|
||||
if (!list || !alt)
|
||||
return;
|
||||
|
||||
if (list->list[idx].alt)
|
||||
free(list->list[idx].alt);
|
||||
list->list[idx].alt = NULL;
|
||||
|
||||
if (alt)
|
||||
list->list[idx].alt = strdup(alt);
|
||||
list->list[idx].alt = strdup(alt);
|
||||
}
|
||||
|
||||
static int file_list_alt_cmp(const void *a_, const void *b_)
|
||||
|
|
|
@ -476,17 +476,18 @@ int string_list_find_elem(const struct string_list *list, const char *elem)
|
|||
bool string_list_find_elem_prefix(const struct string_list *list,
|
||||
const char *prefix, const char *elem)
|
||||
{
|
||||
size_t i;
|
||||
char prefixed[255];
|
||||
if (!list)
|
||||
return false;
|
||||
strlcpy(prefixed, prefix, sizeof(prefixed));
|
||||
strlcat(prefixed, elem, sizeof(prefixed));
|
||||
for (i = 0; i < list->size; i++)
|
||||
if (list)
|
||||
{
|
||||
if ( string_is_equal_noncase(list->elems[i].data, elem)
|
||||
|| string_is_equal_noncase(list->elems[i].data, prefixed))
|
||||
return true;
|
||||
size_t i;
|
||||
char prefixed[255];
|
||||
size_t _len = strlcpy(prefixed, prefix, sizeof(prefixed));
|
||||
strlcpy(prefixed + _len, elem, sizeof(prefixed) - _len);
|
||||
for (i = 0; i < list->size; i++)
|
||||
{
|
||||
if ( string_is_equal_noncase(list->elems[i].data, elem)
|
||||
|| string_is_equal_noncase(list->elems[i].data, prefixed))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -494,21 +495,19 @@ bool string_list_find_elem_prefix(const struct string_list *list,
|
|||
struct string_list *string_list_clone(const struct string_list *src)
|
||||
{
|
||||
size_t i;
|
||||
struct string_list_elem
|
||||
*elems = NULL;
|
||||
struct string_list
|
||||
*dest = (struct string_list*)
|
||||
struct string_list_elem *elems = NULL;
|
||||
struct string_list *dest = (struct string_list*)
|
||||
malloc(sizeof(struct string_list));
|
||||
|
||||
if (!dest)
|
||||
return NULL;
|
||||
|
||||
dest->elems = NULL;
|
||||
dest->size = src->size;
|
||||
dest->elems = NULL;
|
||||
dest->size = src->size;
|
||||
if (src->cap < dest->size)
|
||||
dest->cap = dest->size;
|
||||
dest->cap = dest->size;
|
||||
else
|
||||
dest->cap = src->cap;
|
||||
dest->cap = src->cap;
|
||||
|
||||
if (!(elems = (struct string_list_elem*)
|
||||
calloc(dest->cap, sizeof(struct string_list_elem))))
|
||||
|
@ -517,7 +516,7 @@ struct string_list *string_list_clone(const struct string_list *src)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
dest->elems = elems;
|
||||
dest->elems = elems;
|
||||
|
||||
for (i = 0; i < src->size; i++)
|
||||
{
|
||||
|
|
508
net/net_http.c
508
net/net_http.c
|
@ -389,16 +389,15 @@ void net_http_urlencode(char **dest, const char *source)
|
|||
void net_http_urlencode_full(char *dest,
|
||||
const char *source, size_t size)
|
||||
{
|
||||
size_t buf_pos;
|
||||
size_t tmp_len;
|
||||
size_t url_domain_len;
|
||||
char url_domain[256];
|
||||
char url_path[PATH_MAX_LENGTH];
|
||||
size_t buf_pos = 0;
|
||||
char *tmp = NULL;
|
||||
int count = 0;
|
||||
|
||||
strlcpy(url_path, source, sizeof(url_path));
|
||||
tmp = url_path;
|
||||
tmp = url_path;
|
||||
|
||||
while (count < 3 && tmp[0] != '\0')
|
||||
{
|
||||
|
@ -408,19 +407,19 @@ void net_http_urlencode_full(char *dest,
|
|||
}
|
||||
|
||||
tmp_len = strlen(tmp);
|
||||
url_domain_len = ((strlcpy(url_domain, source, tmp - url_path)) - tmp_len) - 1;
|
||||
buf_pos = ((strlcpy(url_domain, source, tmp - url_path)) - tmp_len) - 1;
|
||||
strlcpy(url_path,
|
||||
source + url_domain_len + 1,
|
||||
tmp_len + 1
|
||||
source + buf_pos + 1,
|
||||
tmp_len + 1
|
||||
);
|
||||
|
||||
tmp = NULL;
|
||||
net_http_urlencode(&tmp, url_path);
|
||||
buf_pos = strlcpy(dest, url_domain, size);
|
||||
dest[buf_pos] = '/';
|
||||
dest[buf_pos+1] = '\0';
|
||||
strlcat(dest, tmp, size);
|
||||
free (tmp);
|
||||
dest[ buf_pos] = '/';
|
||||
dest[++buf_pos] = '\0';
|
||||
strlcpy(dest + buf_pos, tmp, size - buf_pos);
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
static int net_http_new_socket(struct http_connection_t *conn)
|
||||
|
@ -717,16 +716,14 @@ const char* net_http_connection_method(struct http_connection_t* conn)
|
|||
struct http_t *net_http_new(struct http_connection_t *conn)
|
||||
{
|
||||
bool error = false;
|
||||
#ifdef HAVE_SSL
|
||||
if (!conn || (net_http_new_socket(conn)) < 0)
|
||||
return NULL;
|
||||
#else
|
||||
int fd = -1;
|
||||
struct http_t *state = NULL;
|
||||
|
||||
if (!conn)
|
||||
goto error;
|
||||
|
||||
if ((fd = net_http_new_socket(conn)) < 0)
|
||||
goto error;
|
||||
|
||||
error = false;
|
||||
if (!conn || (fd = net_http_new_socket(conn)) < 0)
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
/* This is a bit lazy, but it works. */
|
||||
if (conn->methodcopy)
|
||||
|
@ -755,12 +752,12 @@ struct http_t *net_http_new(struct http_connection_t *conn)
|
|||
if (conn->port)
|
||||
{
|
||||
char portstr[16];
|
||||
|
||||
portstr[0] = '\0';
|
||||
|
||||
snprintf(portstr, sizeof(portstr), ":%i", conn->port);
|
||||
net_http_send_str(&conn->sock_state, &error, portstr,
|
||||
strlen(portstr));
|
||||
size_t _len = 0;
|
||||
portstr[ _len] = ':';
|
||||
portstr[++_len] = '\0';
|
||||
_len += snprintf(portstr + _len, sizeof(portstr) - _len,
|
||||
"%i", conn->port);
|
||||
net_http_send_str(&conn->sock_state, &error, portstr, _len);
|
||||
}
|
||||
|
||||
net_http_send_str(&conn->sock_state, &error, "\r\n",
|
||||
|
@ -787,7 +784,7 @@ struct http_t *net_http_new(struct http_connection_t *conn)
|
|||
char *len_str = NULL;
|
||||
|
||||
if (!conn->postdatacopy)
|
||||
goto error;
|
||||
goto err;
|
||||
|
||||
if (!conn->headerscopy)
|
||||
{
|
||||
|
@ -843,49 +840,48 @@ struct http_t *net_http_new(struct http_connection_t *conn)
|
|||
net_http_send_str(&conn->sock_state, &error, conn->postdatacopy,
|
||||
strlen(conn->postdatacopy));
|
||||
|
||||
if (error)
|
||||
goto error;
|
||||
if (!error)
|
||||
{
|
||||
struct http_t *state = (struct http_t*)malloc(sizeof(struct http_t));
|
||||
state->sock_state = conn->sock_state;
|
||||
state->status = -1;
|
||||
state->data = NULL;
|
||||
state->part = P_HEADER_TOP;
|
||||
state->bodytype = T_FULL;
|
||||
state->error = false;
|
||||
state->pos = 0;
|
||||
state->len = 0;
|
||||
state->buflen = 512;
|
||||
|
||||
state = (struct http_t*)malloc(sizeof(struct http_t));
|
||||
state->sock_state = conn->sock_state;
|
||||
state->status = -1;
|
||||
state->data = NULL;
|
||||
state->part = P_HEADER_TOP;
|
||||
state->bodytype = T_FULL;
|
||||
state->error = false;
|
||||
state->pos = 0;
|
||||
state->len = 0;
|
||||
state->buflen = 512;
|
||||
if ((state->data = (char*)malloc(state->buflen)))
|
||||
return state;
|
||||
free(state);
|
||||
}
|
||||
|
||||
if (!(state->data = (char*)malloc(state->buflen)))
|
||||
goto error;
|
||||
|
||||
return state;
|
||||
|
||||
error:
|
||||
err:
|
||||
if (conn)
|
||||
{
|
||||
if (conn->methodcopy)
|
||||
free(conn->methodcopy);
|
||||
if (conn->contenttypecopy)
|
||||
free(conn->contenttypecopy);
|
||||
conn->methodcopy = NULL;
|
||||
conn->contenttypecopy = NULL;
|
||||
conn->postdatacopy = NULL;
|
||||
}
|
||||
conn->methodcopy = NULL;
|
||||
conn->contenttypecopy = NULL;
|
||||
conn->postdatacopy = NULL;
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
if (conn && conn->sock_state.ssl_ctx)
|
||||
{
|
||||
ssl_socket_close(conn->sock_state.ssl_ctx);
|
||||
ssl_socket_free(conn->sock_state.ssl_ctx);
|
||||
conn->sock_state.ssl_ctx = NULL;
|
||||
}
|
||||
#else
|
||||
if (fd >= 0)
|
||||
socket_close(fd);
|
||||
if (conn->sock_state.ssl_ctx)
|
||||
{
|
||||
ssl_socket_close(conn->sock_state.ssl_ctx);
|
||||
ssl_socket_free(conn->sock_state.ssl_ctx);
|
||||
conn->sock_state.ssl_ctx = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef HAVE_SSL
|
||||
socket_close(fd);
|
||||
#endif
|
||||
if (state)
|
||||
free(state);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -912,248 +908,238 @@ int net_http_fd(struct http_t *state)
|
|||
**/
|
||||
bool net_http_update(struct http_t *state, size_t* progress, size_t* total)
|
||||
{
|
||||
ssize_t newlen = 0;
|
||||
|
||||
if (!state)
|
||||
return true;
|
||||
if (state->error)
|
||||
{
|
||||
state->part = P_ERROR;
|
||||
state->status = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (state->part < P_BODY)
|
||||
if (state)
|
||||
{
|
||||
ssize_t newlen = 0;
|
||||
if (state->error)
|
||||
{
|
||||
state->part = P_ERROR;
|
||||
state->status = -1;
|
||||
return true;
|
||||
}
|
||||
goto error;
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
if (state->sock_state.ssl && state->sock_state.ssl_ctx)
|
||||
newlen = ssl_socket_receive_all_nonblocking(state->sock_state.ssl_ctx, &state->error,
|
||||
(uint8_t*)state->data + state->pos,
|
||||
state->buflen - state->pos);
|
||||
else
|
||||
#endif
|
||||
newlen = socket_receive_all_nonblocking(state->sock_state.fd, &state->error,
|
||||
(uint8_t*)state->data + state->pos,
|
||||
state->buflen - state->pos);
|
||||
|
||||
if (newlen < 0)
|
||||
{
|
||||
state->error = true;
|
||||
state->part = P_ERROR;
|
||||
state->status = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (state->pos + newlen >= state->buflen - 64)
|
||||
{
|
||||
state->buflen *= 2;
|
||||
state->data = (char*)realloc(state->data, state->buflen);
|
||||
}
|
||||
state->pos += newlen;
|
||||
|
||||
while (state->part < P_BODY)
|
||||
{
|
||||
char *dataend = state->data + state->pos;
|
||||
char *lineend = (char*)memchr(state->data, '\n', state->pos);
|
||||
|
||||
if (!lineend)
|
||||
break;
|
||||
|
||||
*lineend='\0';
|
||||
|
||||
if (lineend != state->data && lineend[-1]=='\r')
|
||||
lineend[-1]='\0';
|
||||
|
||||
if (state->part == P_HEADER_TOP)
|
||||
{
|
||||
if (strncmp(state->data, "HTTP/1.", STRLEN_CONST("HTTP/1."))!=0)
|
||||
{
|
||||
state->error = true;
|
||||
state->part = P_ERROR;
|
||||
state->status = -1;
|
||||
return true;
|
||||
}
|
||||
state->status = (int)strtoul(state->data
|
||||
+ STRLEN_CONST("HTTP/1.1 "), NULL, 10);
|
||||
state->part = P_HEADER;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string_starts_with_case_insensitive(state->data, "Content-Length:"))
|
||||
{
|
||||
char* ptr = state->data + STRLEN_CONST("Content-Length:");
|
||||
while (ISSPACE(*ptr))
|
||||
++ptr;
|
||||
|
||||
state->bodytype = T_LEN;
|
||||
state->len = strtol(ptr, NULL, 10);
|
||||
}
|
||||
if (string_is_equal_case_insensitive(state->data, "Transfer-Encoding: chunked"))
|
||||
state->bodytype = T_CHUNK;
|
||||
|
||||
/* TODO: save headers somewhere */
|
||||
if (state->data[0]=='\0')
|
||||
{
|
||||
state->part = P_BODY;
|
||||
if (state->bodytype == T_CHUNK)
|
||||
state->part = P_BODY_CHUNKLEN;
|
||||
}
|
||||
}
|
||||
|
||||
memmove(state->data, lineend + 1, dataend-(lineend+1));
|
||||
state->pos = (dataend-(lineend + 1));
|
||||
}
|
||||
|
||||
if (state->part >= P_BODY)
|
||||
{
|
||||
newlen = state->pos;
|
||||
state->pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (state->part >= P_BODY && state->part < P_DONE)
|
||||
{
|
||||
if (!newlen)
|
||||
if (state->part < P_BODY)
|
||||
{
|
||||
if (state->error)
|
||||
newlen = -1;
|
||||
else
|
||||
{
|
||||
goto error;
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
if (state->sock_state.ssl && state->sock_state.ssl_ctx)
|
||||
newlen = ssl_socket_receive_all_nonblocking(
|
||||
state->sock_state.ssl_ctx,
|
||||
&state->error,
|
||||
if (state->sock_state.ssl && state->sock_state.ssl_ctx)
|
||||
newlen = ssl_socket_receive_all_nonblocking(state->sock_state.ssl_ctx, &state->error,
|
||||
(uint8_t*)state->data + state->pos,
|
||||
state->buflen - state->pos);
|
||||
else
|
||||
else
|
||||
#endif
|
||||
newlen = socket_receive_all_nonblocking(
|
||||
state->sock_state.fd,
|
||||
&state->error,
|
||||
newlen = socket_receive_all_nonblocking(state->sock_state.fd, &state->error,
|
||||
(uint8_t*)state->data + state->pos,
|
||||
state->buflen - state->pos);
|
||||
}
|
||||
|
||||
if (newlen < 0)
|
||||
{
|
||||
if (state->bodytype != T_FULL)
|
||||
{
|
||||
state->error = true;
|
||||
state->part = P_ERROR;
|
||||
state->status = -1;
|
||||
return true;
|
||||
}
|
||||
state->part = P_DONE;
|
||||
state->data = (char*)realloc(state->data, state->len);
|
||||
newlen = 0;
|
||||
state->error = true;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (state->pos + newlen >= state->buflen - 64)
|
||||
{
|
||||
state->buflen *= 2;
|
||||
state->data = (char*)realloc(state->data, state->buflen);
|
||||
state->buflen *= 2;
|
||||
state->data = (char*)realloc(state->data, state->buflen);
|
||||
}
|
||||
}
|
||||
state->pos += newlen;
|
||||
|
||||
parse_again:
|
||||
if (state->bodytype == T_CHUNK)
|
||||
{
|
||||
if (state->part == P_BODY_CHUNKLEN)
|
||||
while (state->part < P_BODY)
|
||||
{
|
||||
state->pos += newlen;
|
||||
char *dataend = state->data + state->pos;
|
||||
char *lineend = (char*)memchr(state->data, '\n', state->pos);
|
||||
|
||||
if (state->pos - state->len >= 2)
|
||||
if (!lineend)
|
||||
break;
|
||||
|
||||
*lineend = '\0';
|
||||
|
||||
if (lineend != state->data && lineend[-1]=='\r')
|
||||
lineend[-1] = '\0';
|
||||
|
||||
if (state->part == P_HEADER_TOP)
|
||||
{
|
||||
/*
|
||||
* len=start of chunk including \r\n
|
||||
* pos=end of data
|
||||
*/
|
||||
|
||||
char *fullend = state->data + state->pos;
|
||||
char *end = (char*)memchr(state->data + state->len + 2, '\n',
|
||||
state->pos - state->len - 2);
|
||||
|
||||
if (end)
|
||||
if (strncmp(state->data, "HTTP/1.", STRLEN_CONST("HTTP/1."))!=0)
|
||||
{
|
||||
size_t chunklen = strtoul(state->data+state->len, NULL, 16);
|
||||
state->pos = state->len;
|
||||
end++;
|
||||
state->error = true;
|
||||
goto error;
|
||||
}
|
||||
state->status = (int)strtoul(state->data
|
||||
+ STRLEN_CONST("HTTP/1.1 "), NULL, 10);
|
||||
state->part = P_HEADER;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string_starts_with_case_insensitive(state->data, "Content-Length:"))
|
||||
{
|
||||
char* ptr = state->data + STRLEN_CONST("Content-Length:");
|
||||
while (ISSPACE(*ptr))
|
||||
++ptr;
|
||||
|
||||
memmove(state->data+state->len, end, fullend-end);
|
||||
|
||||
state->len = chunklen;
|
||||
newlen = (fullend - end);
|
||||
|
||||
/*
|
||||
len=num bytes
|
||||
newlen=unparsed bytes after \n
|
||||
pos=start of chunk including \r\n
|
||||
*/
|
||||
state->bodytype = T_LEN;
|
||||
state->len = strtol(ptr, NULL, 10);
|
||||
}
|
||||
if (string_is_equal_case_insensitive(state->data, "Transfer-Encoding: chunked"))
|
||||
state->bodytype = T_CHUNK;
|
||||
|
||||
/* TODO: save headers somewhere */
|
||||
if (state->data[0]=='\0')
|
||||
{
|
||||
state->part = P_BODY;
|
||||
if (state->len == 0)
|
||||
{
|
||||
state->part = P_DONE;
|
||||
state->len = state->pos;
|
||||
state->data = (char*)realloc(state->data, state->len);
|
||||
}
|
||||
goto parse_again;
|
||||
if (state->bodytype == T_CHUNK)
|
||||
state->part = P_BODY_CHUNKLEN;
|
||||
}
|
||||
}
|
||||
|
||||
memmove(state->data, lineend + 1, dataend-(lineend+1));
|
||||
state->pos = (dataend-(lineend + 1));
|
||||
}
|
||||
else if (state->part == P_BODY)
|
||||
|
||||
if (state->part >= P_BODY)
|
||||
{
|
||||
if ((size_t)newlen >= state->len)
|
||||
{
|
||||
state->pos += state->len;
|
||||
newlen -= state->len;
|
||||
state->len = state->pos;
|
||||
state->part = P_BODY_CHUNKLEN;
|
||||
goto parse_again;
|
||||
}
|
||||
state->pos += newlen;
|
||||
state->len -= newlen;
|
||||
newlen = state->pos;
|
||||
state->pos = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
if (state->part >= P_BODY && state->part < P_DONE)
|
||||
{
|
||||
state->pos += newlen;
|
||||
if (!newlen)
|
||||
{
|
||||
if (state->error)
|
||||
newlen = -1;
|
||||
else
|
||||
{
|
||||
#ifdef HAVE_SSL
|
||||
if (state->sock_state.ssl && state->sock_state.ssl_ctx)
|
||||
newlen = ssl_socket_receive_all_nonblocking(
|
||||
state->sock_state.ssl_ctx,
|
||||
&state->error,
|
||||
(uint8_t*)state->data + state->pos,
|
||||
state->buflen - state->pos);
|
||||
else
|
||||
#endif
|
||||
newlen = socket_receive_all_nonblocking(
|
||||
state->sock_state.fd,
|
||||
&state->error,
|
||||
(uint8_t*)state->data + state->pos,
|
||||
state->buflen - state->pos);
|
||||
}
|
||||
|
||||
if (state->pos > state->len)
|
||||
{
|
||||
state->error = true;
|
||||
state->part = P_ERROR;
|
||||
state->status = -1;
|
||||
return true;
|
||||
if (newlen < 0)
|
||||
{
|
||||
if (state->bodytype != T_FULL)
|
||||
{
|
||||
state->error = true;
|
||||
goto error;
|
||||
}
|
||||
state->part = P_DONE;
|
||||
state->data = (char*)realloc(state->data, state->len);
|
||||
newlen = 0;
|
||||
}
|
||||
|
||||
if (state->pos + newlen >= state->buflen - 64)
|
||||
{
|
||||
state->buflen *= 2;
|
||||
state->data = (char*)realloc(state->data, state->buflen);
|
||||
}
|
||||
}
|
||||
else if (state->pos == state->len)
|
||||
|
||||
parse_again:
|
||||
if (state->bodytype == T_CHUNK)
|
||||
{
|
||||
state->part = P_DONE;
|
||||
state->data = (char*)realloc(state->data, state->len);
|
||||
if (state->part == P_BODY_CHUNKLEN)
|
||||
{
|
||||
state->pos += newlen;
|
||||
|
||||
if (state->pos - state->len >= 2)
|
||||
{
|
||||
/*
|
||||
* len=start of chunk including \r\n
|
||||
* pos=end of data
|
||||
*/
|
||||
|
||||
char *fullend = state->data + state->pos;
|
||||
char *end = (char*)memchr(state->data + state->len + 2, '\n',
|
||||
state->pos - state->len - 2);
|
||||
|
||||
if (end)
|
||||
{
|
||||
size_t chunklen = strtoul(state->data+state->len, NULL, 16);
|
||||
state->pos = state->len;
|
||||
end++;
|
||||
|
||||
memmove(state->data+state->len, end, fullend-end);
|
||||
|
||||
state->len = chunklen;
|
||||
newlen = (fullend - end);
|
||||
|
||||
/*
|
||||
len=num bytes
|
||||
newlen=unparsed bytes after \n
|
||||
pos=start of chunk including \r\n
|
||||
*/
|
||||
|
||||
state->part = P_BODY;
|
||||
if (state->len == 0)
|
||||
{
|
||||
state->part = P_DONE;
|
||||
state->len = state->pos;
|
||||
state->data = (char*)realloc(state->data, state->len);
|
||||
}
|
||||
goto parse_again;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (state->part == P_BODY)
|
||||
{
|
||||
if ((size_t)newlen >= state->len)
|
||||
{
|
||||
state->pos += state->len;
|
||||
newlen -= state->len;
|
||||
state->len = state->pos;
|
||||
state->part = P_BODY_CHUNKLEN;
|
||||
goto parse_again;
|
||||
}
|
||||
state->pos += newlen;
|
||||
state->len -= newlen;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
state->pos += newlen;
|
||||
|
||||
if (state->pos > state->len)
|
||||
{
|
||||
state->error = true;
|
||||
goto error;
|
||||
}
|
||||
else if (state->pos == state->len)
|
||||
{
|
||||
state->part = P_DONE;
|
||||
state->data = (char*)realloc(state->data, state->len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (progress)
|
||||
*progress = state->pos;
|
||||
|
||||
if (total)
|
||||
{
|
||||
if (state->bodytype == T_LEN)
|
||||
*total = state->len;
|
||||
else
|
||||
*total = 0;
|
||||
}
|
||||
|
||||
if (state->part != P_DONE)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (progress)
|
||||
*progress = state->pos;
|
||||
|
||||
if (total)
|
||||
{
|
||||
if (state->bodytype == T_LEN)
|
||||
*total = state->len;
|
||||
else
|
||||
*total = 0;
|
||||
}
|
||||
|
||||
return (state->part == P_DONE);
|
||||
return true;
|
||||
error:
|
||||
state->part = P_ERROR;
|
||||
state->status = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue