/**
* @file transport/plugin_transport_wlan.c
- * @brief template for a new transport service
- * @author Christian Grothoff
+ * @brief transport plugin for wlan
+ * @author David Brodski
*/
#include "platform.h"
#include "gnunet_statistics_service.h"
#include "gnunet_transport_service.h"
#include "plugin_transport.h"
+#include "plugin_transport_wlan.h"
+#include "gnunet_common.h"
#define PROTOCOL_PREFIX "wlan"
+#define WLAN_MTU 3000
#define DEBUG_wlan GNUNET_NO
*/
#define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6)
+/**
+ * Initial handshake message for a session.
+ */
+struct WelcomeMessage
+{
+ /**
+ * Type is GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME.
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Identity of the node connecting (TCP client)
+ */
+ struct GNUNET_PeerIdentity clientIdentity;
+
+};
/**
* Encapsulation of all of the state of the plugin.
*/
-struct Plugin;
+struct Plugin
+{
+ /**
+ * Our environment.
+ */
+ struct GNUNET_TRANSPORT_PluginEnvironment *env;
+ /**
+ * List of open sessions.
+ */
+ struct Session *sessions;
+
+ /**
+ * encapsulation to the local wlan server prog
+ */
+
+ struct GNUNET_SERVER_MessageStreamTokenizer * consoltoken;
+
+
+ /**
+ * stdout pipe handle for the gnunet-wlan-helper process
+ */
+ struct GNUNET_DISK_PipeHandle *server_stdout;
+
+ /**
+ * stdout file handle for the gnunet-wlan-helper process
+ */
+ const struct GNUNET_DISK_FileHandle *server_stdout_handle;
+
+ /**
+ * stdin pipe handle for the gnunet-wlan-helper process
+ */
+ struct GNUNET_DISK_PipeHandle *server_stdin;
+
+ /**
+ * stdin file handle for the gnunet-wlan-helper process
+ */
+ const struct GNUNET_DISK_FileHandle *server_stdin_handle;
+
+ /**
+ * ID of select gnunet-nat-server std read task
+ */
+ GNUNET_SCHEDULER_TaskIdentifier server_read_task;
+
+ /**
+ * ID of select gnunet-nat-server std read task
+ */
+ GNUNET_SCHEDULER_TaskIdentifier server_write_task;
+
+ /**
+ * The process id of the server process (if behind NAT)
+ */
+ pid_t server_pid;
+
+ /**
+ * The interface of the wlan card given to us by the user.
+ */
+ char *interface;
+
+ /**
+ * The mac_address of the wlan card given to us by the helper.
+ */
+ char *mac_address;
+
+ /**
+ * Sessions currently pending for transmission
+ * to this peer, if any.
+ */
+ struct Sessionqueue * pending_Sessions;
+
+ /**
+ * Sessions currently pending for transmission
+ * to this peer, if any.
+ */
+ struct Sessionqueue * all_Sessions;
+
+};
+
+
+struct Sessionqueue
+{
+ struct Sessionqueue * next;
+ struct Sessionqueue * prev;
+ struct Session * content;
+};
/**
* Session handle for connections.
{
/**
- * Stored in a linked list.
+ * API requirement.
*/
- struct Session *next;
+ struct SessionHeader header;
/**
* Pointer to the global plugin struct.
struct Plugin *plugin;
/**
- * The client (used to identify this connection)
+ * Messages currently pending for transmission
+ * to this peer, if any.
*/
- /* void *client; */
+ struct PendingMessage *pending_messages_head;
/**
- * Continuation function to call once the transmission buffer
- * has again space available. NULL if there is no
- * continuation to call.
+ * Messages currently pending for transmission
+ * to this peer, if any.
*/
- GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
+ struct PendingMessage *pending_messages_tail;
/**
- * Closure for transmit_cont.
+ * To whom are we talking to (set to our identity
+ * if we are still waiting for the welcome message)
*/
- void *transmit_cont_cls;
+ struct GNUNET_PeerIdentity * target;
/**
- * To whom are we talking to (set to our identity
- * if we are still waiting for the welcome message)
+ * encapsulation of the data
+ */
+
+ struct GNUNET_SERVER_MessageStreamTokenizer * datatoken;
+
+ /**
+ * peer mac address
+ */
+
+ char addr[6];
+
+
+ /**
+ * Address of the other peer (either based on our 'connect'
+ * call or on our 'accept' call).
*/
- struct GNUNET_PeerIdentity sender;
+ void *connect_addr;
/**
- * At what time did we reset last_received last?
+ * Last activity on this connection. Used to select preferred
+ * connection.
*/
- struct GNUNET_TIME_Absolute last_quota_update;
+ struct GNUNET_TIME_Absolute last_activity;
/**
- * How many bytes have we received since the "last_quota_update"
- * timestamp?
+ * number of message, to distinguish between the messages
*/
- uint64_t last_received;
+
+ uint16_t message_num_in;
/**
- * Number of bytes per ms that this peer is allowed
- * to send to us.
+ * number of message, to distinguish between the messages
*/
- uint32_t quota;
+
+ uint16_t message_num_out;
+
};
/**
- * Encapsulation of all of the state of the plugin.
+ * Information kept for each message that is yet to
+ * be transmitted.
*/
-struct Plugin
+struct PendingMessage
{
+
/**
- * Our environment.
+ * This is a doubly-linked list.
*/
- struct GNUNET_TRANSPORT_PluginEnvironment *env;
+ struct PendingMessage *next;
/**
- * List of open sessions.
- * TODO?
+ * This is a doubly-linked list.
*/
- struct Session *sessions;
+ struct PendingMessage *prev;
/**
- * encapsulation to the local wlan server prog
+ * The pending message
*/
+ const char *msg;
- struct GNUNET_SERVER_MessageStreamTokenizer * consoltoken;
/**
- * encapsulation of the data
+ * Continuation function to call once the message
+ * has been sent. Can be NULL if there is no
+ * continuation to call.
*/
+ GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
- struct GNUNET_SERVER_MessageStreamTokenizer * datatoken;
+ /**
+ * Cls for transmit_cont
+ */
+
+ void * transmit_cont_cls;
/**
- * stdout pipe handle for the gnunet-wlan-helper process
+ * Timeout value for the pending message.
*/
- struct GNUNET_DISK_PipeHandle *server_stdout;
+ struct GNUNET_TIME_Absolute timeout;
/**
- * stdout file handle for the gnunet-wlan-helper process
+ * Size of the message
*/
- const struct GNUNET_DISK_FileHandle *server_stdout_handle;
+ size_t message_size;
/**
- * stdin pipe handle for the gnunet-wlan-helper process
+ * pos in the message, for fragmentation/segmentation
*/
- struct GNUNET_DISK_PipeHandle *server_stdin;
+ size_t message_pos;
+};
+
+
+/**
+ * Header for messages which need fragmentation
+ */
+
+struct FragmentationHeader
+{
/**
- * stdin file handle for the gnunet-wlan-helper process
+ * To whom are we talking to (set to our identity
+ * if we are still waiting for the welcome message)
*/
- const struct GNUNET_DISK_FileHandle *server_stdin_handle;
+ struct GNUNET_PeerIdentity * target GNUNET_PACKED;
/**
- * ID of select gnunet-nat-server std read task
+ * number of message, to distinguish between the messages
*/
- GNUNET_SCHEDULER_TaskIdentifier server_read_task;
+
+ uint16_t message_num GNUNET_PACKED;
/**
- * The process id of the server process (if behind NAT)
+ * number of this fragment, for fragmentation/segmentation
*/
- pid_t server_pid;
+ uint16_t fregment_num GNUNET_PACKED;
+
/**
- * The interface of the wlan card given to us by the user.
+ * number of fregments in this message
*/
- char *interface;
+ uint16_t ack_message_num GNUNET_PACKED;
/**
- * The mac_address of the wlan card given to us by the helper.
+ * number of this fragment, for fragmentation/segmentation
*/
- char *mac_address;
+ uint16_t ack_fregment_num GNUNET_PACKED;
+
+ /**
+ * Flags
+ * 0x1 ack
+ * 0x2 has data (not only ack)
+ * 0x4 last fragment of message
+ * 0x8 new message
+ */
+
+ uint32_t flags GNUNET_PACKED;
+
+ /**
+ * checksum/error correction
+ */
+
+ uint32_t crc GNUNET_PACKED;
};
-struct Plugin* plugin;
+enum { ACK_FRAGMENT = 1, DATA_FRAGMENT = 2, LAST_FRAGMENT = 4, NEW_MESSAGE = 8 };
+
+int getRadiotapHeader (struct RadiotapHeader * Header);
+int getWlanHeader (struct IeeeHeader * Header);
+static int wlan_plugin_address_suggested (void *cls,
+ const void *addr,
+ size_t addrlen);
+/**
+ * get Session from address
+ *
+ */
+
+//TODO add other possibilities to find the right session (are there other?)
+static struct Session *
+get_Session (struct Plugin *plugin,
+ char * addr)
+{
+ struct Sessionqueue * queue = plugin->all_Sessions;
+ struct Sessionqueue * lastitem = NULL;
+
+ while (queue != NULL){
+ // content is never NULL
+ GNUNET_assert (queue->content == NULL);
+ char * addr2 = (queue->content)->addr;
+ if (memcmp(addr, addr2, 6) == 0){
+ //sesion found
+ return queue->content;
+ }
+ // try next
+ lastitem = queue;
+ queue = queue->next;
+ }
+ // new session
+ queue = GNUNET_malloc (sizeof (struct Sessionqueue));
+
+ if (plugin->all_Sessions == NULL){
+ //is first session
+ plugin->all_Sessions = queue;
+ } else {
+ lastitem->next = queue;
+ queue->prev = lastitem;
+ }
+
+ queue->content = GNUNET_malloc (sizeof (struct Session));
+ (queue->content)->plugin = plugin;
+ memcpy((queue->content)->addr, addr, 6);
+
+ //queue welcome
+ struct WelcomeMessage welcome;
+ struct PendingMessage *pm;
+ pm = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (struct WelcomeMessage));
+ pm->msg = (const char*) &pm[1];
+ pm->message_size = sizeof (struct WelcomeMessage);
+ welcome.header.size = htons (sizeof (struct WelcomeMessage));
+ welcome.header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_ADVERTISEMENT);
+ welcome.clientIdentity = *plugin->env->my_identity;
+ memcpy (&pm[1], &welcome, sizeof (welcome));
+ pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
+ GNUNET_CONTAINER_DLL_insert ((queue->content)->pending_messages_head,
+ (queue->content)->pending_messages_tail,
+ pm);
+
+ return queue->content;
+
+}
+
+/**
+ * Queue the session to send data
+ */
+
+static void
+queue_Session (struct Plugin *plugin,
+ struct Session * session)
+{
+ struct Sessionqueue * queue = plugin->pending_Sessions;
+ struct Sessionqueue * lastitem = NULL;
+
+ while (queue != NULL){
+ // content is never NULL
+ GNUNET_assert (queue->content == NULL);
+ // is session already in queue?
+ if (session == queue->content){
+ return;
+ }
+ // try next
+ lastitem = queue;
+ queue = queue->next;
+ }
+
+ // Session is not in the queue
+
+ queue = GNUNET_malloc (sizeof (struct Sessionqueue));
+ if (plugin->pending_Sessions == NULL){
+ //is first session
+ plugin->pending_Sessions = queue;
+ } else {
+ lastitem->next = queue;
+ queue->prev = lastitem;
+ }
+
+ queue->content = session;
+
+}
+
+/**
+ * Function called to when wlan helper is ready to get some data
+ *
+ * @param cls closure
+ * @param GNUNET_SCHEDULER_TaskContext
+ */
+
+static void
+do_transmit (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Plugin * plugin = cls;
+ char * msg;
+ ssize_t bytes;
+
+ if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
+ return;
+
+ struct Session * session;
+ struct Sessionqueue * queue;
+ struct PendingMessage * pm;
+ struct IeeeHeader * wlanheader;
+ struct RadiotapHeader * RadioHeader;
+ struct GNUNET_MessageHeader * msgheader;
+ uint16_t size = 0;
+
+ queue = plugin->pending_Sessions;
+
+ //check if the are some pending sessions/messages ...
+ GNUNET_assert(queue != NULL);
+
+ session = queue->content;
+ GNUNET_assert(session != NULL);
+
+ pm = session->pending_messages_head;
+ GNUNET_assert(pm != NULL);
+
+ //check if msg is valid to send
+ if (GNUNET_TIME_absolute_get_remaining(pm->timeout).value > 0){
+ // fixme split msg if to large
+
+ //increment one, this is a new message
+ session->message_num_out ++;
+ // fixme peer id is needed in each packet
+ size = pm->message_size + sizeof(struct RadiotapHeader)
+ + sizeof(struct IeeeHeader) + sizeof(struct GNUNET_MessageHeader)
+ + sizeof(struct FragmentationHeader);
+ msg = GNUNET_malloc(size);
+
+ msgheader = msg;
+ msgheader->size = pm->message_size + sizeof(struct RadiotapHeader) + sizeof(struct IeeeHeader);
+ msgheader->type = GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA;
+
+ RadioHeader = &msgheader[1];
+ getRadiotapHeader(RadioHeader);
+
+ wlanheader = &RadioHeader[1];
+ getWlanHeader(wlanheader);
+
+ bytes = GNUNET_DISK_file_write(plugin->server_stdin_handle, msg, size);
+ } else {
+ //remove message
+ GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
+ session->pending_messages_tail,
+ pm);
+ GNUNET_free(pm->msg);
+ GNUNET_free(pm);
+
+ }
+
+
+
+
+
+ if (bytes < 1)
+ {
+ return;
+ }
+
+ //plugin->server_read_task =
+ //GNUNET_SCHEDULER_add_read_file (plugin->env->sched,
+ // GNUNET_TIME_UNIT_FOREVER_REL,
+ // plugin->server_stdout_handle, &wlan_plugin_helper_read, plugin);
+
+}
+
+/**
+ * If we have pending messages, ask the server to
+ * transmit them (schedule the respective tasks, etc.)
+ *
+ * @param Plugin env to get everything needed
+ */
+static void
+process_pending_messages (struct Plugin * plugin)
+{
+ struct Sessionqueue * queue;
+ struct Session * session;
+
+ if (plugin->pending_Sessions == NULL)
+ return;
+
+ queue = plugin->pending_Sessions;
+ //contet should not be empty
+ GNUNET_assert(queue->content != NULL);
+
+ session = queue->content;
+ //pending sessions should have some msg
+ GNUNET_assert(session->pending_messages_head != NULL);
+
+ // GNUNET_TIME_UNIT_FOREVER_REL is needed to clean up old msg
+ plugin->server_write_task
+ = GNUNET_SCHEDULER_add_write_file(plugin->env->sched,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->server_stdin_handle,
+ &do_transmit,
+ plugin);
+}
+
+
/**
* Function that can be used by the transport service to transmit
*/
static ssize_t
wlan_plugin_send (void *cls,
- const struct GNUNET_PeerIdentity *
- target,
+ const struct GNUNET_PeerIdentity * target,
const char *msgbuf,
size_t msgbuf_size,
unsigned int priority,
const void *addr,
size_t addrlen,
int force_address,
- GNUNET_TRANSPORT_TransmitContinuation
- cont, void *cont_cls)
+ GNUNET_TRANSPORT_TransmitContinuation cont,
+ void *cont_cls)
{
int bytes_sent = 0;
- /* struct Plugin *plugin = cls; */
- return bytes_sent;
+ char * msg;
+
+ struct Plugin * plugin = cls;
+
+ struct PendingMessage * newmsg = NULL;
+
+ //check if msglen > 0
+ GNUNET_assert(msgbuf_size > 0);
+
+ //get session if needed
+ if (session == NULL) {
+ if ( wlan_plugin_address_suggested(plugin , addr, addrlen) == GNUNET_OK){
+ session = get_Session(plugin, addr);
+ } else {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Wlan Address len %d is wrong\n"),
+ addrlen);
+ return -1;
+ }
+ }
+
+ //TODO target "problem" not solved
+ session->target = target;
+
+ //queue message:
+ //first queue session
+ queue_Session(plugin, session);
+
+ //queue message in session
+ newmsg = GNUNET_malloc(sizeof(struct PendingMessage));
+ newmsg->msg = GNUNET_malloc(msgbuf_size);
+ //copy msg to buffer, not fragmented / segmented yet
+ memcpy(newmsg->msg, msgbuf, msgbuf_size);
+ newmsg->transmit_cont = cont;
+ newmsg->transmit_cont_cls = cont_cls;
+ newmsg->timeout = GNUNET_TIME_relative_to_absolute(timeout);
+ newmsg->message_pos = 0;
+ newmsg->message_size = msgbuf_size;
+ newmsg->next = NULL;
+
+ //check if queue is empty
+ struct PendingMessage * tailmsg;
+ tailmsg = session->pending_messages_tail;
+
+ //new tail is the new msg
+ session->pending_messages_tail = newmsg;
+ newmsg->prev = tailmsg;
+
+ //test if tail was not NULL (queue is empty)
+ if (tailmsg == NULL){
+ // head should be NULL too
+ GNUNET_assert(session->pending_messages_head == NULL);
+
+ session->pending_messages_head = newmsg;
+
+ } else {
+ //next at the tail should be NULL
+ GNUNET_assert(tailmsg->next == NULL);
+
+ //queue the msg
+ tailmsg->next = newmsg;
+ }
+
+ process_pending_messages(plugin);
+
+
+ //FIXME not the correct size
+ return msgbuf_size;
+
}
/**
* Function that can be used to force the plugin to disconnect
* from the given peer and cancel all previous transmissions
- * (and their continuationc).
+ * (and their continuation).
*
* @param cls closure
* @param target peer from which to disconnect
* @return GNUNET_OK if this is a plausible address for this peer
* and transport
*/
+
+
static int
wlan_plugin_address_suggested (void *cls,
const void *addr,
return GNUNET_SYSERR;
}
+ return GNUNET_SYSERR;
}
}
-#if 0
+#if 1
/**
- * Function for used to process the data from the suid process
+ * Function used for to process the data from the suid process
*/
static void
wlan_process_helper (void *cls,
- void *client_identity,
- struct GNUNET_MessageHeader *hdr)
+ void *client,
+ const struct GNUNET_MessageHeader *hdr)
{
+ struct Plugin *plugin = cls;
if (hdr->type == GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA){
//TODO DATA
- } else if (hdr->type == GNUNET_MESSAGE_TYPE_WLAN_HELPER_ADVERTISEMENT){
+ } else if (hdr->type == GNUNET_MESSAGE_TYPE_WLAN_ADVERTISEMENT){
//TODO ADV
} else if (hdr->type == GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL){
//TODO Control
GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Notifying transport of address %s\n", wlan_plugin_address_to_string(cls, plugin->mac_address, hdr->size));
plugin->env->notify_address (plugin->env->cls,
"wlan",
- &plugin->mac_address, sizeof(plugin->mac_address), GNUNET_TIME_UNIT_FOREVER_REL);
+ &plugin->mac_address, sizeof(plugin->mac_address),
+ GNUNET_TIME_UNIT_FOREVER_REL);
} else {
GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Wrong wlan mac address %s\n", plugin->mac_address);
}
wlan_plugin_helper_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
struct Plugin *plugin = cls;
- char mybuf[3000]; //max size of packet from helper
+ char mybuf[WLAN_MTU]; //max size of packet from helper
ssize_t bytes;
//memset(&mybuf, 0, sizeof(mybuf)); //?
return;
}
- plugin->server_read_task =
- GNUNET_SCHEDULER_add_read_file (plugin->env->sched,
- GNUNET_TIME_UNIT_FOREVER_REL,
- plugin->server_stdout_handle, &wlan_plugin_helper_read, plugin);
+ GNUNET_SERVER_mst_receive(plugin->consoltoken,NULL,&mybuf,bytes,0, GNUNET_NO);
}
/**
- * Start the gnunet-wlan-helper process for users behind NAT.
+ * Start the gnunet-wlan-helper process.
*
* @param plugin the transport plugin
*
GNUNET_DISK_pipe_close_end(plugin->server_stdout, GNUNET_DISK_PIPE_END_WRITE);
/* Close the read end of the write pipe */
- GNUNET_DISK_pipe_close_end(plugin->server_stdout, GNUNET_DISK_PIPE_END_READ);
+ GNUNET_DISK_pipe_close_end(plugin->server_stdin, GNUNET_DISK_PIPE_END_READ);
plugin->server_stdout_handle = GNUNET_DISK_pipe_handle(plugin->server_stdout, GNUNET_DISK_PIPE_END_READ);
plugin->server_stdin_handle = GNUNET_DISK_pipe_handle(plugin->server_stdin, GNUNET_DISK_PIPE_END_WRITE);
/**
* Entry point for the plugin.
+ *
+ * @param cls closure, the 'struct GNUNET_TRANSPORT_PluginEnvironment*'
+ * @return the 'struct GNUNET_TRANSPORT_PluginFunctions*' or NULL on error
*/
void *
gnunet_plugin_transport_wlan_init (void *cls)
{
+ struct GNUNET_SERVICE_Context *service;
struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
struct GNUNET_TRANSPORT_PluginFunctions *api;
struct Plugin *plugin;
GNUNET_assert(cls !=NULL);
+ service = GNUNET_SERVICE_start ("transport-wlan", env->sched, env->cfg);
+ if (service == NULL){
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Failed to start service for `%s' transport plugin.\n"),
+ "wlan");
+ return NULL;
+ }
+
plugin = GNUNET_malloc (sizeof (struct Plugin));
plugin->env = env;
+ wlan_transport_start_wlan_helper(plugin);
+ plugin->consoltoken = GNUNET_SERVER_mst_create(&wlan_process_helper,plugin);
+
+ //plugin->all_Sessions = GNUNET_malloc (sizeof (struct Sessionqueue));
+ //plugin->pending_Sessions = GNUNET_malloc (sizeof (struct Sessionqueue));
api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
api->cls = plugin;