Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 7 Aug 2007 18:38:59 GMT
From:      Matus Harvan <mharvan@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 124841 for review
Message-ID:  <200708071838.l77Icx3B006470@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=124841

Change 124841 by mharvan@mharvan_bike-planet on 2007/08/07 18:38:46

	ICMP plugin now correctly implements the polling strategy
		- design with normal and urgent data
	libevent events firign with EV_TIMEOUT have to be re-added

Affected files ...

.. //depot/projects/soc2007/mharvan-mtund/mtund.src/Makefile#7 edit
.. //depot/projects/soc2007/mharvan-mtund/mtund.src/README#3 edit
.. //depot/projects/soc2007/mharvan-mtund/mtund.src/plugin.h#4 edit
.. //depot/projects/soc2007/mharvan-mtund/mtund.src/plugin_icmp.c#5 edit
.. //depot/projects/soc2007/mharvan-mtund/mtund.src/plugin_tcp.c#7 edit
.. //depot/projects/soc2007/mharvan-mtund/mtund.src/plugin_udp.c#6 edit
.. //depot/projects/soc2007/mharvan-mtund/mtund.src/tun_dev.c#2 edit
.. //depot/projects/soc2007/mharvan-mtund/mtund.src/tun_dev.c.freebsd#2 edit
.. //depot/projects/soc2007/mharvan-mtund/mtund.src/tun_dev.c.linux#2 edit
.. //depot/projects/soc2007/mharvan-mtund/mtund.src/tun_dev.h#2 edit
.. //depot/projects/soc2007/mharvan-mtund/mtund.src/tunneld.c#14 edit
.. //depot/projects/soc2007/mharvan-mtund/mtund.src/tunneld.h#8 edit

Differences ...

==== //depot/projects/soc2007/mharvan-mtund/mtund.src/Makefile#7 (text+ko) ====


==== //depot/projects/soc2007/mharvan-mtund/mtund.src/README#3 (text+ko) ====


==== //depot/projects/soc2007/mharvan-mtund/mtund.src/plugin.h#4 (text+ko) ====

@@ -69,7 +69,7 @@
  * Send the data.
  * Return: number of bytes sent, -1 on error. 
  */
-int plugin_send(plugint *pl, char *data, int len);
+int plugin_send(plugint *pl, char *data, int len, int data_type);
 
 #endif
 

==== //depot/projects/soc2007/mharvan-mtund/mtund.src/plugin_icmp.c#5 (text+ko) ====

@@ -7,32 +7,36 @@
  * server always queues one packet at a time from the daemon.
  */
 
+#include <arpa/inet.h>
 #include <stdio.h>
+#include <err.h>
 #include <errno.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <syslog.h>
-#include <string.h>
-#include <time.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
+#include <sys/time.h>
+#include <event.h>
+#include <fcntl.h>
 #include <netdb.h>
-
 #include <netinet/in_systm.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
 #include <netinet/ip_icmp.h>
-
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <syslog.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
 #include <sys/types.h>
-#include <sys/sysctl.h>
-#include <err.h>
-#include <sysexits.h>
+#include <time.h>
+#include <unistd.h>
 
 #include "tunneld.h"
 #include "plugin.h"
 
+/*
+ * how often should an empty request be sent to the server - This is
+ * useful when the server has data to send but the client doesn't.
+ */
+#define PLUGIN_ICMP_KEEP_ALIVE 1
 
 typedef struct {
     int fd; /* udp socket to the other endpoint */
@@ -51,12 +55,22 @@
 static struct sockaddr_in dst_addr; /* address of the other endpoint */
 static socklen_t dst_addr_len = sizeof(dst_addr);
 
-char		*queued_data = NULL;
-int		 queued_data_len = 0;
-u_int16_t	 id = 0;
-u_int16_t	 seq = 0;
+/* normal data queue - regular traffic from the tun interface, ping request */
+char		*queued_normal_data = NULL;
+int		 queued_normal_data_len = 0;
+/* urgent data queue - ping replies */
+char		*queued_urgent_data = NULL;
+int		 queued_urgent_data_len = 0;
+u_int16_t	 id = 0;  /* ICMP echo ID */
+u_int16_t	 seq = 0; /* ICMP echo SEQ */
+/* previous value of net.inet.icmp.echo_user sysctl variable */
 int		 old_sysctl;
 size_t		 old_sysctl_size = sizeof(old_sysctl);
+struct event ev; /* used by libevent to monitor our fd */
+int data_sent_after_last_receive = 0; /* has the client sent data
+				       * after the last reply from the
+				       * server was received?
+				       */
 
 u_int16_t in_cksum(u_int16_t *addr, int len)
 {
@@ -175,6 +189,7 @@
     struct addrinfo hints, *ai;
     int n;
     int new_sysctl = 1;
+    int fd_flags;
 
     plugin_icmp_datat *data = (plugin_icmp_datat*) pl->data;
     fprintf(stderr, "starting plugin_initialize...\n");
@@ -210,14 +225,23 @@
 
     data->fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
     if (data->fd != -1) {
-	register_select_fd(data->fd, plugin_receive, pl);
+	/* non-blocking i/o */
+	fd_flags = fcntl(data->fd, F_GETFL, 0);
+	if (fd_flags == -1)
+	    errx(EX_OSFILE, "Failed to get flags from the icmp socket fd\n");
+	fcntl(data->fd, F_SETFL, fd_flags|O_NONBLOCK);
+
 	if (server) {
+	    register_select_fd(data->fd, plugin_receive, pl, -1);
 	    data->state = PLUGIN_STATE_INITIALIZED;
 	} else {
+	    /* the client should send keep-alive request to the server */
+	    register_select_fd(data->fd, plugin_receive, pl,
+			       PLUGIN_ICMP_KEEP_ALIVE);
 	    data->state = PLUGIN_STATE_CONNECTED;
 	}
 	
-	if (data->server) {
+	if (server) {
 #ifdef __FreeBSD__
 	    if (0 != sysctlbyname("net.inet.icmp.echo_user",
 				  &old_sysctl, &old_sysctl_size,
@@ -259,10 +283,12 @@
     char* packet;
     struct my_icmp_hdr *icmp;
 
+    printf("send_icmp_pkt(): len: %d\n", len);
+
     packet = malloc(sizeof(struct my_icmp_hdr) + len);
     if (!packet) {
 	fprintf(stderr, "plugin_send: out of memory\n");
-	return PLUGIN_SEND_ERROR_MALLOC;
+	return SEND_ERROR_MALLOC;
     }
     memset (packet, 0, sizeof(struct my_icmp_hdr) + len);
     memcpy (packet+sizeof(struct my_icmp_hdr), data, len);
@@ -303,130 +329,177 @@
     char serv[NI_MAXSERV];
     struct my_icmp_hdr *icmp = NULL;
 
+    printf("plugin_receive(ev_type: 0x%x)\n", ev_type);
+
     if (! (data->state == PLUGIN_STATE_CONNECTED
 	   || data->state == PLUGIN_STATE_INITIALIZED)) {
 	return;
     }
 
-    fprintf(stderr, "data on plugin fd\n");
+    /* upon timeout send another request to the server */
+    if (ev_type == EV_TIMEOUT) {
+	register_select_fd(data->fd, plugin_receive, arg,
+			   PLUGIN_ICMP_KEEP_ALIVE);
+	//goto send_request;
+    }
 
     n = recvfrom(data->fd, packet, sizeof(packet), 0,
 		 (struct sockaddr *) &from, &fromlen);
 
-    if (data->state != PLUGIN_STATE_CONNECTED) {
-	/* client connecting for the first time */
-	
-	if (getnameinfo((struct sockaddr *) &from, fromlen,
-			host, sizeof(host), serv, sizeof(serv),
-			NI_NUMERICHOST | NI_DGRAM) ) {
-	    fprintf(stderr, "getnameinfo failed: %s\n",
-		    gai_strerror(errno));
-	} else {
-	    fprintf(stderr, "received traffic from client %s:%s\n",
-		    host, serv);
+    printf("plugin_receive: read %d bytes\n", n);
+
+    /* process the packet */
+    if (n > -1) {
+	/* check whether the packet is for us */
+	if (n < 20 + sizeof(struct my_icmp_hdr)) {
+	    warnx("plugin_icmp: plugin_receive: received data too short "
+		  "to contain IP and ICMP headers\n");
+	    goto pkt_not_for_us;
 	}
+	/* IP header */
+	packetp += 20;
+	n -= 20;
+	/* ICMP header */
+	//icmp = (struct my_icmp_header*)packetp;
+	icmp = (void*)packetp;
+	packetp += sizeof(struct my_icmp_hdr);
+	n -= sizeof(struct my_icmp_hdr);
 	
-	memcpy(&dst_addr, &from, fromlen);
-	dst_addr_len = fromlen;
-	data->state = PLUGIN_STATE_CONNECTED;
-	
-    } else {
-	// TODO: fix the comparison
-	if (n == -1) {
-	    report_plugin_error(pl, PLUGIN_ERROR_RECEIVE);
-	    return;
-	}
-	if (memcmp(&dst_addr, &from, dst_addr_len) != 0) {
+	/* check values in the ICMP header */
+	if (//(ntohs(icmp->id) == id ) &&
+	    icmp->type != ((data->server)? ICMP_ECHO : ICMP_ECHOREPLY))
+	    //icmp->type != ((data->server)? 123 : ICMP_ECHOREPLY))
 	    goto pkt_not_for_us;
-	}
 
-	if (n < 20 + sizeof(struct my_icmp_hdr)) {
-	    warnx("plugin_icmp: plugin_receive: received data too short "
-		  "to contain IP and ICMP headers\n");
-	} else {
-	    /* skip the IP header */
-	    packetp += 20;
-	    n -= 20;
+	/* payload */
+	if (data->state != PLUGIN_STATE_CONNECTED) {
+	    /* client connecting for the first time */
 	    
-	    /* skip the icmp header */
-	    //icmp = (struct my_icmp_header*)packetp;
-	    icmp = (void*)packetp;
-	    packetp += sizeof(struct my_icmp_hdr);
-	    n -= sizeof(struct my_icmp_hdr);
+	    if (getnameinfo((struct sockaddr *) &from, fromlen,
+			    host, sizeof(host), serv, sizeof(serv),
+			    NI_NUMERICHOST | NI_DGRAM) ) {
+		fprintf(stderr, "getnameinfo failed: %s\n",
+			gai_strerror(errno));
+	    } else {
+		fprintf(stderr, "received traffic from client %s\n", host);
+	    }
 	    
-	    /* check values in the ICMP header */
-	    if (//(ntohs(icmp->id) == id ) &&
-		icmp->type == ((data->server)? 
-			       ICMP_ECHO : ICMP_ECHOREPLY))
-		process_data_from_plugin(pl, packetp, n);
-	    // else // pkt not for us, send back an echo reply 
-	    // goto pkt_not_for_us;
+	    //if xxx
+	    memcpy(&dst_addr, &from, fromlen);
+	    dst_addr_len = fromlen;
+	    data->state = PLUGIN_STATE_CONNECTED;
+	    // else goto pkt_no_for_us
+	} else {
+	    if (memcmp(&dst_addr, &from, dst_addr_len) != 0) {
+		goto pkt_not_for_us;
+	    }
+
+	//if (ntohs(icmp->id) != id ) {
+	// pkt not for us, send back an echo reply 
+	// goto pkt_not_for_us;
+	}
+    }
+    data_sent_after_last_receive = 0;
+    if (n > 0)
+	process_data_from_plugin(pl, packetp, n);
+
+    // send_request:
+    /* if no data was queued then ask the daemon for more data */
+    if (queued_urgent_data == NULL && queued_normal_data == NULL)
+	plugin_report(pl, REPORT_READY_TO_SEND);
 
-	    /* use the reply to send data */
-	    if (queued_data != NULL) {
-		send_icmp_pkt(pl, ntohs(icmp->id), ntohs(icmp->seq),
-			  queued_data, queued_data_len);
-		free(queued_data);
-		queued_data = NULL;
-		queued_data_len = 0;
-		report_plugin_error(pl, PLUGIN_ERROR_PKT_SENT);
-	    } else if (!data->server) { /* client */
-		/* client should send back an empty request
-		 * to give the server a chance to send data back
-		 */
-		if (seq == 65535)
-		    seq = 0;
+    /* use the reply to send data */
+    if (queued_urgent_data != NULL || queued_normal_data != NULL) {
+	if (queued_urgent_data != NULL) {
+	    send_icmp_pkt(pl, ntohs(icmp->id), ntohs(icmp->seq),
+			  queued_urgent_data, queued_urgent_data_len);
+	    free(queued_urgent_data);
+	    queued_urgent_data = NULL;
+	    queued_urgent_data_len = 0;
+	} else {
+	    send_icmp_pkt(pl, ntohs(icmp->id), ntohs(icmp->seq),
+			  queued_normal_data, queued_normal_data_len);
+	    free(queued_normal_data);
+	    queued_normal_data = NULL;
+	    queued_normal_data_len = 0;
+	}
+    }
+    /* 
+     * The client should send back an empty request if there was not
+     * data to sent. This allows the server to send more data back.
+     */
+    if (!data->server && !data_sent_after_last_receive) {
+	if (seq == 65535)
+	    seq = 0;
 		else 
 		    seq++;
-		send_icmp_pkt(pl, id, seq, NULL, 0);
-	    }
-	}
-	return;
+	send_icmp_pkt(pl, id, seq, NULL, 0);
+    }
+    return;
     
     pkt_not_for_us:
 	fprintf(stderr, "discarding data from a different client\n");
-    }
 }
 
 int
 plugin_is_ready_to_send()
 {
-    if (queued_data == NULL)
-	return 1;
+    if (queued_normal_data == NULL)
+	return WILL_QUEUE;
     else
-	return 0;
+	return QUEUE_FULL;
 }
 
 int
-plugin_send(plugint *pl, char *data, int len)
+plugin_send(plugint *pl, char *data, int len, int data_type)
 {
+    char **queued_data;
+    int *queued_data_len;
+
     plugin_icmp_datat *datapl = (plugin_icmp_datat*) pl->data;
     int n = 0;
 
+    printf("plugin_send(): urgent_data: %d, normal_data: %d\n",
+	   queued_urgent_data_len, queued_normal_data_len);
+
     if (datapl->state != PLUGIN_STATE_CONNECTED) {
 	fprintf(stderr, "no client connected yet, discarding data\n");
-	return PLUGIN_SEND_ERROR;
+	return SEND_ERROR;
     }
 	
-    if (datapl->server) { /* server */
-	if (queued_data == NULL) {
-	    queued_data = malloc(len);
-	    if (queued_data == NULL) {
-		return PLUGIN_SEND_ERROR_MALLOC;
+    if (datapl->server) { /* server  - queue the data */
+	switch (data_type) {
+	case NORMAL_DATA:
+	    queued_data = &queued_normal_data;
+	    queued_data_len = &queued_normal_data_len;
+	    goto process_queued_data;
+	case URGENT_DATA:
+	    queued_data = &queued_urgent_data;
+	    queued_data_len = &queued_urgent_data_len;
+	process_queued_data:
+	    if (*queued_data == NULL) {
+		*queued_data = malloc(len);
+		if (*queued_data == NULL) {
+		    return SEND_ERROR_MALLOC;
+		}
+		memcpy(*queued_data, data, len);
+		*queued_data_len = len;
+		return SEND_PKT_QUEUED;
+	    } else {
+		return SEND_ERROR_QUEUE_FULL;
 	    }
-	    memcpy(queued_data, data, len);
-	    queued_data_len = len;
-	    return PLUGIN_SEND_PKT_QUEUED;
-	} else {
-	    return PLUGIN_SEND_ERROR_QUEUE_FULL;
+	default:
+	    errx(EX_SOFTWARE, "plugin_icmp: plugin_send(): invalid data_type "
+		 "0x%x\n", data_type);
 	}
-    } else { /* client */
+    } else { /* client - send the data straight away */
 	n = send_icmp_pkt(pl, id, seq, data, len);
 	seq++;
 	fprintf(stderr, "send_icmp_pkt: send returned %d\n", n);
-	if (n > 0) 
- 	    return PLUGIN_SEND_PKT_SENT;
-	else
- 	    return PLUGIN_SEND_ERROR;
+	if (n > 0) {
+	    data_sent_after_last_receive = 1;
+ 	    return SEND_PKT_SENT;
+	} else
+ 	    return SEND_ERROR;
     }
 }

==== //depot/projects/soc2007/mharvan-mtund/mtund.src/plugin_tcp.c#7 (text+ko) ====

@@ -1,15 +1,14 @@
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netdb.h>
 #include <stdio.h>
-#include <errno.h>
 #include <stdlib.h>
-#include <unistd.h>
+#include <string.h>
 #include <syslog.h>
-#include <string.h>
-#include <time.h>
-
 #include <sys/types.h>
 #include <sys/socket.h>
-#include <arpa/inet.h>
-#include <netdb.h>
+#include <time.h>
+#include <unistd.h>
 //#include <sys/select.h>
 
 #include "tunneld.h"
@@ -234,7 +233,7 @@
     }
 
     if (data->fd != -1) {
-	register_select_fd(data->fd, plugin_receive, pl);
+	register_select_fd(data->fd, plugin_receive, pl, -1);
 	return 0;
     } else return -1;
 }
@@ -258,7 +257,7 @@
     //fprintf(stderr, "state: %d\n", data->state);
     if (! (data->state == PLUGIN_STATE_CONNECTED
 	   || data->state == PLUGIN_STATE_INITIALIZED)) {
-	report_plugin_error(pl, PLUGIN_ERROR_RECEIVE);
+	plugin_report(pl, REPORT_ERROR_RECEIVE);
 	return;
     }
 
@@ -267,15 +266,15 @@
 	new_fd = tcp_accept(fd);
 	if (new_fd == -1) {
 	    fprintf(stderr, "accept failed\n");
-	    report_plugin_error(pl, PLUGIN_ERROR_RECEIVE);
+	    plugin_report(pl, REPORT_ERROR_RECEIVE);
 	} else {
 	    unregister_select_fd(data->fd);
 	    tcp_close(data->fd);
 	    data->fd = new_fd;
-	    register_select_fd(data->fd, plugin_receive, pl);
+	    register_select_fd(data->fd, plugin_receive, pl, -1);
 	    data->state = PLUGIN_STATE_CONNECTED;
 	    fprintf(stderr, "new client connection accepted\n");
-	    //report_plugin_error(pl, PLUGIN_ERROR_SUCCESS);
+	    //plugin_report(pl, REPORT_SUCCESS);
 	}
     } else {
 	/* get length of the next packet */
@@ -293,7 +292,7 @@
 		}
 	    }
 	    process_data_from_plugin(pl, packet, n);
-	    //report_plugin_error(pl, PLUGIN_ERROR_SUCCESS);
+	    //plugin_report(pl, REPORT_SUCCESS);
         /* packet too large */
 	} else {
 	    fprintf(stderr, "client sent a too large packet (len: %d)\n",
@@ -312,21 +311,21 @@
 	/* client disconnected */
 	unregister_select_fd(fd);
 	data->state = PLUGIN_STATE_DISCONNECTED;
-	report_plugin_error(pl, PLUGIN_ERROR_RECEIVE);
+	plugin_report(pl, REPORT_ERROR_RECEIVE);
     }
 }
 
 int
 plugin_is_ready_to_send()
 {
-    return 1;
+    return WILL_SEND_IMMEDIATELY;
 }
 
 /*
  * BUG: the write might not send the whole buffer in one go, should check
  * and call again, but then the receiver would have to reassemble packets
  */
-int plugin_send(plugint *pl, char *data, int len) {
+int plugin_send(plugint *pl, char *data, int len, int data_type) {
     plugin_tcp_datat *datapl = (plugin_tcp_datat*) pl->data;
     int n = 0;
 
@@ -343,8 +342,8 @@
 	//fprintf(stderr, "plugin_send: write returned %d\n", n);
     }
     if (n < 0 || (len != 0 && n == 0) ) {
-	report_plugin_error(pl, PLUGIN_ERROR_RECEIVE);
+	plugin_report(pl, REPORT_ERROR_RECEIVE);
     }
     //return n;
-    return PLUGIN_SEND_PKT_SENT;
+    return SEND_PKT_SENT;
 }

==== //depot/projects/soc2007/mharvan-mtund/mtund.src/plugin_udp.c#6 (text+ko) ====

@@ -169,7 +169,7 @@
     if (server) {
 	data->fd = udp_open(port);
 	if (data->fd != -1) {
-	    register_select_fd(data->fd, plugin_receive, pl);
+	    register_select_fd(data->fd, plugin_receive, pl, -1);
 	    data->state = PLUGIN_STATE_INITIALIZED;
 	    return 0;
 	}
@@ -178,10 +178,10 @@
 	if (data->fd != -1) {
 	    //n = send(fd,"test",5,0);
 	    //if (n == 5) {
-		register_select_fd(data->fd, plugin_receive, pl);
-		data->state = PLUGIN_STATE_CONNECTED;
-		return 0;
-		//}
+	    register_select_fd(data->fd, plugin_receive, pl, -1);
+	    data->state = PLUGIN_STATE_CONNECTED;
+	    return 0;
+	    //}
 	}
     }
     return -1;
@@ -250,10 +250,10 @@
 int
 plugin_is_ready_to_send()
 {
-    return 1;
+    return WILL_SEND_IMMEDIATELY;
 }
 
-int plugin_send(plugint *pl, char *data, int len) {
+int plugin_send(plugint *pl, char *data, int len, int data_type) {
     plugin_udp_datat *datapl = (plugin_udp_datat*) pl->data;
     int n = 0;
     if (datapl->state != PLUGIN_STATE_CONNECTED) {
@@ -263,5 +263,5 @@
 	n = send(datapl->fd, data, len, 0);
 	fprintf(stderr, "plugin_send: send returned %d\n", n);
     }
-    return PLUGIN_SEND_PKT_SENT;
+    return SEND_PKT_SENT;
 }

==== //depot/projects/soc2007/mharvan-mtund/mtund.src/tun_dev.c#2 (text+ko) ====


==== //depot/projects/soc2007/mharvan-mtund/mtund.src/tun_dev.c.freebsd#2 (text+ko) ====


==== //depot/projects/soc2007/mharvan-mtund/mtund.src/tun_dev.c.linux#2 (text+ko) ====


==== //depot/projects/soc2007/mharvan-mtund/mtund.src/tun_dev.h#2 (text+ko) ====


==== //depot/projects/soc2007/mharvan-mtund/mtund.src/tunneld.c#14 (text+ko) ====

@@ -40,7 +40,7 @@
 /* max transfered unit - encapsulated packet size */
 #define MTU 1500
 /* how many pings can fail before the plugin is declared broken */
-#define PING_INTERVAL 20
+#define PING_INTERVAL 7
 #define PING_FAIL 3
 
 int server = 0; /* are we a server or a client? */
@@ -55,7 +55,7 @@
 struct event timer_ev;
 
 /* sequence number for the echo request */
-uint echo_seq = 0;
+uint8_t echo_seq = 0;
 
 /* fragment id for the next packet to be fragmented */
 frag_hdr_t frag_hdr;
@@ -83,9 +83,13 @@
 } fdlt;
 fdlt *fdl;
 
-void register_select_fd(int fd,
-			void (*ev_callback)(int, short, void *arg), void *arg)
+void
+register_select_fd(int fd, 
+		   void (*ev_callback)(int, short, void *arg),
+		   void *arg, long tv_sec)
 {
+    struct timeval tv;
+
     fdlt* nfdl = malloc(sizeof(fdlt));
     if (!nfdl) {
 	fprintf(stderr, "failed to malloc an fdlt: out of mem!\n");
@@ -95,10 +99,15 @@
     nfdl->next = fdl;
     fdl = nfdl;
 
-    //update_fdset();
+    event_set(&nfdl->ev, fd, EV_PERSIST | EV_READ, ev_callback, arg);
+
+    if (tv_sec > -1) {
+	tv.tv_sec = tv_sec;
+	tv.tv_usec = 0;
+	event_add(&nfdl->ev, &tv);
+    } else
+	event_add(&nfdl->ev, NULL);
 
-    event_set(&nfdl->ev, fd, EV_PERSIST | EV_READ, ev_callback, arg);
-    event_add(&nfdl->ev, NULL);
 }
 
 void unregister_select_fd(int fd) {
@@ -136,6 +145,20 @@
   return system(cmd);
 }
 
+void
+set_current_pl(plugint* pl)
+{
+    if (current_pl) {
+	event_del(&tun_ev);
+    }
+    current_pl = pl;
+    if (pl) {
+	if (pl->is_ready_to_send() == WILL_SEND_IMMEDIATELY)
+	    event_add(&tun_ev, NULL);
+	// otherwise the tun read is timed by the plugin
+    }
+}
+
 /* read data from the tun interface and pass it to the daemon */
 static void 
 tun_receive()
@@ -149,19 +172,16 @@
 	return;
     
     do {
-	/* only read from the tun device of the plugin is ready to send data */
-	if (current_pl->is_ready_to_send() != 0) {
-	    memset(packet, 0, sizeof(packet));
-	    nread = tun_read(tun_fd, packet, PACKETLEN);
-	    if (nread > 0) {
-		nwrite = process_data_from_tun(packet, nread);
-	    }
+	//memset(packet, 0, sizeof(packet));
+	nread = tun_read(tun_fd, packet, PACKETLEN);
+	if (nread > 0) {
+	    nwrite = process_data_from_tun(packet, nread);
 	}
 	/* continue the loop if we read something
 	 * and the plugin has sent it immediately
 	 */
 	printf("tun_receive: nread: %d, nwrite: %d\n", nread, nwrite);
-    } while (nread > 0 && nwrite == PLUGIN_SEND_PKT_SENT);
+    } while (nread > 0 && nwrite == SEND_PKT_SENT);
 }
 
 /* send data via the tun interface */
@@ -184,7 +204,14 @@
 tun_ev_handler(int fd, short ev_type, void *arg)
 {
     printf("tun_ev_handler(): ev_type: 0x%x\n", ev_type);
-    tun_receive();
+    /*
+     * Only read from the tun device can send the data immediately.
+     * Otherwise, we will be notified via plugin_report() when data
+     * can be sent.
+     */
+    if (current_pl != NULL)
+	if (current_pl->is_ready_to_send() == WILL_SEND_IMMEDIATELY)
+	    tun_receive();
 }
 
 /* 
@@ -242,13 +269,15 @@
 static void
 send_echo_request()
 {
-    char data[10];
+    int nwrite = 0;
+    char data[2];
     plugint *pl = current_pl;
     if (pl) {
 	*data = DISPATCH_ECHO_REQUEST;
 	*(data+1) = echo_seq++;
-	(void) pl->send(pl, data, sizeof(data));
+	nwrite =  pl->send(pl, data, sizeof(data), NORMAL_DATA);
 	pl->ping_counter--;
+	printf("send_cho_request(): nwrite: 0x%x\n", nwrite);
     }
 }
 
@@ -260,12 +289,11 @@
     struct frag_info *np, *np_temp;
     plugint *pl = current_pl;
 
-    fprintf(stderr, "timer fired\n");
-    
     /* check if too many ping requests have not failed */
     if (pl) {
-	if (! pl->ping_counter) {
-	    report_plugin_error(pl, PLUGIN_ERROR_PING);
+	printf("ping_counter: %d\n", pl->ping_counter);
+	if (pl->ping_counter <= 0) {
+	    plugin_report(pl, REPORT_ERROR_PING);
 	} else {
 	    send_echo_request();
 	}
@@ -305,17 +333,20 @@
     struct timeval tv;
     int i;
     int dgram_reassembled;
+    int nwrite;
+
+    if (len <= 0)
+	return;
 
     switch (dispatch) {
     case DISPATCH_DATA:
-	if (len > 0) {
-	    current_pl = pl;
-	}
+	printf("process_data_from_plugin(): DATA\n");
 	tun_send(data+1, len-1);
+	goto plugin_ok;
 	break;
     case DISPATCH_FRAG:
 	if (len <= sizeof(frag_hdr)) {
-	    report_plugin_error(pl, PLUGIN_ERROR_RECEIVE);
+	    plugin_report(pl, REPORT_ERROR_RECEIVE);
 	    return;
 	}
 
@@ -407,7 +438,7 @@
 	/* packet completely reassembled */
 	if (dgram_reassembled) {
 	    fprintf(stderr, "frag reassembly: packet complete\n");
-	    current_pl = pl;
+	    set_current_pl(pl);
 	    tun_send(p->buf, p->size);
 	    
 	    /* remove fragment info from linked list */
@@ -416,22 +447,31 @@
 	    free(p->bitmap);
 	    free(p);
 	}
+	goto plugin_ok;
 	break;
     case DISPATCH_ECHO_REQUEST:
+	printf("process_data_from_plugin(): ECHO_REQUEST\n");
 	*data = (u_int8_t) DISPATCH_ECHO_REPLY;
-	pl->send(pl, data, len);
+	nwrite = pl->send(pl, data, len, URGENT_DATA);
 	fprintf(stderr, "got echo request (plugin: %s)\n",
 		pl->name);
+	printf("sending reply, returned 0x%x\n", nwrite);
+	goto plugin_ok;
 	break;
     case DISPATCH_ECHO_REPLY:
+	printf("process_data_from_plugin(): ECHO_REPLY\n");
 	fprintf(stderr, "got echo reply (plugin: %s)\n",
 		pl->name);
-	pl->ping_counter++;
+	pl->ping_counter = PING_FAIL;
+	//pl->ping_counter++;
+	goto plugin_ok;
 	break;
     default:
 	fprintf(stderr, "unknown dispatch 0x%X in data from plugin %s\n",
 		dispatch, pl->name);
     }
+ plugin_ok:
+    set_current_pl(pl);
 }
 
 /*
@@ -446,17 +486,19 @@
 
     if (current_pl == NULL) {
 	fprintf(stderr, "no plugin connected yet, discarding tun data\n");
-	report_plugin_error(NULL, PLUGIN_ERROR_BOOTSTRAP);
-	return PLUGIN_SEND_ERROR;
+	plugin_report(NULL, REPORT_ERROR_BOOTSTRAP);
+	return SEND_ERROR;
     }
 
-    /* no need to add the fragmentation header */
     printf("process_data_from_tun: len: %d, current_pl->mtu: %d\n",
 	   len, current_pl->mtu);
+    /* no need to add the fragmentation header */
+    //TODO: fix fragmentation
     if (len < current_pl->mtu || 1) {
 	*ldata = DISPATCH_DATA;
 	memcpy(ldata+1, data, min(sizeof(ldata)-1, len));
-	return current_pl->send(current_pl, ldata, min(sizeof(ldata), len+1));
+	return current_pl->send(current_pl, ldata, min(sizeof(ldata), len+1),
+				NORMAL_DATA);
 	
     /* add the fragmentation header */
     } else {
@@ -484,29 +526,34 @@
 	    //      on the return value from send()
 	    n = min(current_pl->mtu, len);
 	    (void) current_pl->send(current_pl, ldatap,
-				    min(current_pl->mtu, len));
+				    min(current_pl->mtu, len), NORMAL_DATA);
 	    n -= sizeof(frag_hdr);
 	    if (n <= 0) {
 		fprintf(stderr, "process_data_from_tun: failed to send "
 			"data (%d)\n", n);
-		report_plugin_error(current_pl, PLUGIN_ERROR_SEND);
-		return PLUGIN_SEND_ERROR;
+		plugin_report(current_pl, REPORT_ERROR_SEND);
+		return SEND_ERROR;
 	    }
 	    ldatap += n;
 	    frag_hdr.offset += n;
 	    len -= n;
 	}
-	return PLUGIN_SEND_PKT_SENT;
+	return SEND_PKT_SENT;
     }
 }
 
 void
-report_plugin_error(plugint *pl, int err)
+plugin_report(plugint *pl, int err)
 {
+    if (pl)
+	printf("plugin_report(%s, 0x%x)\n", pl->name, err);
+    else
+	printf("plugin_report(NULL plugin, 0x%x)\n", err);
+
     switch (err) {
-    case PLUGIN_ERROR_SUCCESS:
-	return;
-    case PLUGIN_ERROR_PKT_SENT:
+/*     case PLUGIN_REPORT_SUCCESS: */
+/* 	return; */
+    case REPORT_READY_TO_SEND:
 	/* plugin is ready to send the next packet */
 	tun_receive();
 	return;
@@ -541,7 +588,7 @@
 		fprintf(stderr, "initalizing plugin: %s...\n", pl->name);
 		if (((pl->initialize)(pl, server, host, pl->name+4)) == 0) {
 		    fprintf(stderr, "found a working plugin: %s\n", pl->name);
-		    current_pl = pl;
+		    set_current_pl(pl);
 		    return;
 		} else {
 		    fprintf(stderr, "plugin %s failed to initialize\n",
@@ -655,7 +702,6 @@
     fcntl(tun_fd, F_SETFL, tun_flags|O_NONBLOCK);
     /* watch the tun device with libevent */
     event_set(&tun_ev, tun_fd, EV_PERSIST | EV_READ, tun_ev_handler, NULL);
-    event_add(&tun_ev, NULL);
     printf("Created tunnel device: %s\n", tun_dev);
 
     /* configure the tun interface */
@@ -709,7 +755,7 @@
 	}
     } else {
 	/* initialize a working plugin */
-	report_plugin_error(NULL, PLUGIN_ERROR_BOOTSTRAP);
+	plugin_report(NULL, REPORT_ERROR_BOOTSTRAP);
     }
     
     /* kick off the timer event, it will re-register itself */

==== //depot/projects/soc2007/mharvan-mtund/mtund.src/tunneld.h#8 (text+ko) ====

@@ -43,39 +43,47 @@
     int (*initialize)(struct _plugint*, int, char*, char*);
     void (*deinitialize)(struct _plugint*);
     void (*receive)(int fd, short ev_type, void *arg); /* select fired on some fd - check for data */
-    int (*send)(struct _plugint*, char*, int);
+    int (*send)(struct _plugint*, char*, int, int);
     int (*is_ready_to_send)();
     void* data;
     int mtu;
     struct _plugint *next;
 } plugint;
 
-/* report_plugin_error() argument values */
+/* plugin_report() argument values */
+enum {
+    REPORT_READY_TO_SEND,   /* ready to send the next packet */
+    REPORT_ERROR_BOOTSTRAP,  /* no plugin initialized yet */
+    REPORT_ERROR_SEND,       /* problem with sending */
+    REPORT_ERROR_RECEIVE,    /* problem with receiving */
+    REPORT_ERROR_TIMEOUT,
+    REPORT_ERROR_PING,
+};
+
+/* plugin_is_ready_to_send() return values */
+enum {
+    WILL_SEND_IMMEDIATELY,
+    WILL_QUEUE,
+    QUEUE_FULL
+};
+
+/* plugin_send() argument */
 enum {
-    PLUGIN_ERROR_SUCCESS = 0,
-    PLUGIN_ERROR_PKT_SENT,   /* packet has been sent,
-			      * ready to send the next one
-			      */
-    PLUGIN_ERROR_BOOTSTRAP,  /* no plugin initialized yet */
-    PLUGIN_ERROR_SEND,       /* problem with sending */
-    PLUGIN_ERROR_RECEIVE,    /* problem with receiving */
-    PLUGIN_ERROR_TIMEOUT,
-    PLUGIN_ERROR_PING,
+    NORMAL_DATA,    /* normal data */
+    URGENT_DATA     /* urgent data */
 };
 
 /* plugin_send() return values */
 enum {
-    PLUGIN_SEND_PKT_SENT = 0,     /* packet has been sent,
+    SEND_PKT_SENT = 0,     /* packet has been sent,
 				   * ready to send the next one
 				   */
-    PLUGIN_SEND_PKT_QUEUED,       /* packet queued, not yet ready
+    SEND_PKT_QUEUED,       /* packet queued, not yet ready
 				   * to send the next one
 				   */
-    PLUGIN_SEND_ERROR_MALLOC,     /* malloc failed */
-    PLUGIN_SEND_ERROR_QUEUE_FULL, /* packet queue is full, cannot yet 
-				   * send more packets
-				   */
-    PLUGIN_SEND_ERROR             /* sending the packet failed */
+    SEND_ERROR_MALLOC,     /* malloc failed, packet dropped */
+    SEND_ERROR_QUEUE_FULL, /* queue is full, packet dropped */
+    SEND_ERROR             /* sending the packet failed */
 };
 
 /* dispatch type - prepended before the payload */
@@ -90,8 +98,8 @@
 /*
  * Register file descriptor fd to be watched by the main select().
  */
-void register_select_fd(int fd,
-			void (*ev_callback)(int, short, void *arg), void *arg);
+void register_select_fd(int fd, void (*ev_callback)(int, short, void *arg),
+			void *arg, long tv_sec);
 /*
  * Unregister file descriptor fd to no longer be watched by the main
  * select().
@@ -110,6 +118,6 @@
 /*
  * Report a problem in the plugin to the daemon.
  */
-void report_plugin_error(plugint *pl, int err);
+void plugin_report(plugint *pl, int err);
 
 #endif



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200708071838.l77Icx3B006470>