/*
* fcp.c: Implementations for the fcp API (talk to the freenet node)
*
* ====================================================================
* Copyleft (c) 2007 saces.
*
* License:
*
* (1) You just DO WHAT THE FUCK YOU WANT TO.
*
* (2) This software comes with none kind of warranty.
* Use at your own risk.
* ====================================================================
*/
#include <apr_general.h>
#include <apr_network_io.h>
#include <apr_poll.h>
#include "svn_error.h"
#include "svn_string.h"
#include "fcp.h"
#include "svn_private_config.h"
/* FcpConnect
Connect to a freenet server */
svn_error_t *
FcpConnect(fcp_connection_t *connection, apr_pool_t *pool)
{
/* dig the host*/
const char *host = getenv(ENVNAME_FCP_HOST);
if (host==NULL || strlen(host)==0)
host = DEFAULT_FCP_HOST;
/* dig the port*/
const char *sport = getenv(ENVNAME_FCP_PORT);
int port = 0;
if (sport)
port = atoi(sport);
if (port <= 0)
port = DEFAULT_FCP_PORT;
return FcpConnect2(connection, host, port, pool);
}
svn_error_t *
FcpConnect2(fcp_connection_t *connection, const char *hostname, int port, apr_pool_t *pool)
{
apr_sockaddr_t *sa;
apr_status_t status;
int family = APR_INET;
apr_socket_t *sock;
svn_string_t *identifier;
/* Identifier stuff: generate an (hopefully) unique one */
identifier = svn_string_createf(pool, "freenetsvn-%s", svn_time_to_cstring(apr_time_now(), pool));
/* Make sure we have IPV6 support first before giving apr_sockaddr_info_get
APR_UNSPEC, because it may give us back an IPV6 address even if we can't
create IPV6 sockets. */
#if APR_HAVE_IPV6
#ifdef MAX_SECS_TO_LINGER
status = apr_socket_create(&sock, APR_INET6, SOCK_STREAM, pool);
#else
status = apr_socket_create(&sock, APR_INET6, SOCK_STREAM,
APR_PROTO_TCP, pool);
#endif
if (status == 0)
{
apr_socket_close(sock);
family = APR_UNSPEC;
}
#endif
/* Resolve the hostname. */
status = apr_sockaddr_info_get(&sa, hostname, family, port, 0, pool);
if (status)
return svn_error_createf(status, NULL, _("Unknown hostname '%s'"),
hostname);
/* Create the socket. */
#ifdef MAX_SECS_TO_LINGER
/* ### old APR interface */
status = apr_socket_create(&sock, sa->family, SOCK_STREAM, pool);
#else
status = apr_socket_create(&sock, sa->family, SOCK_STREAM, APR_PROTO_TCP,
pool);
#endif
if (status)
return svn_error_wrap_apr(status, _("Can't create socket"));
status = apr_socket_connect(sock, sa);
if (status)
return svn_error_wrap_apr(status, _("Can't connect to host '%s'"),
hostname);
/* socket etablished, do node helo
chek node version */
svn_string_t * helomsg = svn_string_createf(pool,
"ClientHello\nName=%s\nExpectedVersion=2.0\nEndMessage\n",
identifier->data);
apr_size_t len = helomsg->len;
status = apr_socket_send(sock, helomsg->data, &len);
if (status)
{
apr_socket_close(sock);
return svn_error_wrap_apr(status, _("Can't write to connection"));
}
/* sock seems pysically ok, make it valid before logic check
from now we return SVN_ERR_FCP* errors only */
connection->pool = pool;
connection->sock = sock;
fcp_message * msg = ReadEndMessage(connection, pool);
/* if (isMessageName(msg, "NodeHello")) */
return svn_error_createf(SVN_ERR_FCP_UNEXPECTET, NULL, "Unexpected reply from node: \n%s", (MessageToString(msg, pool))->data);
/* printf("Go on here: %s:%d\n", __FILE__, __LINE__); */
/* check minimum node version (build number is meant!) */
/*if ((getMessegeItemValueInt32(msg, )
getMessegeItemValueInt32(msg, const char *key, );
*/
return SVN_NO_ERROR;
}
void
FcpDisconnect(fcp_connection_t *connection)
{
;
}
#define FCP_MAXLINELENGTH 4096
fcp_message *ReadEndMessage(fcp_connection_t *connection, apr_pool_t *pool)
{
fcp_message *result;
result = apr_pcalloc(pool, sizeof(fcp_message));
result->items = apr_hash_make(pool);
/* read buffer */
char buf[FCP_MAXLINELENGTH];
/* local temps for read loop */
char bufchar;
apr_size_t len;
/* Always block on read. */
apr_socket_timeout_set(connection->sock, -1);
/* read the first line, its the message name */
int readcount = 0;
while(readcount < FCP_MAXLINELENGTH)
{
len = 1;
result->iostatus = apr_socket_recv(connection->sock, &bufchar, &len);
if (len) /* a char (byte) is read, put into buffer */
{
if (bufchar == '\n')
{
result->name = svn_string_ncreate(buf, readcount, pool);
buf[0] = '\0';
break;
}
else
{
buf[readcount] = bufchar;
buf[readcount + 1] = '\0';
readcount++;
}
}
if (result->iostatus) {
result->lastline = svn_string_ncreate(buf, readcount, pool);
return result;
}
}
/* now we have the messege name, a few lines Item=Value should follow.
parse until endmarker ( a line without '=') */
fcp_message_item *message_item;
while (!result->endmarker)
{
/* read a line */
readcount = 0;
svn_boolean_t is_endmarker = TRUE;
buf[0] = '\0';
while(readcount < FCP_MAXLINELENGTH)
{
len = 1;
result->iostatus = apr_socket_recv(connection->sock, &bufchar, &len);
/* printf("ReadCount: %d\n", readcount); */
if (len) /* a char (byte) is read, put into buffer */
{
if ((bufchar == '=') && (is_endmarker))
{
/* endmarker still true, so its the first '=',
here to split the Item=Value pair, more '=' are part of value and ignored here*/
/* printf("Test00: new msg item\n"); */
message_item = apr_pcalloc(pool, sizeof(message_item));
message_item->name = svn_string_ncreate(buf, readcount, pool);
printf("Test01: %s\n", message_item->name->data);
/* reset buf */
readcount = 0;
buf[0] = '\0';
is_endmarker = FALSE;
/* next char */
continue;
}
if (bufchar == '\n')
{
/* printf("Test02ENDL\n"); */
if (is_endmarker)
{
result->endmarker = svn_string_ncreate(buf, readcount, pool);
/* fertsch */
break;
}
else
{ /* add pair */
message_item->type = fcp_message_item_type_string;
svn_string_t *s = svn_string_ncreate(buf, readcount, pool);
message_item->value.string_item = svn_string_ncreate(buf, readcount, pool);
printf("The following line should be identical with Test01 (same variable)\n");
printf("Test02: %s\n", message_item->name->data); /* <-- hm. problem should be the same output like "Test01" */
printf("shit print line: %s:%d\n", __FILE__, __LINE__-1);
/* printf("Test02y: ");
printf("Test02y %s\n", s->data);
printf("Test02: %s : %s\n", message_item->name->data, (message_item->value.string_item)->data); */
apr_hash_set(result->items, message_item->name->data, APR_HASH_KEY_STRING, message_item);
message_item = NULL;
}
/* result->name = svn_string_ncreate(buf, readcount, pool); */
buf[0] = '\0';
readcount = 0;
break;
}
else
{
/* printf("-ReadCount: %d\n", readcount); */
buf[readcount] = bufchar;
buf[readcount + 1] = '\0';
/* printf("-ReadCount: %s\n", buf); */
readcount++;
}
}
if (result->iostatus) {
result->lastline = svn_string_ncreate(buf, readcount, pool);
return result;
}
}
}
return result;
}
svn_boolean_t isMessageName(const fcp_message * message, const char *name)
{
return svn_string_compare_cstring(message->name, name);
}
static APR_INLINE void
stringbuf_appendnl(svn_stringbuf_t *str)
{
svn_stringbuf_appendbytes(str, "\n", 1);
}
svn_string_t * MessageToString(const fcp_message * message, apr_pool_t *pool)
{
svn_stringbuf_t * msgbuf = svn_stringbuf_create_from_string(message->name, pool);
stringbuf_appendnl(msgbuf);
apr_hash_index_t *hi;
void *val;
for (hi = apr_hash_first(pool, message->items); hi; hi = apr_hash_next(hi)) {
apr_hash_this(hi, NULL, NULL, &val);
svn_stringbuf_appendsstr(msgbuf, MessegeItemToString((fcp_message_item *)val, pool));
stringbuf_appendnl(msgbuf);
}
svn_stringbuf_appendsstr(msgbuf, message->endmarker);
stringbuf_appendnl(msgbuf);
return svn_string_create_from_buf(msgbuf, pool);
}
svn_string_t *MessegeItemToString(const fcp_message_item * messageitem, apr_pool_t *pool)
{
switch (messageitem->type) {
case fcp_message_item_type_string: return svn_string_createf(pool, "%s=%s", messageitem->name->data, (messageitem->value.string_item)->data);
/* fcp_message_item_type_int32: return ;
fcp_message_item_type_int64: return ;
fcp_message_item_type_bool: return ; */
default:
return svn_string_createf(pool, "TODO: %s:%d -> type: %d\n", __FILE__, __LINE__, messageitem->type);
}
return NULL;
}
Welcome to the bulix.org / pastebin. Please don't use this pastebin for illegal purposes, defamation or kitten-squashing.
This pastebin is written using PHP and MySQL and relies on Alex Gorbatchev's syntax hhighlighter (JavaScript based). To avoid spam, you will be required to complete a small mathematical challenge when adding a new paste.
New! Try the pastebin command-line tool: paste.py (requires Python and python-beautifulsoup).
Powered by the Bulix.org Code Pastebin, by Maxime Petazzoni. View pastebin statistics.