Commit beb96023 authored by Stewart Brodie's avatar Stewart Brodie
Browse files

Modified to use DebugLib

Detail:
  Since these modifications were made before customising the code as the
    LDAP module, there seems little point doing that all again, so this
    is the latest DebugLib-enabled version of the generic fetcher.
Admin:
  Module builds and runs (albeit not doing anything much)

Version 0.08. Tagged as 'Generic-0_08'
parent 591bf8c1
/* (0.07)
/* (0.08)
*
* This file is automatically maintained by srccommit, do not edit manually.
*
*/
#define Module_MajorVersion_CMHG 0.07
#define Module_MajorVersion_CMHG 0.08
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 05 May 2000
#define Module_Date_CMHG 20 Jul 2000
#define Module_MajorVersion "0.07"
#define Module_Version 7
#define Module_MajorVersion "0.08"
#define Module_Version 8
#define Module_MinorVersion ""
#define Module_Date "05 May 2000"
#define Module_Date "20 Jul 2000"
#define Module_FullVersion "0.07"
#define Module_ApplicationDate2 "20-Jul-00"
#define Module_ApplicationDate4 "20-Jul-2000"
#define Module_FullVersion "0.08"
......@@ -29,7 +29,7 @@
#include "commands.h"
#include "protocol.h"
#define INTERNAL_BUFFER_SIZE (2048)
#define INTERNAL_BUFFER_SIZE (2048)
/* This function initiates the sending of a command on the command socket.
* It needs to know the command to send (minus the \r\n) and the state into
......@@ -51,12 +51,12 @@ _kernel_oserror *commands_send(Session *session, int next_state, const char *com
{
const size_t length = strlen(command);
free(session->command.data);
session->command.data = malloc(length + 2 + 1);
if (session->command.data == 0) {
session->state = protostate_ERROR_MEM;
return NULL;
}
free(session->command.data);
session->command.data = malloc(length + 2 + 1);
if (session->command.data == 0) {
session->state = protostate_ERROR_MEM;
return NULL;
}
memcpy(session->command.data, command, length);
session->command.data[length] = '\r';
session->command.data[length+1] = '\n';
......@@ -65,13 +65,11 @@ _kernel_oserror *commands_send(Session *session, int next_state, const char *com
session->command.length = length + 2;
session->command.done = 0;
session->state = protostate_SENDING;
/*session->outstanding_response = 1;*/
session->state = protostate_SENDING;
/*session->outstanding_response = 1;*/
#ifdef TRACE
protocol_debug("<--- %s\r\n", command);
#endif
return commands_continue_sending(session);
dprintf(("commands_1", "<--- %s\r\n", command));
return commands_continue_sending(session);
}
/* Specify command and parameters separately */
......@@ -82,7 +80,7 @@ _kernel_oserror *vcommands_send(Session *session, int next_state, const char *co
char *full_string;
full_string = malloc(length_command + length_parameters + sizeof(" "));
if (full_string == NULL) {
session->state = protostate_ERROR_MEM;
session->state = protostate_ERROR_MEM;
return NULL;
}
else {
......@@ -111,16 +109,14 @@ _kernel_oserror *commands_continue_sending(Session *s)
s->command.done += result;
if (s->command.done < s->command.length) {
/* Not yet sent the command - it MUST be big :-) */
#ifdef TRACE
protocol_debug("%d sent total, %d total to send\n", s->command.done, s->command.length);
#endif
dprintf(("commands_1", "%d sent total, %d total to send\n", s->command.done, s->command.length));
return state_BLOCKING;
}
free(s->command.data);
s->command.data = NULL;
s->command.data = NULL;
if (s->command.next_state < 0) {
s->state = -s->command.next_state;
return NULL;
return NULL;
}
return commands_recv(s, s->command.next_state);
}
......@@ -129,8 +125,8 @@ _kernel_oserror *commands_continue_sending(Session *s)
}
/* Oh dear - a real error */
s->error_state = s->command.next_state;
s->state = protostate_ERROR_WRITE;
s->error_state = s->command.next_state;
s->state = protostate_ERROR_WRITE;
return NULL;
}
......@@ -143,16 +139,14 @@ static _kernel_oserror *commands_process_read_line(Session *s)
*/
const size_t length = strlen(s->response.data);
#ifdef TRACE
protocol_debug("---> %s\r\n", s->response.data);
#endif
dprintf(("commands_1", "---> %s\r\n", s->response.data));
if (s->response_code == -1) {
if (s->response_code == -1) {
/* First time through. */
}
(void) length;
s->state = s->response.next_state;
(void) length;
s->state = s->response.next_state;
return NULL;
}
......@@ -170,15 +164,15 @@ _kernel_oserror *commands_continue_reading(Session *s, arbitrary_data *data)
int result;
int sd = s->sd;
/* Initialise the error state here, because there are too many places where
* errors are generated to remember to set it everywhere
*/
s->error_state = data->next_state;
/* Initialise the error state here, because there are too many places where
* errors are generated to remember to set it everywhere
*/
s->error_state = data->next_state;
/* If there is no space left in the buffer (this will be the case if the buffer
* has not yet been allocated, but since the magic of realloc will magically do
* the malloc for us, we do not need to special case that code.
*/
/* If there is no space left in the buffer (this will be the case if the buffer
* has not yet been allocated, but since the magic of realloc will magically do
* the malloc for us, we do not need to special case that code.
*/
if (buffer_space == 0) {
char *buffer;
buffer = module_realloc(data->data, data->length + INTERNAL_BUFFER_SIZE + 4);
......@@ -193,12 +187,12 @@ _kernel_oserror *commands_continue_reading(Session *s, arbitrary_data *data)
}
}
/* Obtain copy of the data ONLY - we discard the appropriate amount later */
/* Obtain copy of the data ONLY - we discard the appropriate amount later */
result = recv(sd, data->data + data->done, buffer_space, MSG_PEEK);
if (result == 0) {
/* Closing data connection is end of transfer so switch to next state */
s->state = data->next_state;
return NULL;
/* Closing data connection is end of transfer so switch to next state */
s->state = data->next_state;
return NULL;
}
else if (result < 0) {
/* Errors are errors either way, unless we are waiting for connection/data */
......@@ -208,43 +202,43 @@ _kernel_oserror *commands_continue_reading(Session *s, arbitrary_data *data)
s->state = protostate_ERROR_READ;
return NULL;
}
else {
/* Seek out a newline character. More efficient to use memchr than
* writing a zero byte and using strchr, especially as we know the
* length of the buffer!
*/
char *const eol = memchr(data->data, '\n', data->done + result);
else {
/* Seek out a newline character. More efficient to use memchr than
* writing a zero byte and using strchr, especially as we know the
* length of the buffer!
*/
char *const eol = memchr(data->data, '\n', data->done + result);
if (eol == NULL) {
/* Have not read a complete line - suck all of the data into the buffer
* immediately, and then block until we get called again
*/
(void) recv(sd, data->data + data->done, result, 0);
data->done += result;
return state_BLOCKING;
}
else {
/* Read for real - remembering we've already read "done" bytes previously
* Errors cannot occur - we've just been told the data is there.
*/
const size_t bytes_to_read = (eol + 1 - data->data) - data->done;
(void) recv(sd, data->data + data->done, bytes_to_read, 0);
if (eol == NULL) {
/* Have not read a complete line - suck all of the data into the buffer
* immediately, and then block until we get called again
*/
(void) recv(sd, data->data + data->done, result, 0);
data->done += result;
return state_BLOCKING;
}
else {
/* Read for real - remembering we've already read "done" bytes previously
* Errors cannot occur - we've just been told the data is there.
*/
const size_t bytes_to_read = (eol + 1 - data->data) - data->done;
(void) recv(sd, data->data + data->done, bytes_to_read, 0);
/* Terminate buffer, zero counters for next response */
*eol = '\0';
data->done = 0;
/* Terminate buffer, zero counters for next response */
*eol = '\0';
data->done = 0;
if (eol > data->data) {
/* Look for and remove an immediately preceding \r */
if (eol[-1] == '\r') {
eol[-1] = '\0';
}
}
}
if (eol > data->data) {
/* Look for and remove an immediately preceding \r */
if (eol[-1] == '\r') {
eol[-1] = '\0';
}
}
}
/* Process this line of data as approproate */
return commands_process_read_line(s);
}
/* Process this line of data as approproate */
return commands_process_read_line(s);
}
}
/* This function initiates the process of receiving an FTP command response
......@@ -252,10 +246,10 @@ _kernel_oserror *commands_continue_reading(Session *s, arbitrary_data *data)
*/
_kernel_oserror *commands_recv(Session *session, int next_state)
{
session->response.next_state = next_state;
session->response.next_state = next_state;
session->response.length = INTERNAL_BUFFER_SIZE - 4;
session->response.done = 0;
session->response_code = -1;
session->response.done = 0;
session->response_code = -1;
free(session->response.data);
session->response.data = malloc(INTERNAL_BUFFER_SIZE);
if (session->response.data == NULL) {
......
......@@ -45,152 +45,123 @@
int make_sock_nonblocking(int fd)
{
int one = 1;
int one = 1;
if (socketioctl(fd, FIONBIO, &one) < 0) return 0;
if (socketioctl(fd, FIOASYNC, &one) < 0) return 0; /* Causes Internet events */
return 1;
if (socketioctl(fd, FIONBIO, &one) < 0) return 0;
if (socketioctl(fd, FIOASYNC, &one) < 0) return 0; /* Causes Internet events */
return 1;
}
/************************************************************************/
/* opensock(host, port, portname, pointer to state, current descriptor) */
/************************************************************************/
/* This function is responsible for initiating connections to remote */
/* hosts. It tries to connect to "host" on the port specified by the */
/* "sername" parameter unless this is NULL - in which case the "port" */
/* parameter is used. "port" is ignored if "sername" is non-NULL */
/* This function must fill in the state with the appropriate state so */
/* that when the ReadData SWI handler comes to dispatch through the */
/* This function is responsible for initiating connections to remote */
/* hosts. It tries to connect to "host" on the port specified by the */
/* "sername" parameter unless this is NULL - in which case the "port" */
/* parameter is used. "port" is ignored if "sername" is non-NULL */
/* This function must fill in the state with the appropriate state so */
/* that when the ReadData SWI handler comes to dispatch through the */
/* state table, it goes to the right place. "fd" is the current socket */
/* descriptor or -1 if there is no socket yet. It will be -1 on the */
/* first call (typically from the GetData SWI handler) and then be a */
/* descriptor or -1 if there is no socket yet. It will be -1 on the */
/* first call (typically from the GetData SWI handler) and then be a */
/* real socket handle in subsequent calls from a ReadData FSM handler. */
/* This function returns the handle of the created socket - the caller */
/* *must* prefer this to any handle it passed in the "fd" parameter. */
/* This function will close the passed "fd" if it so desires. */
/* If the return value is <0, this indicates an error (the value is */
/* actually "-errno" so you can use the value if you really want to) */
/* *must* prefer this to any handle it passed in the "fd" parameter. */
/* This function will close the passed "fd" if it so desires. */
/* If the return value is <0, this indicates an error (the value is */
/* actually "-errno" so you can use the value if you really want to) */
/* Note that the socket to be used is always created on the first time */
/* through this routine and it is left unbound until the DNS lookup */
/* has succeeded. This means that if you happen to use *inetstat to */
/* through this routine and it is left unbound until the DNS lookup */
/* has succeeded. This means that if you happen to use *inetstat to */
/* see all the sockets, you'll see a strange entry for a socket with */
/* an unknown port and unknown protocol. This is normal and correct. */
/* an unknown port and unknown protocol. This is normal and correct. */
/************************************************************************/
int opensock(char *name, int port, char *sername, int *state, int fd)
{
static int can_nonblock = 1;
int status=-1;
struct sockaddr_in addr;
addr.sin_family = AF_INET;
memset(addr.sin_zero, '\0', sizeof(addr.sin_zero));
if (sername == NULL) {
addr.sin_port = htons(port);
}
else {
struct servent *service = NULL;
if (strcmp(sername, CONNECT_DEFAULT_PROTOCOL_NAME) != 0) {
service = getservbyname(sername, "tcp");
}
addr.sin_port = service ? service->s_port : htons(CONNECT_DEFAULT_PORT_NUMBER);
}
/* Jump back here if we start a nonblocking connect and then discover
* that the platform has a broken read() or select().
*/
retry:
errno = 0;
if (fd < 0) {
#ifdef TRACE
protocol_debug("Creating socket ...\n");
#endif
if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
#ifdef TRACE
protocol_debug(".. error = %d\n", errno);
#endif
*state = CONNECT_ERROR_STATE;
return -errno;
}
#ifdef TRACE
protocol_debug(".. result = %d\n", fd);
#endif
if (can_nonblock) {
if (!make_sock_nonblocking(fd)) can_nonblock=0;
#ifdef TML
Printf("opensock> nonblock=%x (errno=%d)\n",can_nonblock,errno);
#endif
}
}
status = dns_find_ip_address(name, &addr.sin_addr);
if (status == EINPROGRESS) {
#ifdef TRACE
protocol_debug("dns_find_ip_address(%s) incomplete ... waiting\n", name);
#endif
*state = CONNECT_DNS_STATE;
return fd;
}
else if (status != 0) {
#ifdef TRACE
protocol_debug("dns_find_ip_address(%s) failed (%d)\n", name, status);
#endif
close_socket(&fd);
*state = CONNECT_CONNECTED_STATE;
return -status;
}
#ifdef TRACE
protocol_debug("dns_find_ip_address(%s) worked --> %s\n",
name, inet_ntoa(addr.sin_addr));
#endif
/* Set the state */
*state = CONNECT_CONNECTED_STATE;
status = connect(fd, (struct sockaddr*)&addr, sizeof(addr));
if (status == 0) {
/* The connection completed successfully. */
#ifdef TRACE
protocol_debug("connect() returned 0! Returning %d\n", fd);
#endif
return fd;
}
else {
if ((errno == EINPROGRESS) || (errno==0)) {
#ifdef TML
Printf("opensock> OK2: returning sd=%d (errno=%d)\n",fd,errno);
#endif
#ifdef TRACE
protocol_debug("errno==0 or EINPROGRESS - returning %d\n", fd);
#endif
return fd;
}
else {
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
#ifdef TML
Printf("closing %d (errno=%d), trying again\n",fd,errno);
#endif
#ifdef TRACE
protocol_debug("EAGAIN/WOULDBLOCK closing %d\n", fd);
#endif
close_socket(&fd);
can_nonblock = 0;
goto retry; /* try again */
}
}
}
#ifdef TRACE
protocol_debug("connect() return value was %d (errno now %d)\n",
status, errno);
#endif
status = errno;
close_socket(&fd);
return -status;
static int can_nonblock = 1;
int status=-1;
struct sockaddr_in addr;
addr.sin_family = AF_INET;
memset(addr.sin_zero, '\0', sizeof(addr.sin_zero));
if (sername == NULL) {
addr.sin_port = htons(port);
}
else {
struct servent *service = NULL;
if (strcmp(sername, CONNECT_DEFAULT_PROTOCOL_NAME) != 0) {
service = getservbyname(sername, "tcp");
}
addr.sin_port = service ? service->s_port : htons(CONNECT_DEFAULT_PORT_NUMBER);
}
/* Jump back here if we start a nonblocking connect and then discover
* that the platform has a broken read() or select().
*/
retry:
errno = 0;
if (fd < 0) {
dprintf(("connect_1", "Creating socket ...\n"));
if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
dprintf(("connect_1", ".. error = %d\n", errno));
*state = CONNECT_ERROR_STATE;
return -errno;
}
dprintf(("connect_1", ".. result = %d\n", fd));
if (can_nonblock) {
if (!make_sock_nonblocking(fd)) can_nonblock=0;
}
}
status = dns_find_ip_address(name, &addr.sin_addr);
if (status == EINPROGRESS) {
dprintf(("connect_1", "dns_find_ip_address(%s) incomplete ... waiting\n", name));
*state = CONNECT_DNS_STATE;
return fd;
}
else if (status != 0) {
dprintf(("connect_1", "dns_find_ip_address(%s) failed (%d)\n", name, status));
close_socket(&fd);
*state = CONNECT_CONNECTED_STATE;
return -status;
}
dprintf(("connect_1", "dns_find_ip_address(%s) worked --> %s\n",
name, inet_ntoa(addr.sin_addr)));
/* Set the state */
*state = CONNECT_CONNECTED_STATE;
status = connect(fd, (struct sockaddr*)&addr, sizeof(addr));
if (status == 0) {
/* The connection completed successfully. */
dprintf(("connect_1", "connect() returned 0! Returning %d\n", fd));
return fd;
}
else {
if ((errno == EINPROGRESS) || (errno==0)) {
dprintf(("connect_1", "errno==0 or EINPROGRESS - returning %d\n", fd));
return fd;
}
else {
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
dprintf(("connect_1", "EAGAIN/WOULDBLOCK closing %d\n", fd));
close_socket(&fd);
can_nonblock = 0;
goto retry; /* try again */
}
}
}
dprintf(("connect_1", "connect() return value was %d (errno now %d)\n",
status, errno));
status = errno;
close_socket(&fd);
return -status;
}
......@@ -51,18 +51,18 @@ void http_add_header(http_header **list, const char *header, const char *value)
h->next = NULL;
h->header = h->text;
memcpy(h->text, header, header_len);
h->value = h->text + header_len;
h->value = h->text + header_len;
memcpy(h->value, value, value_len);
if (*list == NULL) {
*list = h;
}
else {
if (*list == NULL) {
*list = h;
}
else {
http_header *plist;
for (plist = *list; plist->next; plist = plist->next) ;;
plist->next = h;
}
}
}
void http_delete_header(http_header **list, http_header *header)
......@@ -90,7 +90,7 @@ http_header *http_find_header(http_header *list, char *header)
if (Strcmp_ci(list->header, header) == 0) break;
}
return list;
return list;
}
void http_free_headers(http_header **list)
......@@ -105,39 +105,35 @@ void http_free_headers(http_header **list)
void http_filter_connection_tokens(http_header **list, char *tokens)
{
for (;;) {
char *comma, *end, saved;
while (*tokens == ',' || (*tokens != '\0' && isspace(*tokens))) ++tokens;
if (*tokens == '\0') break;
comma = strchr(tokens, ',');
if (comma != NULL) {
end = comma++;
}
else {
comma = end = strchr(tokens, '\0');
}
/* We now know we are not looking at an empty list member token */
for (--end; isspace(*end); --end) ;;
++end;
/* Found it! Do NOT get fooled by removing ourselves! Shouldn't happen but ... */
if (Strncmp_ci(tokens, "connection", sizeof("connection")) != 0) {
#ifdef TRACE
protocol_debug("Filtering header named in connection: %.*s\n", end-tokens, tokens);
#endif
saved = *end;
*end = '\0';
for (;;) {
http_header *h = http_find_header(*list, tokens);
if (h == NULL) break;
#ifdef TRACE
protocol_debug("Deleting `%s' header\n", h->header);
#endif
http_delete_header(list, h);
}
*end = saved;
}
char *comma, *end, saved;
while (*tokens == ',' || (*tokens != '\0' && isspace(*tokens))) ++tokens;
if (*tokens == '\0') break;
comma = strchr(tokens, ',');
if (comma != NULL) {
end = comma++;
}
else {
comma = end = strchr(tokens, '\0');
}
/* We now know we are not looking at an empty list member token */
for (--end; isspace(*end); --end) ;;
++end;
/* Found it! Do NOT get fooled by removing ourselves! Shouldn't happen but ... */
if (Strncmp_ci(tokens, "connection", sizeof("connection")) != 0) {
dprintf(("headers_1", "Filtering header named in connection: %.*s\n", end-tokens, tokens));
saved = *end;
*end = '\0';
for (;;) {
http_header *h = http_find_header(*list, tokens);
if (h == NULL) break;
dprintf(("headers_1", "Deleting `%s' header\n", h->header));
http_delete_header(list, h);
}
*end = saved;
}
tokens = comma;
}
......@@ -149,17 +145,15 @@ void http_filter_connection_tokens(http_header **list, char *tokens)
*/
size_t http_construct_header_buffer(Session *ses, size_t extra)
{
http_header *h;
char *ptr;
size_t header_size = extra + sizeof("\r\n");
http_header *h;
char *ptr;
size_t header_size = extra + sizeof("\r\n");
for (h=ses->headers; h; h=h->next) {
header_size += strlen(h->header) + strlen(h->value) + sizeof(": \r\n") - 1;
}
#ifdef TRACE
protocol_debug("Need %d bytes to hold the entire header\n", header_size);
#endif
dprintf(("headers_1", "Need %d bytes to hold the entire header\n", header_size));
ses->current_header = malloc(header_size);
if (ses->current_header == NULL) {
/* This will have the effect of persuading the browser we are HTTP 0.9
......@@ -168,16 +162,14 @@ size_t http_construct_header_buffer(Session *ses, size_t extra)
return 0;
}
ptr = ses->current_header;
for (h=ses->headers; h; h=h->next) {
#ifdef TRACE
protocol_debug("Writing `%s' header to buffer (value `%s')\n", h->header, h->value);
#endif
ptr += sprintf(ptr, "%s%s %s\r\n", h->header, h == ses->headers ? "" : ":", h->value);
}
ptr += sprintf(ptr, "\r\n");
http_free_headers(&ses->headers);
return (ptr - ses->current_header);
ptr = ses->current_header;
for (h=ses->headers; h; h=h->next) {
dprintf(("headers_1", "Writing `%s' header to buffer (value `%s')\n", h->header, h->value));
ptr += sprintf(ptr, "%s%s %s\r\n", h->header, h == ses->headers ? "" : ":", h->value);
}
ptr += sprintf(ptr, "\r\n");
http_free_headers(&ses->headers);
return (ptr - ses->current_header);
}
......@@ -188,125 +180,123 @@ size_t http_construct_header_buffer(Session *ses, size_t extra)
*/
static int http_delimit_header(char *buffer, char **eobuffer, char **header, char **value)
{
char *ptr;
ptr = buffer + strcspn(buffer, "\n\r"); /* Locate line terminator (if present) else string term.*/
if (*ptr) {
*ptr = '\0'; /* terminate buffer */
if (eobuffer) {
*eobuffer = ptr + 1; /* Return that there was more than one line in buffer */
}
}
else {
if (eobuffer) *eobuffer = 0; /* Return that there was no more data in buffer */
}
while (ptr > buffer) {
if (isspace(ptr[-1])) { /* Strip trailing spaces */
*--ptr = '\0';
}
else break;
}
buffer += strspn(buffer, " \t"); /* Skip leading spaces */
if (!*buffer) { /* String was empty? Bail out */
*header = 0;
*value = 0;
return 0;
}
*header = buffer;
buffer += strcspn(buffer, " :\t"); /* Skip over header name */
if (!*buffer) {
*value = 0; /* No data for this header - corrupt? */
return 0;
}
*buffer++ = 0; /* Terminate header name and move along */
*value = buffer + strspn(buffer, " :\t"); /* Locate start of header value and store it */
return 1;
char *ptr;
ptr = buffer + strcspn(buffer, "\n\r"); /* Locate line terminator (if present) else string term.*/
if (*ptr) {
*ptr = '\0'; /* terminate buffer */
if (eobuffer) {
*eobuffer = ptr + 1; /* Return that there was more than one line in buffer */
}
}
else {
if (eobuffer) *eobuffer = 0; /* Return that there was no more data in buffer */
}
while (ptr > buffer) {
if (isspace(ptr[-1])) { /* Strip trailing spaces */
*--ptr = '\0';
}
else break;
}
buffer += strspn(buffer, " \t"); /* Skip leading spaces */
if (!*buffer) { /* String was empty? Bail out */
*header = 0;
*value = 0;
return 0;
}
*header = buffer;
buffer += strcspn(buffer, " :\t"); /* Skip over header name */
if (!*buffer) {
*value = 0; /* No data for this header - corrupt? */
return 0;
}
*buffer++ = 0; /* Terminate header name and move along */
*value = buffer + strspn(buffer, " :\t"); /* Locate start of header value and store it */
return 1;
}
/* This function returns non-zero if it managed to locate a complete header line */
static int http_check_found_header(char *buffer, char **next, int continuations)
{
char *ptr, *nl;
#ifdef TRACE
protocol_debug("http_check_found_header(%.*s)\n", 96, buffer);
#endif
/* Find the first \r and \n characters in the buffer, if any */
ptr = strchr(buffer, '\r');
nl = strchr(buffer, '\n');
if (!ptr || (nl && ptr && (nl < ptr))) {
/* If there was a \n and \r AND \n occurred before \r, make ptr
* point at the \n instead (because we're using EOL of \n and
* it looks as if we might have picked up a \r somewhere in the
* object body which we DON'T want to see yet
*/
ptr = nl;
}
/* At this point, ptr can only be NULL if nl is also NULL */
if (ptr && !nl) {
/* found a \r but didn't find a \n */
if (ptr[1] == ' ' || ptr[1] == '\t') {
/* Was this a continuation line? */
ptr[0] = ' '; /* blank the spurious \r character out */
return http_check_found_header(buffer, next, continuations);
}
if (!ptr[1]) {
/* BUT the \r happened to be at the end of the buffer
* so we'll go around again in order to forcibly pick
* up the \n on the next read.
*/
*next = NULL;
return 0;
}
/* To get here, ptr points to a lonely \r character at a real header end */
}
else if (!ptr) {
/* neither \r nor \n found */
*next = NULL;
return 0;
}
else {
if (ptr != nl) {
/* To get here, we have found both a \r and a \n */
if (ptr[1] == '\n') {
nl = ptr+1;
*ptr++ = ' '; /* Blank out the \r */
}
}
else {
/* Found just a \n - check at end of buffer */
if (nl[1] == '\0' && continuations && nl != buffer) {
/* At end of buffer */
*next = NULL;
return 0;
}
}
}
/* To get here, ptr is non NULL and points at the end of line character
* which WILL be either \r or \n, BUT the next character ptr[1] will not
* be another newline indicator unless this is the end of the headers */
if (ptr == buffer || (ptr == (buffer+1) && buffer[0] == ' ')) {
/* Was the last header - send blank string back */
*buffer = '\0';
*next = ptr+1;
return 1;
}
if (ptr[1] == ' ' || ptr[1] == '\t') {
/* This was a continuation line */
*ptr = ' '; /* exterminate the previous end of line */
return http_check_found_header(buffer, next, continuations);
}
*ptr++ = '\0';
*next = ptr;
char *ptr, *nl;
dprintf(("headers_1", "http_check_found_header(%.*s)\n", 96, buffer));
/* Find the first \r and \n characters in the buffer, if any */
ptr = strchr(buffer, '\r');
nl = strchr(buffer, '\n');
if (!ptr || (nl && ptr && (nl < ptr))) {
/* If there was a \n and \r AND \n occurred before \r, make ptr
* point at the \n instead (because we're using EOL of \n and
* it looks as if we might have picked up a \r somewhere in the
* object body which we DON'T want to see yet
*/
ptr = nl;
}
/* At this point, ptr can only be NULL if nl is also NULL */
if (ptr && !nl) {
/* found a \r but didn't find a \n */
if (ptr[1] == ' ' || ptr[1] == '\t') {
/* Was this a continuation line? */
ptr[0] = ' '; /* blank the spurious \r character out */
return http_check_found_header(buffer, next, continuations);
}
if (!ptr[1]) {
/* BUT the \r happened to be at the end of the buffer
* so we'll go around again in order to forcibly pick
* up the \n on the next read.
*/
*next = NULL;
return 0;
}
/* To get here, ptr points to a lonely \r character at a real header end */
}
else if (!ptr) {
/* neither \r nor \n found */
*next = NULL;
return 0;
}
else {
if (ptr != nl) {
/* To get here, we have found both a \r and a \n */
if (ptr[1] == '\n') {
nl = ptr+1;
*ptr++ = ' '; /* Blank out the \r */
}
}
else {
/* Found just a \n - check at end of buffer */
if (nl[1] == '\0' && continuations && nl != buffer) {
/* At end of buffer */
*next = NULL;
return 0;
}
}
}
/* To get here, ptr is non NULL and points at the end of line character
* which WILL be either \r or \n, BUT the next character ptr[1] will not
* be another newline indicator unless this is the end of the headers */
if (ptr == buffer || (ptr == (buffer+1) && buffer[0] == ' ')) {
/* Was the last header - send blank string back */
*buffer = '\0';
*next = ptr+1;
return 1;
}
if (ptr[1] == ' ' || ptr[1] == '\t') {
/* This was a continuation line */
*ptr = ' '; /* exterminate the previous end of line */
return http_check_found_header(buffer, next, continuations);
}
*ptr++ = '\0';
*next = ptr;
return 1;
}
......@@ -321,32 +311,28 @@ int parse_user_header(char *buffer, int buflen, Session *ses)
char *next, *eob, *header, *value;
int consumed = 0, ended = 0;
#ifdef TRACE
protocol_debug("Parsing user supplied header block\n");
protocol_dump(buffer, buflen);
#endif
dprintf(("headers_1", "Parsing user supplied header block\n"));
ddumpbuf("headers_1", buffer, buflen, 0);
while (!ended && http_check_found_header(buffer, &next, 1)) {
if (http_delimit_header(buffer, &eob, &header, &value)) {
if (header != NULL) {
if (Strcmp_ci(header, "host") != 0 && Strcmp_ci(header, "connection") != 0 &&
Strcmp_ci(header, "user-agent") != 0) {
http_add_header(&ses->headers, header, value ? value : "");
}
}
}
consumed += (next - buffer);
buffer = next;
if (http_delimit_header(buffer, &eob, &header, &value)) {
if (header != NULL) {
if (Strcmp_ci(header, "host") != 0 && Strcmp_ci(header, "connection") != 0 &&
Strcmp_ci(header, "user-agent") != 0) {
http_add_header(&ses->headers, header, value ? value : "");
}
}
}
consumed += (next - buffer);
buffer = next;
if (consumed >= buflen) ended = TRUE;
if (header == NULL && value == NULL) {
ended = TRUE;
}
if (header == NULL && value == NULL) {
ended = TRUE;
}
}
#ifdef TRACE
protocol_debug("End parse user supplied header block. Data remaining: %d bytes\n", buflen - consumed);
protocol_dump(buffer, buflen - consumed);
#endif
dprintf(("headers_1", "End parse user supplied header block. Data remaining: %d bytes\n", buflen - consumed));
ddumpbuf("headers_1", buffer, buflen - consumed, 0);
return consumed;
}
......@@ -50,12 +50,12 @@
#ifdef ROM
#ifndef NO_TINYSTUBS
static _kernel_oserror *__ROM;
#define TinySupport_Share (0x82c43)
#define TinySupport_Die (0x82c41)
#define TinySupport_Share (0x82c43)
#define TinySupport_Die (0x82c41)
#endif
#endif
#define NO_SUCH_SWI (0x1E6)
#define NO_SUCH_SWI (0x1E6)
#define URL_PROTOCOL_REGISTER 0x83e20
#define URL_PROTOCOL_DEREGISTER 0x83e21
......@@ -77,9 +77,9 @@ static int callback_pending_flag;
static int clibrary_realloc_routine_is_buggy;
static void module_check_os_version(void)
{
int os;
(void) _swix(OS_Byte, _INR(0,2)|_OUT(1), 129, 0, 255, &os);
clibrary_realloc_routine_is_buggy = (os <= 0xA4);
int os;
(void) _swix(OS_Byte, _INR(0,2)|_OUT(1), 129, 0, 255, &os);
clibrary_realloc_routine_is_buggy = (os <= 0xA4);
}
......@@ -87,252 +87,249 @@ static int registered;
static _kernel_oserror *try_to_register(void)
{
_kernel_oserror *e;
if (registered) return NULL;
e = _swix(URL_PROTOCOL_REGISTER, _INR(0,4), 0,
GenericFetcher_00,
CONNECT_DEFAULT_PROTOCOL_NAME ":",
Module_VersionNumber, Module_Help " Acorn 1998 (Built: " Module_Date ")");
if (e == NULL) {
registered = 1;
}
return e;
_kernel_oserror *e;
if (registered) return NULL;
e = _swix(URL_PROTOCOL_REGISTER, _INR(0,4), 0,
GenericFetcher_00,
CONNECT_DEFAULT_PROTOCOL_NAME ":",
Module_VersionNumber, Module_Help " Acorn");
if (e == NULL) {
registered = 1;
}
return e;
}
static _kernel_oserror *try_to_deregister(void)
{
if (!registered) {
return NULL;
}
else {
registered = 0;
return _swix(URL_PROTOCOL_DEREGISTER, _INR(0,1), 0, GenericFetcher_00);
}
if (!registered) {
return NULL;
}
else {
registered = 0;
return _swix(URL_PROTOCOL_DEREGISTER, _INR(0,1), 0, GenericFetcher_00);
}
}
static _kernel_oserror *register_with_url(void)
{
_kernel_oserror *e;
e = try_to_register();
if (e == NULL) return e;
if (e->errnum != NO_SUCH_SWI) return e;
#ifndef ROM
e = _swix(OS_Module, _INR(0,1), 1 /* Load */, "System:Modules.Network.URL.URL");
return try_to_register();
#else
return NULL;
#endif
_kernel_oserror *e;
e = try_to_register();
if (e == NULL) return e;
if (e->errnum != NO_SUCH_SWI) return e;
#ifndef ROM
e = _swix(OS_Module, _INR(0,1), 1 /* Load */, "System:Modules.Network.URL.URL");
return try_to_register();
#else
return NULL;
#endif
}
/*************************************************************/
/* _kernel_oserror *module_init(char *cmd_fail, int podu... */
/*************************************************************/
/* Start up and register ourselves with the URL module */
/* Start up and register ourselves with the URL module */
/*************************************************************/
_kernel_oserror *module_init(CMHG_CONST char *cmd_tail, int podule_base, void *pw)
{
_kernel_oserror *e;
(void) podule_base;
(void) cmd_tail;
#ifdef ROM
#ifndef NO_TINYSTUBS
__ROM = _swix(TinySupport_Share, _IN(0), pw);
#endif
#endif
registered = 0;
callback_pending_flag = 0;
session_init();
module_check_os_version();
MemCheck_InitNoDebug();
MemCheck_SetQuitting(0,0);
MemCheck_RedirectToFilename("adfs::4.Trace.Genericmem");
MemCheck_InterceptSCLStringFunctions();
MemCheck_RegisterMiscBlock((void *)0x01c0001c,8164);
MemCheck_SetStoreMallocFunctions(1);
MemCheck_SetReportFrees(1);
MemCheck_SetChecking(0,0);
e = register_with_url();
if (e) {
#ifndef ROM
if (e->errnum == NO_SUCH_SWI) {
_kernel_oserror *newe = find_error();
const size_t length = strlen(strcpy(newe->errmess, e->errmess));
newe->errnum = NO_SUCH_SWI;
strncat(newe->errmess, " (Load the URL module)", sizeof(newe->errmess) - length);
return newe;
}
#endif
return e;
}
#ifndef ROM
e = _swix(ResourceFS_RegisterFiles, _IN(0), messages_file());
if (e) {
(void) try_to_deregister();
return e;
}
#endif
if (getenv(Module_Title "$Path")) {
e = messages_file_open(Module_Title ":Messages");
}
else {
e = messages_file_open("Resources:$.Resources.URL." "Generic" ".Messages");
}
if (e) {
#ifndef ROM
(void) _swix(ResourceFS_DeregisterFiles, _IN(0), messages_file());
#endif
(void) try_to_deregister();
return e;
}
callback_pending_flag = 0;
/* Set up a callevery */
e = _swix(OS_CallEvery, _INR(0,2), 15*100-1, callevery_entry, pw);
if (e) {
messages_file_close();
#ifndef ROM
(void) _swix(ResourceFS_DeregisterFiles, _IN(0), messages_file());
#endif
(void) try_to_deregister();
return e;
}
return NULL;
_kernel_oserror *e;
(void) podule_base;
(void) cmd_tail;
#ifdef ROM
#ifndef NO_TINYSTUBS
__ROM = _swix(TinySupport_Share, _IN(0), pw);
#endif
#endif
debug_initialise("Generic", 0, 0);
debug_output_device(DEBUGIT_OUTPUT);
registered = 0;
callback_pending_flag = 0;
session_init();
module_check_os_version();
MemCheck_InitNoDebug();
MemCheck_SetQuitting(0,0);
MemCheck_RedirectToFilename("adfs::4.Trace.Genericmem");
MemCheck_InterceptSCLStringFunctions();
MemCheck_RegisterMiscBlock((void *)0x01c0001c,8164);
MemCheck_SetStoreMallocFunctions(1);
MemCheck_SetReportFrees(1);
MemCheck_SetChecking(0,0);
e = register_with_url();
if (e) {
#ifndef ROM
if (e->errnum == NO_SUCH_SWI) {
_kernel_oserror *newe = find_error();
newe->errnum = 0x115; /* NeedMod */
strcpy(newe->errmess, "NeedMod");
e = _swix(MessageTrans_ErrorLookup, _INR(0,7), newe, 0, 0, 0, Module_Title, "URL", 0, 0);
}
#endif
return e;
}
#ifndef ROM
e = _swix(ResourceFS_RegisterFiles, _IN(0), messages_file());
if (e) {
(void) try_to_deregister();
return e;
}
#endif
if (getenv(Module_Title "$Path")) {
e = messages_file_open(Module_Title ":Messages");
}
else {
e = messages_file_open("Resources:$.Resources.URL." "Generic" ".Messages");
}
if (e) {
#ifndef ROM
(void) _swix(ResourceFS_DeregisterFiles, _IN(0), messages_file());
#endif
(void) try_to_deregister();
return e;
}
callback_pending_flag = 0;
/* Set up a callevery */
e = _swix(OS_CallEvery, _INR(0,2), 15*100-1, callevery_entry, pw);
if (e) {
messages_file_close();
#ifndef ROM
(void) _swix(ResourceFS_DeregisterFiles, _IN(0), messages_file());
#endif
(void) try_to_deregister();
return e;
}
return NULL;
}
void service_handler(int service_number, _kernel_swi_regs *r, void *pw)
{
#ifdef TRACE
protocol_debug("Service &%X: R0 = %d for URL version %03d\n", service_number, r->r[0], r->r[2]);
#endif
(void) pw;
(void) service_number;
switch (r->r[0]) {
case 0:
(void) try_to_register();
break;
case 1:
(void) try_to_deregister();
break;
default:
break;
}
dprintf(("module_1", "Service &%X: R0 = %d for URL version %03d\n", service_number, r->r[0], r->r[2]));
(void) pw;
(void) service_number;
switch (r->r[0]) {
case 0:
(void) try_to_register();
break;
case 1:
(void) try_to_deregister();
break;
default:
break;
}
}
_kernel_oserror *module_kill(int fatal, int podule, void *pw)
{
(void) fatal;
(void) podule;
(void) fatal;
(void) podule;
(void) _swix(OS_RemoveTickerEvent, _INR(0,1), callevery_entry, pw);
if (callback_pending_flag) {
(void) _swix(OS_RemoveCallBack, _INR(0,1), callback_entry, pw);
}
messages_file_close();
#ifndef ROM
(void) _swix(ResourceFS_DeregisterFiles, _IN(0), messages_file());
#endif
(void) _swix(OS_RemoveTickerEvent, _INR(0,1), callevery_entry, pw);
if (callback_pending_flag) {
(void) _swix(OS_RemoveCallBack, _INR(0,1), callback_entry, pw);
}
messages_file_close();
#ifndef ROM
(void) _swix(ResourceFS_DeregisterFiles, _IN(0), messages_file());
#endif
ses_kill_all();
ses_kill_all();
(void) try_to_deregister();
#ifdef ROM
#ifndef NO_TINYSTUBS
if(!__ROM) _swix(TinySupport_Die, 0);
#endif
#endif
if(!__ROM) _swix(TinySupport_Die, 0);
#endif
#endif
return NULL;
return NULL;
}
_kernel_oserror *swi_handler(int swi_offset, _kernel_swi_regs *r, void *pw)
{
(void) pw;
(void) pw;
switch (swi_offset) {
case GenericFetcher_GetData - GenericFetcher_00:
return(generic_start(r));
switch (swi_offset) {
case GenericFetcher_GetData - GenericFetcher_00:
return(generic_start(r));
case GenericFetcher_Status - GenericFetcher_00:
return(generic_status(r));
case GenericFetcher_Status - GenericFetcher_00:
return(generic_status(r));
case GenericFetcher_ReadData - GenericFetcher_00:
return(generic_readdata(r));
case GenericFetcher_ReadData - GenericFetcher_00:
return(generic_readdata(r));
case GenericFetcher_Stop - GenericFetcher_00:
return (generic_stop(r));
case GenericFetcher_Stop - GenericFetcher_00:
return (generic_stop(r));
default:
return(error_BAD_SWI);
}
default:
return(error_BAD_SWI);
}
}
int callback_handler(_kernel_swi_regs *r, void *pw)
{
(void) pw;
(void) r;
(void) pw;
(void) r;
if (!callback_pending_flag) {
return 1;
}
if (!callback_pending_flag) {
return 1;
}
callback_pending_flag = 0;
return 1;
callback_pending_flag = 0;
return 1;
}
int callevery_handler(_kernel_swi_regs *r, void *pw)
{
(void) r;
if (callback_pending_flag) {
return 1;
}
callback_pending_flag = 1;
(void) _swix(OS_AddCallBack, _INR(0,1), callback_entry, pw);
return 1;
(void) r;
if (callback_pending_flag) {
return 1;
}
callback_pending_flag = 1;
(void) _swix(OS_AddCallBack, _INR(0,1), callback_entry, pw);
return 1;
}
/* RISC OS 3.1 SVC mode realloc is broken, so we must provide our own */
char *module_realloc(void *ptr, size_t size)
{
#ifdef TRACE
protocol_debug("module_realloc(%p, %d)\n", ptr, size);
#endif
if (!clibrary_realloc_routine_is_buggy) return realloc(ptr, size);
if (ptr == NULL) {
return malloc(size);
}
if (size == 0) {
free(ptr);
return NULL;
}
else {
const int *rma_block = ptr;
const size_t newsize = size - (rma_block[-1] - 4);
char *newptr;
if (_swix(OS_Module, _IN(0)|_INR(2,3)|_OUT(2), 0xD, ptr, newsize, &newptr) != NULL) {
return NULL;
}
return newptr;
}
dprintf(("module_1", "module_realloc(%p, %d)\n", ptr, size));
if (!clibrary_realloc_routine_is_buggy) return realloc(ptr, size);
if (ptr == NULL) {
return malloc(size);
}
if (size == 0) {
free(ptr);
return NULL;
}
else {
const int *rma_block = ptr;
const size_t newsize = size - (rma_block[-1] - 4);
char *newptr;
if (_swix(OS_Module, _IN(0)|_INR(2,3)|_OUT(2), 0xD, ptr, newsize, &newptr) != NULL) {
return NULL;
}
return newptr;
}
}
......@@ -23,170 +23,54 @@
#include <stdlib.h>
#include <ctype.h>
#include" protocol.h"
#include "utils.h"
#define TRACE_NAME "Generic"
#ifdef USE_SYSLOG
#include "<syslog$dir>.C-veneer.h.syslog"
#endif
#define DEBUG_FILENAME "RAM:$.TR-" TRACE_NAME
/*************************************************************/
/* static void protocol_debug(const char *format, ... */
/*************************************************************/
/* Output trace information to the DEBUG_FILENAME */
/*************************************************************/
#ifdef TRACE
#ifdef USE_SYSLOG
static int dont_use_syslog = 0;
#endif
void protocol_debug(const char *format, ...)
{
#ifdef TRACE
if (getenv("NoTrace$" TRACE_NAME)) return; else {
va_list ap;
#ifdef USE_SYSLOG
if (!dont_use_syslog) {
static char buffer[1024];
va_start(ap, format);
vsprintf(buffer, format, ap);
va_end(ap);
if (xsyslog_logmessage(TRACE_NAME, buffer, 100)) {
dont_use_syslog = 1;
}
}
if (dont_use_syslog) {
#endif
FILE *fp = fopen(DEBUG_FILENAME, "a");
if (fp != 0) {
va_start(ap, format);
(void) vfprintf(fp, format, ap);
va_end(ap);
fclose(fp);
}
#ifdef USE_SYSLOG
}
#endif
}
#else
(void) format;
#endif
}
#endif
#ifdef TRACE
static char *filter(char *buf, const char *ptr, int max)
{
int i;
for (i=0; i<=max; ++i) {
int p = ptr[i];
if (p<32 || p == 127) buf[i] = '.'; else buf[i] = p;
}
buf[i] = '\0';
return buf;
}
void protocol_dump(const char *ptr, int size)
{
#ifdef TRACE
if (getenv("NoTrace$" TRACE_NAME) || getenv("NoTrace$" TRACE_NAME "Raw")) {
return;
}
else {
#ifdef USE_SYSLOG
if (!dont_use_syslog) {
if (xsyslog_logdata(TRACE_NAME, 100, ptr, size, 0)) {
dont_use_syslog = 1;
}
}
if (dont_use_syslog) {
#endif
FILE *fp = fopen(DEBUG_FILENAME, "a");
if (fp != NULL) {
int ctr;
char buf[48];
fprintf(fp, "%08x: ", 0);
for (ctr=0; ctr<size; ++ctr) {
fprintf(fp, "%02x ", ptr[ctr]);
if ((ctr & 31) == 31) {
fprintf(fp, " %s",
filter(buf, ptr+(ctr & ~31), ctr & 31));
fprintf(fp, "\n%08x: ", ctr+1);
}
}
if (ctr & 31) {
const char *start = ptr + (ctr & ~31);
while (ctr & 31) {
fprintf(fp, " ");
++ctr;
}
fprintf(fp, " %s", filter(buf, start, (size & 31)-1));
}
fputc('\n', fp);
fclose(fp);
}
#ifdef USE_SYSLOG
}
#endif
}
#else
(void) ptr;
(void) size;
#endif
}
#endif
#ifdef TRACE
#ifdef DEBUGLIB
char *protocol_states(int state)
{
switch (state) {
case protostate_ERROR: return "protostate_ERROR";
case protostate_ERROR_DEAD: return "protostate_ERROR_DEAD";
case protostate_ERROR_MEM: return "protostate_ERROR_MEM";
case protostate_ERROR_WRITE: return "protostate_ERROR_WRITE";
case protostate_ERROR_READ: return "protostate_ERROR_READ";
case protostate_ERROR_CONNECTION: return "protostate_ERROR_CONNECTION";
case protostate_ERROR_NO_TOKEN: return "protostate_ERROR_NO_TOKEN";
case protostate_ERROR_NOT_IMPLEMENTED: return "protostate_ERROR_NOT_IMPLEMENTED";
case protostate_INITIAL: return "protostate_INITIAL";
case protostate_DNS: return "protostate_DNS";
case protostate_CONNECTED: return "protostate_CONNECTED";
case protostate_SENDING: return "protostate_SENDING";
case protostate_RECEIVING: return "protostate_RECEIVING";
case protostate_PUMPING: return "protostate_PUMPING";
case protostate_COMPLETED: return "protostate_COMPLETED";
default: return "*UNKNOWN*";
}
switch (state) {
case protostate_ERROR: return "protostate_ERROR";
case protostate_ERROR_DEAD: return "protostate_ERROR_DEAD";
case protostate_ERROR_MEM: return "protostate_ERROR_MEM";
case protostate_ERROR_WRITE: return "protostate_ERROR_WRITE";
case protostate_ERROR_READ: return "protostate_ERROR_READ";
case protostate_ERROR_CONNECTION: return "protostate_ERROR_CONNECTION";
case protostate_ERROR_NO_TOKEN: return "protostate_ERROR_NO_TOKEN";
case protostate_ERROR_NOT_IMPLEMENTED: return "protostate_ERROR_NOT_IMPLEMENTED";
case protostate_INITIAL: return "protostate_INITIAL";
case protostate_DNS: return "protostate_DNS";
case protostate_CONNECTED: return "protostate_CONNECTED";
case protostate_SENDING: return "protostate_SENDING";
case protostate_RECEIVING: return "protostate_RECEIVING";
case protostate_PUMPING: return "protostate_PUMPING";
case protostate_COMPLETED: return "protostate_COMPLETED";
default: return "*UNKNOWN*";
}
}
#endif
#ifdef TRACE
#ifdef DEBUGLIB
char *protocol_network_states(int status)
{
switch (status) {
case status_NOT_YET_CONNECTED: return "status_NOT_YET_CONNECTED";
case status_CONNECTED_TO_SERVER: return "status_CONNECTED_TO_SERVER";
case status_SENT_REQUEST: return "status_SENT_REQUEST";
case status_SENT_DATA: return "status_SENT_DATA";
case status_WAIT_INITIAL_RESPONSE: return "status_WAIT_INITIAL_RESPONSE";
case status_HAVE_INITIAL_RESPONSE: return "status_HAVE_INITIAL_RESPONSE";
case status_WAIT_FOR_BODY: return "status_WAIT_FOR_BODY";
case status_TRANSFER_IN_PROGRESS: return "status_TRANSFER_IN_PROGRESS";
case status_READING_REPLY: return "status_READING_REPLY";
case status_ALL_DATA_RECEIVED: return "status_ALL_DATA_RECEIVED";
case status_ABORTED: return "status_ABORTED";
switch (status) {
case status_NOT_YET_CONNECTED: return "status_NOT_YET_CONNECTED";
case status_CONNECTED_TO_SERVER: return "status_CONNECTED_TO_SERVER";
case status_SENT_REQUEST: return "status_SENT_REQUEST";
case status_SENT_DATA: return "status_SENT_DATA";
case status_WAIT_INITIAL_RESPONSE: return "status_WAIT_INITIAL_RESPONSE";
case status_HAVE_INITIAL_RESPONSE: return "status_HAVE_INITIAL_RESPONSE";
case status_WAIT_FOR_BODY: return "status_WAIT_FOR_BODY";
case status_TRANSFER_IN_PROGRESS: return "status_TRANSFER_IN_PROGRESS";
case status_READING_REPLY: return "status_READING_REPLY";
case status_ALL_DATA_RECEIVED: return "status_ALL_DATA_RECEIVED";
case status_ABORTED: return "status_ABORTED";
default:
{
static char charbuf[16];
sprintf(charbuf, "&%08X", status);
return charbuf;
}
}
default:
{
static char charbuf[16];
sprintf(charbuf, "&%08X", status);
return charbuf;
}
}
}
#endif
......@@ -45,32 +45,28 @@
static _kernel_oserror *generic_exec_readdata(_kernel_swi_regs */*r*/);
_kernel_oserror *generic_readdata(_kernel_swi_regs *r)
{
/* This wrapper is used to ensure that R2 and R3 are preserved across the SWI
* This is needed because in order to generate the client's data buffer piecemeal
* (we are rewriting the headers to help the browser out and removing some that
* do not concern it at all), we keep updating R2 and R3 to avoid writing off
* the end of the buffer.
* We also take the opportunity to initialise R4 and R5 safely.
*/
const int const_buffer = r->r[2];
const int const_buflen = r->r[3];
_kernel_oserror *result;
#ifdef TRACE
protocol_debug("Buffer (R2) is &%08x; Size (R3) = %d\n", const_buffer, const_buflen);
#endif
r->r[0] = status_READING_REPLY;
r->r[4] = 0; /* No data in client buffer yet */
r->r[5] = -1; /* Unknown how much more data to read */
result = generic_exec_readdata(r);
r->r[2] = const_buffer; /* Restore buffer address */
r->r[3] = const_buflen; /* Restore buffer size */
#ifdef TRACE
protocol_debug("<< Exit SWI ReadData. Bytes read: %d\n", r->r[4]);
protocol_dump((void *)r->r[2], r->r[4]);
#endif
return result;
/* This wrapper is used to ensure that R2 and R3 are preserved across the SWI
* This is needed because in order to generate the client's data buffer piecemeal
* (we are rewriting the headers to help the browser out and removing some that
* do not concern it at all), we keep updating R2 and R3 to avoid writing off
* the end of the buffer.
* We also take the opportunity to initialise R4 and R5 safely.
*/
const int const_buffer = r->r[2];
const int const_buflen = r->r[3];
_kernel_oserror *result;
dprintf(("readdata_1", "Buffer (R2) is &%08x; Size (R3) = %d\n", const_buffer, const_buflen));
r->r[0] = status_READING_REPLY;
r->r[4] = 0; /* No data in client buffer yet */
r->r[5] = -1; /* Unknown how much more data to read */
result = generic_exec_readdata(r);
r->r[2] = const_buffer; /* Restore buffer address */
r->r[3] = const_buflen; /* Restore buffer size */
dprintf(("readdata_1", "<< Exit SWI ReadData. Bytes read: %d\n", r->r[4]));
ddumpbuf("readdata_1", (void *)r->r[2], r->r[4], 0);
return result;
}
......@@ -81,10 +77,10 @@ static _kernel_oserror *generic_process_connected(Session *s, _kernel_swi_regs *
static _kernel_oserror *generic_return_no_more_data(Session *s, _kernel_swi_regs *r);
#ifdef TRACE
#ifdef DEBUGLIB
static void generic_show_state(const Session *s)
{
protocol_debug("FTP session %p status now %s\n", s, protocol_states(s->state));
dprintf(("readdata_1", "FTP session %p status now %s\n", s, protocol_states(s->state)));
}
#else
#define generic_show_state(s) ((void)(s))
......@@ -94,7 +90,7 @@ static void generic_show_state(const Session *s)
* with overflowing the SVC stack, it sits in a while loop dispatching on the session state until
* one of the routines returns an error or the special value "state_BLOCKING". Errors are real
* errors reported to the caller of the ReadData SWI. state_BLOCKING indicates that the SWI code
* should exit with no error. NULL indicates that the loop should be executed again. This means
* should exit with no error. NULL indicates that the loop should be executed again. This means
* that the code can arrange for the maximum amount of work to be done on each SWI call, which
* basically means that the caller is guaranteed that on exit from these calls, either an error has
* occurred, or there is buffered data waiting to be written to the client because not all of it
......@@ -112,225 +108,219 @@ static void generic_show_state(const Session *s)
*/
static _kernel_oserror *generic_readdata_dispatch(Session *s, _kernel_swi_regs *r)
{
_kernel_oserror *e = NULL;
int ctr = 0;
while (generic_show_state(s), e == NULL && ctr++<64) switch (s->state) {
/* Add any more error states to the top section here. Keep the same format, add
* new errortokens to protoerror.h and add the messages to the Messages file.
*/
default:
case protostate_ERROR:
case protostate_ERROR_DEAD:
return make_error(errortoken_ERROR_INTERNAL, 0);
case protostate_ERROR_MEM:
return make_error(errortoken_ERROR_NO_MEMORY, 0);
case protostate_ERROR_WRITE:
return make_error(errortoken_ERROR_WRITE, 0);
case protostate_ERROR_READ:
return make_error(errortoken_ERROR_READ, 0);
case protostate_ERROR_CONNECTION:
return make_error(errortoken_ERROR_NO_CONNECTION, 0);
case protostate_ERROR_NO_TOKEN:
return make_error(errortoken_ERROR_NO_TOKEN, 0);
case protostate_ERROR_NOT_IMPLEMENTED:
return make_error(errortoken_ERROR_NOT_IMPLEMENTED, 0);
case protostate_INITIAL:
case protostate_DNS: e = generic_wait_dns(s, r); break;
case protostate_CONNECTED: e = generic_process_connected(s, r); break;
case protostate_SENDING: e = commands_continue_sending(s); break;
case protostate_RECEIVING: e = commands_continue_reading(s, &s->response); break;
case protostate_PUMPING: e = generic_pump_client_response(s, r); break;
case protostate_COMPLETED: e = generic_return_no_more_data(s, r); break;
/* Add customised states to the dispatcher beneath here. If you add a new state,
* you must add the dispatch here. It should follow the format of those just above
* this comment. ie. e = functionname(s, r); break; so that the function does not
* contain any specific cleverness - only the dispatching functionality.
*/
}
if (e != NULL) {
if (e == state_BLOCKING) {
e = NULL;
}
else {
s->state = protostate_ERROR_DEAD;
}
}
return e;
_kernel_oserror *e = NULL;
int ctr = 0;
while (generic_show_state(s), e == NULL && ctr++<64) switch (s->state) {
/* Add any more error states to the top section here. Keep the same format, add
* new errortokens to protoerror.h and add the messages to the Messages file.
*/
default:
case protostate_ERROR:
case protostate_ERROR_DEAD:
return make_error(errortoken_ERROR_INTERNAL, 0);
case protostate_ERROR_MEM:
return make_error(errortoken_ERROR_NO_MEMORY, 0);
case protostate_ERROR_WRITE:
return make_error(errortoken_ERROR_WRITE, 0);
case protostate_ERROR_READ:
return make_error(errortoken_ERROR_READ, 0);
case protostate_ERROR_CONNECTION:
return make_error(errortoken_ERROR_NO_CONNECTION, 0);
case protostate_ERROR_NO_TOKEN:
return make_error(errortoken_ERROR_NO_TOKEN, 0);
case protostate_ERROR_NOT_IMPLEMENTED:
return make_error(errortoken_ERROR_NOT_IMPLEMENTED, 0);
case protostate_INITIAL:
case protostate_DNS: e = generic_wait_dns(s, r); break;
case protostate_CONNECTED: e = generic_process_connected(s, r); break;
case protostate_SENDING: e = commands_continue_sending(s); break;
case protostate_RECEIVING: e = commands_continue_reading(s, &s->response); break;
case protostate_PUMPING: e = generic_pump_client_response(s, r); break;
case protostate_COMPLETED: e = generic_return_no_more_data(s, r); break;
/* Add customised states to the dispatcher beneath here. If you add a new state,
* you must add the dispatch here. It should follow the format of those just above
* this comment. ie. e = functionname(s, r); break; so that the function does not
* contain any specific cleverness - only the dispatching functionality.
*/
}
if (e != NULL) {
if (e == state_BLOCKING) {
e = NULL;
}
else {
s->state = protostate_ERROR_DEAD;
}
}
return e;
}
static _kernel_oserror *generic_exec_readdata(_kernel_swi_regs *r)
{
Session *ses = find_session(r->r[1]);
Session *ses = find_session(r->r[1]);
/*
* Check to see session exists and has connected cleanly first
* If it doesn't/hasn't, reject this request cleanly
*/
/*
* Check to see session exists and has connected cleanly first
* If it doesn't/hasn't, reject this request cleanly
*/
if (ses == NULL) {
return make_error(errortoken_ERROR_BAD_SESSION, 0);
}
if (ses == NULL) {
return make_error(errortoken_ERROR_BAD_SESSION, 0);
}
r->r[0] = *((int *)r->r[1]) = ses->reported_state;
r->r[5] = ses->size;
r->r[0] = *((int *)r->r[1]) = ses->reported_state;
r->r[5] = ses->size;
return generic_readdata_dispatch(ses, r);
return generic_readdata_dispatch(ses, r);
}
static _kernel_oserror *gen_error(Session *s, char *errmess)
{
_kernel_oserror *e = find_error();
(void) s;
#ifdef TRACE
protocol_debug("FTP session %p error --> %s\n", s, errmess);
#endif
strncpy(e->errmess, errmess, sizeof(e->errmess));
return e;
_kernel_oserror *e = find_error();
(void) s;
dprintf(("readdata_1", "FTP session %p error --> %s\n", s, errmess));
strncpy(e->errmess, errmess, sizeof(e->errmess));
return e;
}
static _kernel_oserror *generic_return_no_more_data(Session *s, _kernel_swi_regs *r)
{
s->reported_state = *((int *)r->r[1]) = r->r[0] = status_ALL_DATA_RECEIVED;
r->r[5] = 0;
close_socket(&s->sd);
return state_BLOCKING;
s->reported_state = *((int *)r->r[1]) = r->r[0] = status_ALL_DATA_RECEIVED;
r->r[5] = 0;
close_socket(&s->sd);
return state_BLOCKING;
}
static _kernel_oserror *generic_pump_data(Session *s, _kernel_swi_regs *r, arbitrary_data *data)
{
if (r->r[3] <= 0) {
return state_BLOCKING;
}
else {
const size_t remaining = data->length - data->done;
const size_t size = generic_write_data_to_client(r, data->data + data->done, remaining);
data->done += size;
if (data->done != data->length) {
return state_BLOCKING;
}
free(data->data);
data->data = NULL;
s->state = data->next_state;
return NULL;
}
if (r->r[3] <= 0) {
return state_BLOCKING;
}
else {
const size_t remaining = data->length - data->done;
const size_t size = generic_write_data_to_client(r, data->data + data->done, remaining);
data->done += size;
if (data->done != data->length) {
return state_BLOCKING;
}
free(data->data);
data->data = NULL;
s->state = data->next_state;
return NULL;
}
}
static _kernel_oserror *generic_pump_client_response(Session *s, _kernel_swi_regs *r)
{
return generic_pump_data(s, r, &s->client_pump);
return generic_pump_data(s, r, &s->client_pump);
}
static char *generic_copy_message_token(const char *tag)
{
const char *token = NULL;
size_t token_length;
_kernel_oserror *result;
result = read_message(tag, &token, &token_length);
if (result != NULL) {
return NULL;
}
else {
if (token == NULL) {
tag = strchr(tag, ':');
if (tag != NULL) {
return Strdup(tag + 1);
}
return NULL;
}
else {
char *data = malloc(token_length+1);
if (data == NULL) {
return NULL;
}
memcpy(data, token, token_length);
data[token_length] = '\0';
return data;
}
}
const char *token = NULL;
size_t token_length;
_kernel_oserror *result;
result = read_message(tag, &token, &token_length);
if (result != NULL) {
return NULL;
}
else {
if (token == NULL) {
tag = strchr(tag, ':');
if (tag != NULL) {
return Strdup(tag + 1);
}
return NULL;
}
else {
char *data = malloc(token_length+1);
if (data == NULL) {
return NULL;
}
memcpy(data, token, token_length);
data[token_length] = '\0';
return data;
}
}
}
static void generic_vstart_client_pump(char *buffer, const char *h1, va_list ap)
{
for (*buffer = '\0'; h1; h1 = va_arg(ap, char *)) {
#ifdef TRACE
/*protocol_debug("Copying string `%s'\n", h1);*/
#endif
buffer = strcat(buffer, h1);
}
for (*buffer = '\0'; h1; h1 = va_arg(ap, char *)) {
/*dprintf(("readdata_1", "Copying string `%s'\n", h1));*/
buffer = strcat(buffer, h1);
}
}
static _kernel_oserror *generic_start_client_pump_va(Session *s, int next_state, const char *h, ...)
{
const char *h1 = h;
va_list ap;
size_t total_length = 0;
s->client_pump.next_state = next_state;
s->client_pump.done = 0;
va_start(ap, h);
while (h1 != NULL) {
#ifdef TRACE
/*protocol_debug("Adding length of `%s'\n", h1);*/
#endif
total_length += strlen(h1);
h1 = va_arg(ap, const char *);
}
va_end(ap);
s->client_pump.length = total_length;
s->client_pump.data = malloc(total_length+1);
if (s->client_pump.data == NULL) {
s->state = protostate_ERROR_MEM;
return NULL;
}
va_start(ap, h);
generic_vstart_client_pump(s->client_pump.data, h, ap);
va_end(ap);
s->state = protostate_PUMPING;
return NULL;
const char *h1 = h;
va_list ap;
size_t total_length = 0;
s->client_pump.next_state = next_state;
s->client_pump.done = 0;
va_start(ap, h);
while (h1 != NULL) {
/*dprintf(("readdata_1", "Adding length of `%s'\n", h1));*/
total_length += strlen(h1);
h1 = va_arg(ap, const char *);
}
va_end(ap);
s->client_pump.length = total_length;
s->client_pump.data = malloc(total_length+1);
if (s->client_pump.data == NULL) {
s->state = protostate_ERROR_MEM;
return NULL;
}
va_start(ap, h);
generic_vstart_client_pump(s->client_pump.data, h, ap);
va_end(ap);
s->state = protostate_PUMPING;
return NULL;
}
static _kernel_oserror *generic_start_client_pump(Session *s, int next_state, const char *h1, const char *mt_h2)
{
char *const token = generic_copy_message_token(mt_h2);
if (token == NULL) {
s->state = protostate_ERROR_NO_TOKEN;
return NULL;
}
else {
_kernel_oserror *result;
result = generic_start_client_pump_va(s, next_state, h1, token, NULL);
free(token);
return result;
}
char *const token = generic_copy_message_token(mt_h2);
if (token == NULL) {
s->state = protostate_ERROR_NO_TOKEN;
return NULL;
}
else {
_kernel_oserror *result;
result = generic_start_client_pump_va(s, next_state, h1, token, NULL);
free(token);
return result;
}
}
static _kernel_oserror *generic_wait_dns(Session *ses, _kernel_swi_regs *r)
{
int *pollword = (int *)r->r[1];
int *pollword = (int *)r->r[1];
ses->sd = opensock(ses->host, ses->port, NULL, &ses->state, ses->sd);
if (ses->sd < 0) {
ses->sd = -1;
*pollword = status_ABORTED;
return make_error(errortoken_ERROR_NO_CONNECTION, 0);
}
ses->sd = opensock(ses->host, ses->port, NULL, &ses->state, ses->sd);
if (ses->sd < 0) {
ses->sd = -1;
*pollword = status_ABORTED;
return make_error(errortoken_ERROR_NO_CONNECTION, 0);
}
*pollword = r->r[0] = ses->reported_state =
(ses->state == protostate_DNS) ? status_NOT_YET_CONNECTED : status_CONNECTED_TO_SERVER;
*pollword = r->r[0] = ses->reported_state =
(ses->state == protostate_DNS) ? status_NOT_YET_CONNECTED : status_CONNECTED_TO_SERVER;
return NULL;
return NULL;
}
/* Add other handlers below this point (end of the generic readdata.c file) */
......@@ -341,7 +331,7 @@ static _kernel_oserror *generic_process_connected(Session *s, _kernel_swi_regs *
(void) generic_start_client_pump;
(void) gen_error;
s->state = protostate_ERROR_NOT_IMPLEMENTED;
s->state = protostate_ERROR_NOT_IMPLEMENTED;
return NULL;
}
......@@ -37,122 +37,120 @@
static Session *session_list = NULL;
/*************************************************************/
/* Session *find_session(unsigned int id) */
/* Session *find_session(unsigned int id) */
/*************************************************************/
/* Given a session ID, return the session control block */
/* associated with it. */
/* Given a session ID, return the session control block */
/* associated with it. */
/*************************************************************/
Session *find_session(unsigned int id)
{
Session *session;
Session *session;
for (session = session_list; session; session = session->next) {
if (session->id == id) return session;
}
for (session = session_list; session; session = session->next) {
if (session->id == id) return session;
}
return NULL;
return NULL;
}
/*************************************************************/
/* Session *new_session(void) */
/* Session *new_session(void) */
/*************************************************************/
/* Create a new session, taking into account starting the */
/* sessions list */
/* sessions list */
/*************************************************************/
Session *new_session(void)
{
Session *ses = calloc(1, sizeof(Session));
Session *ses = calloc(1, sizeof(Session));
if (ses == NULL) {
return ses;
}
if (ses == NULL) {
return ses;
}
ses->sd = -1;
ses->sd = -1;
if (session_list == NULL) {
/* no list so create a new one */
session_list = ses;
}
else {
/* else find end of list and add an element */
Session *s;
if (session_list == NULL) {
/* no list so create a new one */
session_list = ses;
}
else {
/* else find end of list and add an element */
Session *s;
for (s=session_list; s->next; s=s->next) ;;
s->next = ses;
}
for (s=session_list; s->next; s=s->next) ;;
s->next = ses;
}
return ses;
return ses;
}
static Session *kill_session_data(Session *s)
{
Session *result = s->next;
close_socket(&s->sd);
http_free_headers(&s->headers);
free(s->command.data);
free(s->response.data);
free(s->client_pump.data);
free(s->uri);
free(s->url);
free(s->host);
free(s->data);
free(s->agent);
/* Insert protocol specific stuff here */
/* End protocol specific stuff here */
memset(s, '\0', sizeof(*s)); /* Let's be careful */
free(s);
return result;
Session *result = s->next;
close_socket(&s->sd);
http_free_headers(&s->headers);
free(s->command.data);
free(s->response.data);
free(s->client_pump.data);
free(s->uri);
free(s->url);
free(s->host);
free(s->data);
free(s->agent);
/* Insert protocol specific stuff here */
/* End protocol specific stuff here */
memset(s, '\0', sizeof(*s)); /* Let's be careful */
free(s);
return result;
}
/*************************************************************/
/* void kill_session(Session *s) */
/* void kill_session(Session *s) */
/*************************************************************/
/* Given the location of the session block, delete the */
/* Given the location of the session block, delete the */
/* session cleanly, taking into account the session next */
/* pointers and any memory associated with it */
/* pointers and any memory associated with it */
/*************************************************************/
void kill_session(Session *s)
{
Session *ses = session_list, *prev_ses = NULL;
for (ses = session_list; ses; prev_ses = ses, ses = ses->next) {
if (ses == s) {
Session *const next = kill_session_data(s);
if (prev_ses == NULL) {
session_list = next;
}
else {
prev_ses->next = next;
}
break;
}
}
#ifdef TRACE
protocol_debug("\nkill_session %p completed. Dump of session chain\n", s);
for (ses=session_list; ses; ses=ses->next) {
protocol_debug("%p (socket %d) URL %s\n", ses, ses->sd, ses->url);
}
protocol_debug("End of session chain\n\n");
#endif
Session *ses = session_list, *prev_ses = NULL;
for (ses = session_list; ses; prev_ses = ses, ses = ses->next) {
if (ses == s) {
Session *const next = kill_session_data(s);
if (prev_ses == NULL) {
session_list = next;
}
else {
prev_ses->next = next;
}
break;
}
}
dprintf(("sesctrl_1", "\nkill_session %p completed. Dump of session chain\n", s));
for (ses=session_list; ses; ses=ses->next) {
dprintf(("sesctrl_1", "%p (socket %d) URL %s\n", ses, ses->sd, ses->url));
}
dprintf(("sesctrl_1", "End of session chain\n\n"));
}
/*************************************************************/
/* void ses_kill_all(void) */
/* void ses_kill_all(void) */
/*************************************************************/
/* A small routine to kill off all sessions at module shut- */
/* down. */
/* down. */
/*************************************************************/
void ses_kill_all(void)
{
while (session_list) {
kill_session(session_list);
}
while (session_list) {
kill_session(session_list);
}
}
......@@ -164,7 +162,7 @@ void ses_kill_all(void)
*/
void session_check(void)
{
/* Nothing */
/* Nothing */
}
/* session_init is called by the module's init entry to ensure
......
......@@ -43,168 +43,158 @@ static void start_get_request(const char *url, char **host, int *port, char **ur
_kernel_oserror *generic_start(_kernel_swi_regs *r)
{
int flags = r->r[0];
int *pollword = (int *)r->r[1];
char *url = (char *)r->r[3];
char *data = (char *)r->r[4];
int style = r->r[5];
char *uri;
char *urlcopy;
char *host;
int port;
Session *ses;
#ifdef TRACE
protocol_debug("Asking for url %s\n", url);
#endif
(void) flags;
MemCheck_RegisterMiscBlock((void *) url,strlen(url)+1);
MemCheck_SetBlockAccess((void *) url,1,0);
/* Check to see if this session already exists before doing anything */
if (find_session(r->r[1])) {
return make_error(errortoken_ERROR_BAD_SESSION, 0);
}
/* Create a session control block */
ses = new_session();
if (ses == NULL) {
return make_error(errortoken_ERROR_NO_SESSION, 0);
}
/* fill in a few bits */
ses->id = (unsigned int)pollword;
ses->uri = NULL;
ses->url = NULL;
if (flags & flags_DATA_LENGTH_IN_R5) {
style = ((r->r[2] >> 8) & 0xFF);
r->r[2] &= 0xFF;
}
else {
style = r->r[5];
}
/* Now work out the host and port and URI bit we are after */
host = NULL;
uri = NULL;
start_get_request(url, &host, &port, &uri, &urlcopy);
if (host == NULL) {
int flags = r->r[0];
int *pollword = (int *)r->r[1];
char *url = (char *)r->r[3];
char *data = (char *)r->r[4];
int style = r->r[5];
char *uri;
char *urlcopy;
char *host;
int port;
Session *ses;
dprintf(("start_1", "Asking for url %s\n", url));
(void) flags;
MemCheck_RegisterMiscBlock((void *) url,strlen(url)+1);
MemCheck_SetBlockAccess((void *) url,1,0);
/* Check to see if this session already exists before doing anything */
if (find_session(r->r[1])) {
return make_error(errortoken_ERROR_BAD_SESSION, 0);
}
/* Create a session control block */
ses = new_session();
if (ses == NULL) {
return make_error(errortoken_ERROR_NO_SESSION, 0);
}
/* fill in a few bits */
ses->id = (unsigned int)pollword;
ses->uri = NULL;
ses->url = NULL;
if (flags & flags_DATA_LENGTH_IN_R5) {
style = ((r->r[2] >> 8) & 0xFF);
r->r[2] &= 0xFF;
}
else {
style = r->r[5];
}
/* Now work out the host and port and URI bit we are after */
host = NULL;
uri = NULL;
start_get_request(url, &host, &port, &uri, &urlcopy);
if (host == NULL) {
kill_session(ses);
return make_error(errortoken_ERROR_NO_URL_DECODE, 0);
}
return make_error(errortoken_ERROR_NO_URL_DECODE, 0);
}
#ifdef TRACE
protocol_debug("Host:%s Port:%d URI:%s URL:%s\n", host, port, uri, urlcopy);
#endif
dprintf(("start_1", "Host:%s Port:%d URI:%s URL:%s\n", host, port, uri, urlcopy));
ses->uri = uri;
ses->url = urlcopy;
ses->data = data;
ses->uri = uri;
ses->url = urlcopy;
ses->data = data;
ses->host = host;
ses->port = port;
ses->host = host;
ses->port = port;
MemCheck_UnRegisterMiscBlock((void *) url);
MemCheck_UnRegisterMiscBlock((void *) url);
/* establish the connection */
#ifdef TRACE
protocol_debug("Preparing to send URL %s to %s port %d\n", uri, host, port);
#endif
/* establish the connection */
dprintf(("start_1", "Preparing to send URL %s to %s port %d\n", uri, host, port));
ses->state = protostate_INITIAL;
return NULL;
ses->state = protostate_INITIAL;
return NULL;
}
static void start_get_request(const char *url, char **host, int *port, char **uri, char **urlcopy)
{
URL u;
_kernel_oserror *e;
int i;
size_t path_len, query_len;
*uri = NULL;
*host = NULL;
*urlcopy = NULL;
*port = CONNECT_DEFAULT_PORT_NUMBER;
e = URL_find_lengths(0, url, NULL, &u);
if (e) {
#ifdef TRACE
protocol_debug("start_get_request> URL_find_lengths> %s\n", e->errmess);
#endif
return;
}
path_len = u.lengths.path;
query_len = u.lengths.query;
for (i=0; i<URL_fields; ++i) switch (i) {
case urlfield_HOST:
case urlfield_PORT:
case urlfield_FULL:
case urlfield_SCHEME:
if (u.len[i]) {
u.field[i] = malloc(u.len[i]);
}
break;
case urlfield_PATH:
u.data.path = malloc(path_len + query_len + 2);
if (u.data.path != NULL) {
if (query_len == 0) {
u.data.query = NULL;
}
else {
u.data.query = u.data.path + path_len;
}
if (path_len == 0) {
u.data.path[0] = '\0';
++path_len;
if (query_len > 0) {
u.data.query++;
}
}
}
else {
u.data.query = NULL;
}
break;
case urlfield_QUERY:
break;
default:
u.field[i] = NULL;
break;
}
e = URL_find_data(0, url, NULL, &u);
if (e) {
#ifdef TRACE
protocol_debug("start_get_request> URL_find_data> %s\n", e->errmess);
#endif
for (i=0; i<URL_fields; ++i) {
if (i != urlfield_QUERY) free(u.field[i]);
}
return;
}
if (path_len > 0 && query_len > 0) {
u.data.path[path_len - 1] = '?';
}
*uri = u.data.path;
*host = u.data.host;
*urlcopy = u.data.full;
if (u.data.port) {
int i = atoi(u.data.port);
if (i != 0) *port = i;
free(u.data.port);
}
/* Check the scheme here if we handle multiple schemes */
free(u.data.scheme);
URL u;
_kernel_oserror *e;
int i;
size_t path_len, query_len;
*uri = NULL;
*host = NULL;
*urlcopy = NULL;
*port = CONNECT_DEFAULT_PORT_NUMBER;
e = URL_find_lengths(0, url, NULL, &u);
if (e) {
dprintf(("start_1", "start_get_request> URL_find_lengths> %s\n", e->errmess));
return;
}
path_len = u.lengths.path;
query_len = u.lengths.query;
for (i=0; i<URL_fields; ++i) switch (i) {
case urlfield_HOST:
case urlfield_PORT:
case urlfield_FULL:
case urlfield_SCHEME:
if (u.len[i]) {
u.field[i] = malloc(u.len[i]);
}
break;
case urlfield_PATH:
u.data.path = malloc(path_len + query_len + 2);
if (u.data.path != NULL) {
if (query_len == 0) {
u.data.query = NULL;
}
else {
u.data.query = u.data.path + path_len;
}
if (path_len == 0) {
u.data.path[0] = '\0';
++path_len;
if (query_len > 0) {
u.data.query++;
}
}
}
else {
u.data.query = NULL;
}
break;
case urlfield_QUERY:
break;
default:
u.field[i] = NULL;
break;
}
e = URL_find_data(0, url, NULL, &u);
if (e) {
dprintf(("start_1", "start_get_request> URL_find_data> %s\n", e->errmess));
for (i=0; i<URL_fields; ++i) {
if (i != urlfield_QUERY) free(u.field[i]);
}
return;
}
if (path_len > 0 && query_len > 0) {
u.data.path[path_len - 1] = '?';
}
*uri = u.data.path;
*host = u.data.host;
*urlcopy = u.data.full;
if (u.data.port) {
int i = atoi(u.data.port);
if (i != 0) *port = i;
free(u.data.port);
}
/* Check the scheme here if we handle multiple schemes */
free(u.data.scheme);
}
......@@ -28,24 +28,24 @@
_kernel_oserror *generic_status(_kernel_swi_regs *r)
{
int *pollword=(int *)r->r[1];
Session *ses;
int *pollword=(int *)r->r[1];
Session *ses;
ses = find_session(r->r[1]);
if (ses == NULL) {
ses = find_session(r->r[1]);
if (ses == NULL) {
r->r[0] = r->r[2] = r->r[3] = r->r[4] = 0;
return NULL;
}
return NULL;
}
r->r[0] = *pollword = ses->reported_state;
r->r[3] = ses->sent;
r->r[0] = *pollword = ses->reported_state;
r->r[3] = ses->sent;
/* Note. The following condition is CORRECT. We don't want to confuse the caller
* into thinking that there is no more data left just because we've seen a
* Content-Length: 0 header. We need it to continue to read the header information.
* Only once we are into body transfers can be legally set this to zero
*/
r->r[4] = ses->size > 0 ? ses->size : -1;
/* Note. The following condition is CORRECT. We don't want to confuse the caller
* into thinking that there is no more data left just because we've seen a
* Content-Length: 0 header. We need it to continue to read the header information.
* Only once we are into body transfers can be legally set this to zero
*/
r->r[4] = ses->size > 0 ? ses->size : -1;
return NULL;
return NULL;
}
......@@ -28,17 +28,15 @@
_kernel_oserror *generic_stop(_kernel_swi_regs *r)
{
Session *ses;
Session *ses;
r->r[0] = 0;
ses = find_session(r->r[1]);
r->r[0] = 0;
ses = find_session(r->r[1]);
#ifdef TRACE
protocol_debug("Stop SWI for session %p\n", ses);
#endif
dprintf(("stop_1", "Stop SWI for session %p\n", ses));
/* kill_session validates session pointer anyway */
kill_session(ses);
/* kill_session validates session pointer anyway */
kill_session(ses);
return NULL;
return NULL;
}
......@@ -32,53 +32,53 @@ static int messages_fd[4];
_kernel_oserror *read_message (const char *token, const char **buffer, size_t *inoutlength)
{
return _swix(MessageTrans_Lookup, _INR(0,7)|_OUTR(2,3), messages_fd, token, *buffer,
*inoutlength, 0, 0, 0, 0, buffer, inoutlength);
return _swix(MessageTrans_Lookup, _INR(0,7)|_OUTR(2,3), messages_fd, token, *buffer,
*inoutlength, 0, 0, 0, 0, buffer, inoutlength);
}
_kernel_oserror *find_error (void)
{
static _kernel_oserror global_error_block[ERR_BLOCKS];
static int errblock = 0;
static _kernel_oserror global_error_block[ERR_BLOCKS];
static int errblock = 0;
errblock = (errblock+1) % ERR_BLOCKS;
return &global_error_block[errblock];
errblock = (errblock+1) % ERR_BLOCKS;
return &global_error_block[errblock];
}
_kernel_oserror *make_error (int err_num, int num_args, ...)
{
_kernel_oserror *e, *ptr = find_error();
va_list ap;
char *s, token[4];
int i=4;
char *sub[4]={0,0,0,0};
_kernel_oserror *e, *ptr = find_error();
va_list ap;
char *s, token[4];
int i=0;
char *sub[4]={0,0,0,0};
ptr->errnum = err_num;
ptr->errnum = err_num;
num_args = (num_args>4)?4:num_args;
num_args = (num_args>4)?4:num_args;
for (va_start(ap, num_args); num_args--; i++) {
s = va_arg (ap, char *);
sub[i] = (s && *s) ? s : NULL; /* copy (pointer to args)s into registers */
}
va_end (ap);
for (va_start(ap, num_args); num_args--; i++) {
s = va_arg (ap, char *);
sub[i] = (s && *s) ? s : NULL; /* copy (pointer to args)s into registers */
}
va_end (ap);
sprintf (token, "E%02x", err_num&0x1f);
sprintf (token, "E%02x", err_num&0x1f);
e = _swix(MessageTrans_Lookup, _INR(0,7), messages_fd, token, ptr->errmess,
sizeof(*ptr) - sizeof(ptr->errnum) /* 252! */,
sub[0],sub[1],sub[2],sub[3]);
return ptr;
e = _swix(MessageTrans_Lookup, _INR(0,7), messages_fd, token, ptr->errmess,
sizeof(*ptr) - sizeof(ptr->errnum) /* 252! */,
sub[0],sub[1],sub[2],sub[3]);
return ptr;
}
_kernel_oserror *messages_file_open (char *messages_filename)
{
return _swix(MessageTrans_OpenFile, _INR(0,2), messages_fd, messages_filename, 0);
return _swix(MessageTrans_OpenFile, _INR(0,2), messages_fd, messages_filename, 0);
}
_kernel_oserror *messages_file_close (void)
{
return _swix(MessageTrans_CloseFile, _IN(0), messages_fd);
return _swix(MessageTrans_CloseFile, _IN(0), messages_fd);
}
......@@ -38,28 +38,24 @@ int generic_write_data_to_client(_kernel_swi_regs *r, const char *buffer, int si
{
int copied = r->r[3] > size ? size : r->r[3];
if (copied > 0) {
char *const dest = (char *) r->r[2];
if (dest != buffer && buffer != NULL) {
memcpy(dest, buffer, copied);
#ifdef TRACE
protocol_debug("Copying data to client buffer:\n");
protocol_dump(dest, copied);
#endif
}
else {
#ifdef TRACE
protocol_debug("Client data already in situ\n");
#endif
}
}
else {
copied = 0;
}
if (copied > 0) {
char *const dest = (char *) r->r[2];
if (dest != buffer && buffer != NULL) {
memcpy(dest, buffer, copied);
dprintf(("writedata_1", "Copying data to client buffer:\n"));
/*ddumpbuf("writedata_1", dest, copied, 0);*/
}
else {
dprintf(("writedata_1", "Client data already in situ\n"));
}
}
else {
copied = 0;
}
r->r[2] += copied; /* increment buffer - ReadData SWI preserves this */
r->r[3] -= copied; /* Decrement buflen - ReadData SWI preserves this */
r->r[4] += copied; /* Increment sent counter */
return copied;
r->r[2] += copied; /* increment buffer - ReadData SWI preserves this */
r->r[3] -= copied; /* Decrement buflen - ReadData SWI preserves this */
r->r[4] += copied; /* Increment sent counter */
return copied;
}
......@@ -30,13 +30,13 @@ extern int opensock(char *name, int port, char *sername, int *state, int fd);
*
* Typically they will have been defined in protostate.h
*/
#define CONNECT_ERROR_STATE protostate_ERROR
#define CONNECT_ERROR_STATE protostate_ERROR
#define CONNECT_DNS_STATE protostate_DNS
#define CONNECT_CONNECTED_STATE protostate_CONNECTED
/* The following define the protocol being implemented and its default
* port number
*/
#define CONNECT_DEFAULT_PROTOCOL_NAME "echo"
#define CONNECT_DEFAULT_PORT_NUMBER 7
#define CONNECT_DEFAULT_PROTOCOL_NAME "echo"
#define CONNECT_DEFAULT_PORT_NUMBER 7
......@@ -23,19 +23,16 @@
#include <time.h>
#define TRUE 1
#define FALSE 0
typedef enum {
flags_USER_AGENT_IN_R6 = 1,
flags_DATA_LENGTH_IN_R5 = 2
flags_USER_AGENT_IN_R6 = 1,
flags_DATA_LENGTH_IN_R5 = 2
} network_protocol_start_swi_r0_flags;
typedef struct {
int next_state; /* State to enter when all data "done" */
char *data; /* Data itself */
size_t length; /* Total length of data */
size_t done; /* Amount written so far, or read so far */
int next_state; /* State to enter when all data "done" */
char *data; /* Data itself */
size_t length; /* Total length of data */
size_t done; /* Amount written so far, or read so far */
} arbitrary_data;
/* Structure for remembering headers - can be applicable to protocols other than
......@@ -45,43 +42,43 @@ typedef struct {
*/
typedef struct http_header http_header;
struct http_header {
http_header *next; /* Link to next member */
char *header; /* Pointer into text member - is the HTTP header tag */
char *value; /* Pointer into text member - is the tag value setting */
char text[1]; /* Entire header but ':' and "\r\n" represented by '\0' terminators */
http_header *next; /* Link to next member */
char *header; /* Pointer into text member - is the HTTP header tag */
char *value; /* Pointer into text member - is the tag value setting */
char text[1]; /* Entire header but ':' and "\r\n" represented by '\0' terminators */
};
typedef struct session {
struct session *next; /* Pointer to next session */
int state; /* The state of this session */
int error_state; /* Used to record the state before an error occurred */
int reported_state; /* R0 status returned on last SWI call (used by status SWI) */
unsigned int id; /* Client handle */
int sd; /* Socket descriptor */
int server_code; /* Server response code */
int size; /* expected size of retrieved object - 0 if unknown */
unsigned int sent; /* Amount of data sent to the client in total by this module */
char *uri; /* Specific part of the URI */
char *url; /* Full URI of the document being fetched */
char *host; /* Host name of the host being contacted */
int port; /* Port number of the host being contacted */
char *data; /* Additional client data to be sent to server */
int data_len; /* Size of data pointed to by 'data'. strlen(data) if not known */
char *agent; /* User-Agent string to be sent - NULL to use this module's own ID */
int donehead; /* Set to non-zero if we have sent our client an HTTP response header */
int reused_socket; /* Set to non-zero when a socket is being re-used on a persistent connection */
http_header *headers; /* List of headers */
char *current_header;/* Holds the current header buffer */
int hdrptr; /* Pointer into current_header */
time_t last; /* Last activity timeout */
arbitrary_data command; /* Queued "command" data being sent to remote server */
arbitrary_data response; /* Reception buffers for receiving data from remote server */
arbitrary_data client_pump; /* Data being pumped to our client */
int response_code; /* Holds the response code for the latest response read */
/* Protocol specific members added here */
/* End protocol specific members */
struct session *next; /* Pointer to next session */
int state; /* The state of this session */
int error_state; /* Used to record the state before an error occurred */
int reported_state; /* R0 status returned on last SWI call (used by status SWI) */
unsigned int id; /* Client handle */
int sd; /* Socket descriptor */
int server_code; /* Server response code */
int size; /* expected size of retrieved object - 0 if unknown */
unsigned int sent; /* Amount of data sent to the client in total by this module */
char *uri; /* Specific part of the URI */
char *url; /* Full URI of the document being fetched */
char *host; /* Host name of the host being contacted */
int port; /* Port number of the host being contacted */
char *data; /* Additional client data to be sent to server */
int data_len; /* Size of data pointed to by 'data'. strlen(data) if not known */
char *agent; /* User-Agent string to be sent - NULL to use this module's own ID */
int donehead; /* Set to non-zero if we have sent our client an HTTP response header */
int reused_socket; /* Set to non-zero when a socket is being re-used on a persistent connection */
http_header *headers; /* List of headers */
char *current_header;/* Holds the current header buffer */
int hdrptr; /* Pointer into current_header */
time_t last; /* Last activity timeout */
arbitrary_data command; /* Queued "command" data being sent to remote server */
arbitrary_data response; /* Reception buffers for receiving data from remote server */
arbitrary_data client_pump; /* Data being pumped to our client */
int response_code; /* Holds the response code for the latest response read */
/* Protocol specific members added here */
/* End protocol specific members */
} Session;
......@@ -117,7 +114,7 @@ extern char *module_realloc(void */*ptr*/, size_t /*size*/);
* handler and wait to be called by the client again because we
* are busy waiting for a network response or a buffer empty.
*/
#define state_BLOCKING ((_kernel_oserror *)-3)
#define state_BLOCKING ((_kernel_oserror *)-3)
/* Switches to user mode, does an OS_Byte 0, switches back
* thus allowing callbacks to fire
......
......@@ -25,13 +25,13 @@
*/
typedef enum {
status_NOT_YET_CONNECTED = 0,
status_NOT_YET_CONNECTED = 0,
status_CONNECTED_TO_SERVER = 1,
status_SENT_REQUEST = 2,
status_SENT_DATA = 4,
status_WAIT_INITIAL_RESPONSE = 7,
status_HAVE_INITIAL_RESPONSE = 8,
status_WAIT_FOR_BODY = 15,
status_WAIT_FOR_BODY = 15,
status_TRANSFER_IN_PROGRESS = 16,
status_READING_REPLY = 31,
status_ALL_DATA_RECEIVED = 32,
......@@ -46,23 +46,32 @@ typedef enum {
* generate more meaningful error messages if the method is a known one)
*/
typedef enum {
method_GET = 1,
method_HEAD = 2,
method_OPTIONS = 3,
method_POST = 4,
method_TRACE = 5,
method__resv_1 = 6,
method__resv_2 = 7,
method_PUT = 8,
method_MKDIR = 9,
method_RMDIR = 10,
method_RENAME = 11,
method_DELETE = 12,
method_FTP_STOU = 13
method_GET = 1,
method_HEAD = 2,
method_OPTIONS = 3,
method_POST = 4,
method_TRACE = 5,
method__resv_1 = 6,
method__resv_2 = 7,
method_PUT = 8,
method_MKDIR = 9,
method_RMDIR = 10,
method_RENAME = 11,
method_DELETE = 12,
method_FTP_STOU = 13
} protocol_method_in_r2_codes;
#include "protostate.h"
#include "protoerror.h"
#include "DebugLib.h"
#ifndef BOOL_DEFINED
#define BOOL_DEFINED
#ifndef BOOL
#define BOOL int
#define TRUE 1
#define FALSE 0
#endif
#endif
#pragma -v1
extern void protocol_debug(const char */*format*/, ...);
......
......@@ -29,7 +29,7 @@
*/
#define URL_ERROR_BASE (0x80de00) /* URL module base */
#define URL_ERROR2_BASE (0x813f00) /* Second URL error block base */
#define URL_ERROR2_BASE (0x813f00) /* Second URL error block base */
/* Acorn fetcher modules use a sub-block of the URL module block
* Non-Acorn fetcher modules should use a block of 32 errors from
......@@ -42,14 +42,14 @@
* generate and return to you a _kernel_oserror block suitable for
* returning to the client of the module.
*/
#define PROTO_ERROR_BLOCK (URL_ERROR_BASE)
#define PROTO_MODULE_OFFSET 0
#define PROTO_ERROR_BLOCK (URL_ERROR_BASE)
#define PROTO_MODULE_OFFSET 0
#define ERROR_BASE (PROTO_ERROR_BLOCK + PROTO_MODULE_OFFSET)
#define ERROR_BASE (PROTO_ERROR_BLOCK + PROTO_MODULE_OFFSET)
typedef enum {
errortoken_ERROR_BAD_SESSION = (ERROR_BASE),
errortoken_ERROR_NO_SESSION,
errortoken_ERROR_NO_SESSION,
errortoken_ERROR_NO_CONNECTION,
errortoken_ERROR_NO_URL_DECODE,
errortoken_ERROR_NO_MEMORY,
......
......@@ -28,20 +28,20 @@
*
*/
typedef enum {
protostate_ERROR,
protostate_ERROR_DEAD,
protostate_ERROR_MEM,
protostate_ERROR_WRITE,
protostate_ERROR_READ,
protostate_ERROR_CONNECTION,
protostate_ERROR_NO_TOKEN,
protostate_ERROR_NOT_IMPLEMENTED,
protostate_ERROR,
protostate_ERROR_DEAD,
protostate_ERROR_MEM,
protostate_ERROR_WRITE,
protostate_ERROR_READ,
protostate_ERROR_CONNECTION,
protostate_ERROR_NO_TOKEN,
protostate_ERROR_NOT_IMPLEMENTED,
protostate_INITIAL,
protostate_DNS,
protostate_CONNECTED,
protostate_SENDING,
protostate_RECEIVING,
protostate_PUMPING,
protostate_COMPLETED
protostate_INITIAL,
protostate_DNS,
protostate_CONNECTED,
protostate_SENDING,
protostate_RECEIVING,
protostate_PUMPING,
protostate_COMPLETED
} network_protocol_fsm_states;
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment