diff --git a/commandline.c b/commandline.c index 20900433..c3c96d69 100644 --- a/commandline.c +++ b/commandline.c @@ -22,6 +22,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include #include +#include +#include +#include #ifdef HAVE_STRINGS_H #include #endif @@ -209,7 +212,6 @@ int parseCommandLine(const char *argv0, int argc, const char *const *args) } /* clean up after ourselves */ - overlay_mdp_client_done(); rhizome_close_db(); OUT(); @@ -361,7 +363,8 @@ int app_echo(int argc, const char *const *argv, const struct command_line_option return 0; } -void lookup_send_request(unsigned char *srcsid, int srcport, unsigned char *dstsid, const char *did){ +void lookup_send_request(int mdp_sockfd, unsigned char *srcsid, int srcport, unsigned char *dstsid, const char *did) +{ int i; overlay_mdp_frame mdp; bzero(&mdp,sizeof(mdp)); @@ -389,20 +392,21 @@ void lookup_send_request(unsigned char *srcsid, int srcport, unsigned char *dsts bcopy(did,&mdp.out.payload[0],strlen(did)+1); mdp.out.payload_length=strlen(did)+1; - overlay_mdp_send(&mdp,0,0); + overlay_mdp_send(mdp_sockfd, &mdp, 0, 0); /* Also send an encrypted unicast request to a configured directory service */ if (!dstsid){ if (!is_sid_any(config.directory.service.binary)) { memcpy(mdp.out.dst.sid, config.directory.service.binary, SID_SIZE); mdp.packetTypeAndFlags=MDP_TX; - overlay_mdp_send(&mdp,0,0); + overlay_mdp_send(mdp_sockfd, &mdp, 0, 0); } } } int app_dna_lookup(int argc, const char *const *argv, const struct command_line_option *o, void *context) { + int mdp_sockfd; if (config.debug.verbose) DEBUG_argv("command", argc, argv); /* Create the instance directory if it does not yet exist */ @@ -428,12 +432,21 @@ int app_dna_lookup(int argc, const char *const *argv, const struct command_line_ one_reply=1; idelay=-idelay; } - + + if ((mdp_sockfd = overlay_mdp_client_socket()) < 0) + WHY("Cannot create MDP socket"); + /* Bind to MDP socket and await confirmation */ unsigned char srcsid[SID_SIZE]; int port=32768+(random()&32767); - if (overlay_mdp_getmyaddr(0,srcsid)) return WHY("Could not get local address"); - if (overlay_mdp_bind(srcsid,port)) return WHY("Could not bind to MDP socket"); + if (overlay_mdp_getmyaddr(mdp_sockfd, 0, srcsid)) { + overlay_mdp_client_close(mdp_sockfd); + return WHY("Could not get local address"); + } + if (overlay_mdp_bind(mdp_sockfd, srcsid, port)) { + overlay_mdp_client_close(mdp_sockfd); + return WHY("Could not bind to MDP socket"); + } /* use MDP to send the lookup request to MDP_PORT_DNALOOKUP, and wait for replies. */ @@ -450,18 +463,18 @@ int app_dna_lookup(int argc, const char *const *argv, const struct command_line_ if ((last_tx+interval)>1; } time_ms_t short_timeout=125; while(short_timeout>0) { - if (overlay_mdp_client_poll(short_timeout)) + if (overlay_mdp_client_poll(mdp_sockfd, short_timeout)) { overlay_mdp_frame rx; int ttl; - if (overlay_mdp_recv(&rx, port, &ttl)==0) + if (overlay_mdp_recv(mdp_sockfd, &rx, port, &ttl)==0) { if (rx.packetTypeAndFlags==MDP_ERROR) { @@ -514,10 +527,44 @@ int app_dna_lookup(int argc, const char *const *argv, const struct command_line_ if (servalShutdown) break; } - overlay_mdp_client_done(); + overlay_mdp_client_close(mdp_sockfd); return 0; } +/* Delete all UNIX socket files in instance directory. */ +static void clean_socket_files() +{ + const char *instance_path = serval_instancepath(); + char path[PATH_MAX]; + DIR *dir; + struct dirent *dp; + struct stat st; + + /* Open instance_path directory. */ + if ((dir = opendir(instance_path)) == NULL) { + WARNF("Can't open %s\n", instance_path); + return; + } + + /* Read all files in instance_path directory. */ + while ((dp = readdir(dir)) != NULL) { + + /* Concatenate dir and name. */ + sprintf(path, "%s/%s", instance_path, dp->d_name); + + /* Retrieve stat info. */ + if (stat(path, &st)) { + WARNF("Cannot stat %s (errno=%d)\n", path, errno); + continue; + } + + if (S_ISSOCK(st.st_mode)) { + /* The file is a UNIX socket, delete it. */ + unlink(path); + } + } +} + int app_server_start(int argc, const char *const *argv, const struct command_line_option *o, void *context) { if (config.debug.verbose) DEBUG_argv("command", argc, argv); @@ -581,6 +628,8 @@ int app_server_start(int argc, const char *const *argv, const struct command_lin /* Create the instance directory if it does not yet exist */ if (create_serval_instance_dir() == -1) return -1; + /* Clean old socket files from instance directory. */ + clean_socket_files(); /* Now that we know our instance path, we can ask for the default set of network interfaces that we will take interest in. */ if (config.interfaces.ac == 0) @@ -781,6 +830,7 @@ int app_server_status(int argc, const char *const *argv, const struct command_li int app_mdp_ping(int argc, const char *const *argv, const struct command_line_option *o, void *context) { + int mdp_sockfd; if (config.debug.verbose) DEBUG_argv("command", argc, argv); const char *sid, *count; if (cli_arg(argc, argv, o, "SID|broadcast", &sid, str_is_subscriber_id, "broadcast") == -1) @@ -792,13 +842,22 @@ int app_mdp_ping(int argc, const char *const *argv, const struct command_line_op int ret=-1; int icount=atoi(count); + if ((mdp_sockfd = overlay_mdp_client_socket()) < 0) + WHY("Cannot create MDP socket"); + overlay_mdp_frame mdp; bzero(&mdp, sizeof(overlay_mdp_frame)); /* Bind to MDP socket and await confirmation */ unsigned char srcsid[SID_SIZE]; int port=32768+(random()&32767); - if (overlay_mdp_getmyaddr(0,srcsid)) return WHY("Could not get local address"); - if (overlay_mdp_bind(srcsid,port)) return WHY("Could not bind to MDP socket"); + if (overlay_mdp_getmyaddr(mdp_sockfd, 0, srcsid)) { + overlay_mdp_client_close(mdp_sockfd); + return WHY("Could not get local address"); + } + if (overlay_mdp_bind(mdp_sockfd, srcsid, port)) { + overlay_mdp_client_close(mdp_sockfd); + return WHY("Could not bind to MDP socket"); + } /* First sequence number in the echo frames */ unsigned int firstSeq=random(); @@ -844,7 +903,7 @@ int app_mdp_ping(int argc, const char *const *argv, const struct command_line_op long long *txtime=(long long *)&mdp.out.payload[4]; *txtime=gettime_ms(); - int res=overlay_mdp_send(&mdp,0,0); + int res=overlay_mdp_send(mdp_sockfd, &mdp, 0, 0); if (res) { WHYF("ERROR: Could not dispatch PING frame #%d (error %d)", sequence_number - firstSeq, res); if (mdp.packetTypeAndFlags==MDP_ERROR) @@ -858,11 +917,11 @@ int app_mdp_ping(int argc, const char *const *argv, const struct command_line_op while(now0) { int ttl=-1; - if (overlay_mdp_recv(&mdp, port, &ttl)==0) { + if (overlay_mdp_recv(mdp_sockfd, &mdp, port, &ttl)==0) { switch(mdp.packetTypeAndFlags&MDP_TYPE_MASK) { case MDP_ERROR: WHYF("mdpping: overlay_mdp_recv: %s (code %d)", mdp.error.message, mdp.error.error); @@ -922,7 +981,7 @@ int app_mdp_ping(int argc, const char *const *argv, const struct command_line_op (samples= next_send){ /* Send a unicast packet to this node, asking for any did */ - lookup_send_request(srcsid, port, dstsid, ""); + lookup_send_request(mdp_sockfd, srcsid, port, dstsid, ""); next_send+=125; continue; } time_ms_t poll_timeout = (next_send>timeout?timeout:next_send) - now; - if (overlay_mdp_client_poll(poll_timeout)<=0) + if (overlay_mdp_client_poll(mdp_sockfd, poll_timeout)<=0) continue; int ttl=-1; - if (overlay_mdp_recv(&mdp_reply, port, &ttl)) + if (overlay_mdp_recv(mdp_sockfd, &mdp_reply, port, &ttl)) continue; if ((mdp_reply.packetTypeAndFlags&MDP_TYPE_MASK)==MDP_ERROR){ @@ -1896,6 +1986,11 @@ int app_reverse_lookup(int argc, const char *const *argv, const struct command_l int app_network_scan(int argc, const char *const *argv, const struct command_line_option *o, void *context) { + int mdp_sockfd; + + if ((mdp_sockfd = overlay_mdp_client_socket()) < 0) + WHY("Cannot create MDP socket"); + overlay_mdp_frame mdp; bzero(&mdp,sizeof(mdp)); @@ -1913,11 +2008,14 @@ int app_network_scan(int argc, const char *const *argv, const struct command_lin }else DEBUGF("Scanning local networks"); - overlay_mdp_send(&mdp,MDP_AWAITREPLY,5000); + overlay_mdp_send(mdp_sockfd, &mdp, MDP_AWAITREPLY, 5000); if (mdp.packetTypeAndFlags!=MDP_ERROR) return -1; cli_puts(mdp.error.message); cli_delim("\n"); + + overlay_mdp_client_close(mdp_sockfd); + return mdp.error.error; } diff --git a/mdp_client.c b/mdp_client.c index 1db51350..b1501e39 100644 --- a/mdp_client.c +++ b/mdp_client.c @@ -26,14 +26,75 @@ #include "overlay_packet.h" #include "mdp_client.h" -int mdp_client_socket=-1; -int overlay_mdp_send(overlay_mdp_frame *mdp,int flags,int timeout_ms) +/* We randomly generate UNIX socket path names for communicating with servald, + * and handle only mdp_sockfd. But when we close the socket, the file is not + * deleted. Thus, we need to keep a mapping between mdp_sockfd and sun_path. + * Every time a MDP socket is open, we store it with its path_name. + * Every time a MDP socket is closed, we remove it from the list and delete the + * file. + */ + +/* Item mapping mdp_sockfd and sun_path. */ +struct mdp_sock_node { + int mdp_sockfd; + char sun_path[108]; /* same size as struct sockaddr_un sun_path */ + struct mdp_sock_node *next; /* next item for linked-list */ +}; + +/* Linked-list storing the mapping between mdp_sockfd and sun_path for open MDP + * sockets. */ +static struct mdp_sock_node *open_mdp_sock_list; + +/* Add the socket to the open MDP socket list. */ +static void mdp_sock_opened(int mdp_sockfd, char *sun_path) { - int len=4; - - if (mdp_client_socket==-1) - if (overlay_mdp_client_init() != 0) - return -1; + struct mdp_sock_node *old_head = open_mdp_sock_list; + + /* The new item becomes the head. */ + open_mdp_sock_list = + (struct mdp_sock_node *) malloc(sizeof(struct mdp_sock_node)); + + open_mdp_sock_list->mdp_sockfd = mdp_sockfd; + strncpy(open_mdp_sock_list->sun_path, sun_path, 108); + open_mdp_sock_list->next = old_head; +} + +/* Remove the socket from the list and delete associated file on filesystem. */ +static void mdp_sock_closed(int mdp_sockfd) +{ + struct mdp_sock_node *node = open_mdp_sock_list; + struct mdp_sock_node *prev_node = NULL; + + /* Find the node having the same mdp_sockfd. */ + while (node != NULL && node->mdp_sockfd != mdp_sockfd) { + prev_node = node; + node = node->next; + } + + if (node != NULL) { + /* Node found. */ + + if (prev_node != NULL) { + /* General case. */ + prev_node->next = node->next; + } else { + /* Special case for the first item. */ + open_mdp_sock_list = node->next; + } + /* Remove socket file. */ + unlink(node->sun_path); + free(node); + } else { + WARN("Socket to remove not found"); + } +} + +/* Send an mdp frame and return 0 if everything is OK, -1 otherwise. + * Warning: does not return the length of characters sent like sendto(). + */ +int overlay_mdp_send(int mdp_sockfd, overlay_mdp_frame *mdp, int flags, int timeout_ms) +{ + int len; /* Minimise frame length to save work and prevent accidental disclosure of memory contents. */ @@ -46,10 +107,8 @@ int overlay_mdp_send(overlay_mdp_frame *mdp,int flags,int timeout_ms) if (!FORM_SERVAL_INSTANCE_PATH(name.sun_path, "mdp.socket")) return -1; - set_nonblock(mdp_client_socket); - int result=sendto(mdp_client_socket, mdp, len, 0, + int result=sendto(mdp_sockfd, mdp, len, 0, (struct sockaddr *)&name, sizeof(struct sockaddr_un)); - set_block(mdp_client_socket); if (result<0) { mdp->packetTypeAndFlags=MDP_ERROR; mdp->error.error=1; @@ -66,9 +125,9 @@ int overlay_mdp_send(overlay_mdp_frame *mdp,int flags,int timeout_ms) port = mdp->out.dst.port; time_ms_t started = gettime_ms(); - while(timeout_ms>=0 && overlay_mdp_client_poll(timeout_ms)>0){ + while(timeout_ms>=0 && overlay_mdp_client_poll(mdp_sockfd, timeout_ms)>0){ int ttl=-1; - if (!overlay_mdp_recv(mdp, port, &ttl)) { + if (!overlay_mdp_recv(mdp_sockfd, mdp, port, &ttl)) { /* If all is well, examine result and return error code provided */ if ((mdp->packetTypeAndFlags&MDP_TYPE_MASK)==MDP_ERROR) return mdp->error.error; @@ -89,81 +148,79 @@ int overlay_mdp_send(overlay_mdp_frame *mdp,int flags,int timeout_ms) return -1; /* WHY("Timeout waiting for server response"); */ } -char overlay_mdp_client_socket_path[1024]; -int overlay_mdp_client_socket_path_len=-1; - -int overlay_mdp_client_init() +/** Create a new MDP socket and return its descriptor (-1 on error). */ +int overlay_mdp_client_socket(void) { - if (mdp_client_socket==-1) { - /* Open socket to MDP server (thus connection is always local) */ - if (0) WHY("Use of abstract name space socket for Linux not implemented"); - - mdp_client_socket = socket(AF_UNIX, SOCK_DGRAM, 0); - if (mdp_client_socket < 0) { - WHY_perror("socket"); - return WHY("Could not open socket to MDP server"); - } - - /* We must bind to a temporary file name */ - struct sockaddr_un name; - unsigned int random_value; - if (urandombytes((unsigned char *)&random_value,sizeof(int))) - return WHY("urandombytes() failed"); - name.sun_family = AF_UNIX; - if (overlay_mdp_client_socket_path_len==-1) { - char fmt[1024]; - if (!FORM_SERVAL_INSTANCE_PATH(fmt, "mdp-client-%d-%08x.socket")) - return WHY("Could not form MDP client socket name"); - snprintf(overlay_mdp_client_socket_path,1024,fmt,getpid(),random_value); - overlay_mdp_client_socket_path_len=strlen(overlay_mdp_client_socket_path)+1; - if(config.debug.io) DEBUGF("MDP client socket name='%s'",overlay_mdp_client_socket_path); - } - if (overlay_mdp_client_socket_path_len > sizeof(name.sun_path) - 1) - FATALF("MDP socket path too long (%d > %d)", overlay_mdp_client_socket_path_len, sizeof(name.sun_path) - 1); - - bcopy(overlay_mdp_client_socket_path,name.sun_path, - overlay_mdp_client_socket_path_len); - unlink(name.sun_path); - int len = 1 + strlen(name.sun_path) + sizeof(name.sun_family) + 1; - int r=bind(mdp_client_socket, (struct sockaddr *)&name, len); - if (r) { - WHY_perror("bind"); - return WHY("Could not bind MDP client socket to file name"); - } - - int send_buffer_size=128*1024; - if (setsockopt(mdp_client_socket, SOL_SOCKET, SO_RCVBUF, - &send_buffer_size, sizeof(send_buffer_size)) == -1) - WARN_perror("setsockopt"); + int mdp_sockfd; + char overlay_mdp_client_socket_path[1024]; + int overlay_mdp_client_socket_path_len; + /* Open socket to MDP server (thus connection is always local) */ + if (0) WHY("Use of abstract name space socket for Linux not implemented"); + + mdp_sockfd = socket(AF_UNIX, SOCK_DGRAM, 0); + if (mdp_sockfd < 0) { + WHY_perror("socket"); + return WHY("Could not open socket to MDP server"); } - - return 0; + + /* We must bind to a temporary file name */ + struct sockaddr_un name; + unsigned int random_value; + if (urandombytes((unsigned char *)&random_value,sizeof(int))) + return WHY("urandombytes() failed"); + name.sun_family = AF_UNIX; + char fmt[1024]; + if (!FORM_SERVAL_INSTANCE_PATH(fmt, "mdp-client-%d-%08x.socket")) + return WHY("Could not form MDP client socket name"); + snprintf(overlay_mdp_client_socket_path,1024,fmt,getpid(),random_value); + overlay_mdp_client_socket_path_len=strlen(overlay_mdp_client_socket_path)+1; + if(config.debug.io) DEBUGF("MDP client socket name='%s'",overlay_mdp_client_socket_path); + if (overlay_mdp_client_socket_path_len > sizeof(name.sun_path) - 1) + FATALF("MDP socket path too long (%d > %d)", overlay_mdp_client_socket_path_len, sizeof(name.sun_path) - 1); + + bcopy(overlay_mdp_client_socket_path,name.sun_path, + overlay_mdp_client_socket_path_len); + + /* Store the mapping sockfd/sun_path. */ + mdp_sock_opened(mdp_sockfd, name.sun_path); + + unlink(name.sun_path); + int len = 1 + strlen(name.sun_path) + sizeof(name.sun_family) + 1; + int r=bind(mdp_sockfd, (struct sockaddr *)&name, len); + if (r) { + WHY_perror("bind"); + return WHY("Could not bind MDP client socket to file name"); + } + + int send_buffer_size=128*1024; + if (setsockopt(mdp_sockfd, SOL_SOCKET, SO_RCVBUF, + &send_buffer_size, sizeof(send_buffer_size)) == -1) + WARN_perror("setsockopt"); + + return mdp_sockfd; } -int overlay_mdp_client_done() +int overlay_mdp_client_close(int mdp_sockfd) { - IN(); - if (mdp_client_socket!=-1) { - /* Tell MDP server to release all our bindings */ - overlay_mdp_frame mdp; - mdp.packetTypeAndFlags=MDP_GOODBYE; - overlay_mdp_send(&mdp,0,0); - } - - if (overlay_mdp_client_socket_path_len>-1) - unlink(overlay_mdp_client_socket_path); - if (mdp_client_socket!=-1) - close(mdp_client_socket); - mdp_client_socket=-1; - RETURN(0); + /* Tell MDP server to release all our bindings */ + overlay_mdp_frame mdp; + mdp.packetTypeAndFlags=MDP_GOODBYE; + overlay_mdp_send(mdp_sockfd, &mdp, 0, 0); + + int res = close(mdp_sockfd); + + /* Remove the socket file. */ + mdp_sock_closed(mdp_sockfd); + + return res; } -int overlay_mdp_client_poll(time_ms_t timeout_ms) +int overlay_mdp_client_poll(int mdp_sockfd, time_ms_t timeout_ms) { fd_set r; int ret; FD_ZERO(&r); - FD_SET(mdp_client_socket,&r); + FD_SET(mdp_sockfd, &r); if (timeout_ms<0) timeout_ms=0; struct timeval tv; @@ -171,14 +228,14 @@ int overlay_mdp_client_poll(time_ms_t timeout_ms) if (timeout_ms>=0) { tv.tv_sec=timeout_ms/1000; tv.tv_usec=(timeout_ms%1000)*1000; - ret=select(mdp_client_socket+1,&r,NULL,&r,&tv); + ret=select(mdp_sockfd+1,&r,NULL,&r,&tv); } else - ret=select(mdp_client_socket+1,&r,NULL,&r,NULL); + ret=select(mdp_sockfd+1,&r,NULL,&r,NULL); return ret; } -int overlay_mdp_recv(overlay_mdp_frame *mdp, int port, int *ttl) +int overlay_mdp_recv(int mdp_sockfd, overlay_mdp_frame *mdp, int port, int *ttl) { char mdp_socket_name[101]; unsigned char recvaddrbuffer[1024]; @@ -191,9 +248,7 @@ int overlay_mdp_recv(overlay_mdp_frame *mdp, int port, int *ttl) mdp->packetTypeAndFlags=0; /* Check if reply available */ - set_nonblock(mdp_client_socket); - ssize_t len = recvwithttl(mdp_client_socket,(unsigned char *)mdp, sizeof(overlay_mdp_frame),ttl,recvaddr,&recvaddrlen); - set_block(mdp_client_socket); + ssize_t len = recvwithttl(mdp_sockfd,(unsigned char *)mdp, sizeof(overlay_mdp_frame),ttl,recvaddr,&recvaddrlen); recvaddr_un=(struct sockaddr_un *)recvaddr; /* Null terminate received address so that the stat() call below can succeed */ @@ -233,13 +288,13 @@ int overlay_mdp_recv(overlay_mdp_frame *mdp, int port, int *ttl) } // send a request to servald deamon to add a port binding -int overlay_mdp_bind(unsigned char *localaddr,int port) +int overlay_mdp_bind(int mdp_sockfd, unsigned char *localaddr, int port) { overlay_mdp_frame mdp; mdp.packetTypeAndFlags=MDP_BIND|MDP_FORCE; bcopy(localaddr,mdp.bind.sid,SID_SIZE); mdp.bind.port=port; - int result=overlay_mdp_send(&mdp,MDP_AWAITREPLY,5000); + int result=overlay_mdp_send(mdp_sockfd, &mdp,MDP_AWAITREPLY,5000); if (result) { if (mdp.packetTypeAndFlags==MDP_ERROR) WHYF("Could not bind to MDP port %d: error=%d, message='%s'", @@ -251,7 +306,7 @@ int overlay_mdp_bind(unsigned char *localaddr,int port) return 0; } -int overlay_mdp_getmyaddr(int index,unsigned char *sid) +int overlay_mdp_getmyaddr(int mdp_sockfd, int index, unsigned char *sid) { overlay_mdp_frame a; memset(&a, 0, sizeof(a)); @@ -261,7 +316,7 @@ int overlay_mdp_getmyaddr(int index,unsigned char *sid) a.addrlist.first_sid=index; a.addrlist.last_sid=0x7fffffff; a.addrlist.frame_sid_count=MDP_MAX_SID_REQUEST; - int result=overlay_mdp_send(&a,MDP_AWAITREPLY,5000); + int result=overlay_mdp_send(mdp_sockfd,&a,MDP_AWAITREPLY,5000); if (result) { if (a.packetTypeAndFlags == MDP_ERROR) DEBUGF("MDP Server error #%d: '%s'", a.error.error, a.error.message); diff --git a/mdp_client.h b/mdp_client.h index 3e2cb56f..49d77d1f 100644 --- a/mdp_client.h +++ b/mdp_client.h @@ -32,12 +32,12 @@ struct overlay_mdp_scan{ }; /* Client-side MDP function */ -extern int mdp_client_socket; -int overlay_mdp_client_init(); -int overlay_mdp_client_done(); -int overlay_mdp_client_poll(time_ms_t timeout_ms); -int overlay_mdp_recv(overlay_mdp_frame *mdp, int port, int *ttl); -int overlay_mdp_send(overlay_mdp_frame *mdp,int flags,int timeout_ms); +int overlay_mdp_client_socket(void); +int overlay_mdp_client_close(int mdp_sockfd); +int overlay_mdp_client_poll(int mdp_sockfd, time_ms_t timeout_ms); +int overlay_mdp_bind(int mdp_sockfd, unsigned char *localaddr, int port); +int overlay_mdp_recv(int mdp_sockfd, overlay_mdp_frame *mdp, int port, int *ttl); +int overlay_mdp_send(int mdp_sockfd, overlay_mdp_frame *mdp,int flags,int timeout_ms); int overlay_mdp_relevant_bytes(overlay_mdp_frame *mdp); -#endif \ No newline at end of file +#endif diff --git a/mdp_jni.c b/mdp_jni.c new file mode 100644 index 00000000..16ef3f2b --- /dev/null +++ b/mdp_jni.c @@ -0,0 +1,351 @@ +/* JNI bindings for MDP protocol. + * + * Author(s): + * - Romain Vimont (®om) + */ + +#ifdef HAVE_JNI_H +#include +#include "mdp_client.h" + +#define THROW_NULL_POINTER_EXCEPTION \ + (*env)->ThrowNew(env, cl_nullpointerexception, NULL); +#define THROW_OUT_OF_MEMORY_ERROR \ + (*env)->ThrowNew(env, cl_outofmemoryerror, NULL); +#define THROW_MESH_SOCKET_EXCEPTION(x) \ + (*env)->ThrowNew(env, cl_meshsocketexception, (x)); + +/* jfieldID and jmethodID do not need global ref. */ + +/* Get jfieldID ref. */ +#define G_FIELD(env, cls, name, type) \ + (jfieldID) (*(env))->GetFieldID(env, cls, name, type) +/* Get jmethodID ref. */ +#define G_METHOD(env, cls, name, type) \ + (jmethodID) (*(env))->GetMethodID(env, cls, name, type) +/* Get global jclass ref. */ +#define GG_CLASS(env, name) \ + (jclass) (*(env))->NewGlobalRef(env,(*(env))->FindClass(env, name)) + +/* Classes */ +static jclass cl_meshpacket; +static jclass cl_subscriberid; + +/* Methods */ +static jmethodID m_subscriberid_init; + +/* MeshSocket fields */ +static jfieldID f_meshsocket_fd; +static jfieldID f_meshsocket_rawsid; +static jfieldID f_meshsocket_port; + +/* MeshPacket fields */ +static jfieldID f_meshpacket_buf; +static jfieldID f_meshpacket_offset; +static jfieldID f_meshpacket_length; +static jfieldID f_meshpacket_sid; +static jfieldID f_meshpacket_port; + +/* SubscriberId fields */ +static jfieldID f_subscriberid_binary; + +/* Throwables */ +static jclass cl_meshsocketexception; +static jclass cl_nullpointerexception; +static jclass cl_outofmemoryerror; + +JNIEXPORT void JNICALL +Java_org_servalproject_servald_mdp_MeshSocket_init(JNIEnv * env, jclass cls) +{ + /* Keep JNI refs of fields, methods and classes. */ + + f_meshsocket_fd = G_FIELD(env, cls, "fd", "I"); + f_meshsocket_rawsid = G_FIELD(env, cls, "rawSid", "[B"); + f_meshsocket_port = G_FIELD(env, cls, "port", "I"); + + cl_meshpacket = GG_CLASS(env, "org/servalproject/servald/mdp/MeshPacket"); + f_meshpacket_buf = G_FIELD(env, cl_meshpacket, "buf", "[B"); + f_meshpacket_offset = G_FIELD(env, cl_meshpacket, "offset", "I"); + f_meshpacket_length = G_FIELD(env, cl_meshpacket, "length", "I"); + f_meshpacket_sid = + G_FIELD(env, cl_meshpacket, "sid", + "Lorg/servalproject/servald/SubscriberId;"); + f_meshpacket_port = G_FIELD(env, cl_meshpacket, "port", "I"); + + cl_subscriberid = GG_CLASS(env, "org/servalproject/servald/SubscriberId"); + f_subscriberid_binary = G_FIELD(env, cl_subscriberid, "binary", "[B"); + m_subscriberid_init = G_METHOD(env, cl_subscriberid, "", "([B)V"); + + cl_meshsocketexception = + GG_CLASS(env, "org/servalproject/servald/mdp/MeshSocketException"); + cl_nullpointerexception = GG_CLASS(env, "java/lang/NullPointerException"); + cl_outofmemoryerror = GG_CLASS(env, "java/lang/OutOfMemoryError"); +} + +JNIEXPORT void JNICALL +Java_org_servalproject_servald_mdp_MeshSocket__1create(JNIEnv * env, + jobject this) +{ + jint fd; + + /* Create mesh socket. */ + + if ((fd = overlay_mdp_client_socket()) < 0) { + THROW_MESH_SOCKET_EXCEPTION("Cannot create socket"); + return; /* No resources to clean. */ + } + + /* this.fd = fd; */ + (*env)->SetIntField(env, this, f_meshsocket_fd, fd); +} + +JNIEXPORT void JNICALL +Java_org_servalproject_servald_mdp_MeshSocket__1bind(JNIEnv * env, + jobject this, jint port, + jobject sid_obj) +{ + jint fd; + jbyteArray jsid = NULL; + jbyte *sid = NULL; + char any[SID_SIZE]; + + /* Retrieve values from java objects. */ + + if (sid_obj != NULL) { + /* jsid = sid_obj.binary; */ + if ((jsid = + (jbyteArray) (*env)->GetObjectField(env, sid_obj, + f_subscriberid_binary)) == + NULL) { + THROW_NULL_POINTER_EXCEPTION; + WHY("jsid is NULL"); + return; /* No resources to clean. */ + } + + /* Convert jsid array. */ + if ((sid = + (jbyte *) (*env)->GetByteArrayElements(env, jsid, NULL)) == NULL) { + THROW_OUT_OF_MEMORY_ERROR; + WHY("Cannot create sid"); + goto finally; + } + } else { + /* If sid_obj is NULL, then use sid = 0. */ + memset(any, 0, SID_SIZE); + sid = (jbyte *) any; + } + + /* fd = this.fd; */ + fd = (*env)->GetIntField(env, this, f_meshsocket_fd); + + /* Bind. */ + + if (overlay_mdp_bind(fd, (unsigned char *) sid, port)) { + THROW_MESH_SOCKET_EXCEPTION("Cannot bind to MDP socket"); + /* fall through finally */ + } + +finally: + if (sid_obj != NULL) { + (*env)->ReleaseByteArrayElements(env, jsid, sid, 0); + } +} + +JNIEXPORT void JNICALL +Java_org_servalproject_servald_mdp_MeshSocket__1send(JNIEnv * env, + jobject this, + jobject mdppack) +{ + jint fd, localport, offset, length, port; + jobject sid_obj; + jbyteArray jbuf, jsid, jlocalsid; + jbyte *buf, *sid, *localsid = NULL; + overlay_mdp_frame mdp = { }; /* Init with zeros */ + + /* Retrieve values from java objects. */ + + /* length = mdppack.length; */ + length = (*env)->GetIntField(env, mdppack, f_meshpacket_length); + if (length > MDP_MTU) { + THROW_MESH_SOCKET_EXCEPTION("Mesh packet too big"); + WHYF("Mesh packet too big (size=%d, MTU=%d)", length, MDP_MTU); + return; + } + + /* fd = this.fd; */ + fd = (*env)->GetIntField(env, this, f_meshsocket_fd); + + /* jlocalsid = this.rawSid; */ + jlocalsid = + (jbyteArray) (*env)->GetObjectField(env, this, f_meshsocket_rawsid); + + /* localport = this.port; */ + localport = (*env)->GetIntField(env, this, f_meshsocket_port); + + /* offset = mdppack.offset; */ + offset = (*env)->GetIntField(env, mdppack, f_meshpacket_offset); + + /* port = mdppack.port; */ + port = (*env)->GetIntField(env, mdppack, f_meshpacket_port); + + /* sid_obj = mdppack.sid; */ + if ((sid_obj = + (*env)->GetObjectField(env, mdppack, f_meshpacket_sid)) == NULL) { + THROW_NULL_POINTER_EXCEPTION; + WHY("sid_obj is NULL"); + return; /* No resources to clean. */ + } + + /* jsid = mdppack.sid.binary; */ + if ((jsid = + (jbyteArray) (*env)->GetObjectField(env, sid_obj, + f_subscriberid_binary)) == NULL) { + THROW_NULL_POINTER_EXCEPTION; + WHY("jsid is NULL"); + return; /* No resources to clean. */ + } + + /* jbuf = mdppack.buf; */ + if ((jbuf = + (jbyteArray) (*env)->GetObjectField(env, mdppack, + f_meshpacket_buf)) == NULL) { + THROW_NULL_POINTER_EXCEPTION; + WHY("jbuf is NULL"); + return; /* No resources to clean. */ + }; + + /* Convert arrays. */ + + /* jlocalsid can be NULL: the user wants to use its own SID. */ + if (jlocalsid != NULL + && (localsid = + (jbyte *) (*env)->GetByteArrayElements(env, jlocalsid, + NULL)) == NULL) { + THROW_OUT_OF_MEMORY_ERROR; + WHY("Cannot create localsid"); + return; /* No resources to clean. */ + } + + if ((sid = (jbyte *) (*env)->GetByteArrayElements(env, jsid, NULL)) == NULL) { + THROW_OUT_OF_MEMORY_ERROR; + WHY("Cannot create sid"); + goto finally1; + } + + if ((buf = (jbyte *) malloc(length * sizeof(jbyte))) == NULL) { + THROW_OUT_OF_MEMORY_ERROR; + WHY("Cannot create buf"); + goto finally2; + } + + (*env)->GetByteArrayRegion(env, jbuf, offset, length, buf); + if ((*env)->ExceptionCheck(env) == JNI_TRUE) { + WHY("IndexOutOfBoundsException while filling buf"); + goto finally3; + } + + /* Fill mdp structure. */ + + mdp.packetTypeAndFlags = MDP_TX; + mdp.out.src.port = localport; + if (localsid != NULL) { + memcpy(mdp.out.src.sid, localsid, SID_SIZE); + /* else, src.sid is let to 0, so servald will automatically fill it with + my sid. */ + } + memcpy(mdp.out.dst.sid, sid, SID_SIZE); + mdp.out.dst.port = port; + mdp.out.payload_length = length; + memcpy(mdp.out.payload, buf, length); + + /* Send data. */ + if (overlay_mdp_send(fd, &mdp, 0, 0)) { + THROW_MESH_SOCKET_EXCEPTION("Cannot send data to servald"); + /* fall through finally */ + } + + /* Finally, release resources. */ + +finally3: + free(buf); + +finally2: + (*env)->ReleaseByteArrayElements(env, jsid, sid, 0); + +finally1: + if (localsid != NULL) { + (*env)->ReleaseByteArrayElements(env, jlocalsid, localsid, 0); + } +} + +JNIEXPORT void JNICALL +Java_org_servalproject_servald_mdp_MeshSocket__1receive(JNIEnv * env, + jobject this, + jobject mdppack) +{ + jint fd, localport, offset, length; + int buf_length, ttl; + jobject sid_obj; + jbyteArray jbuf, jsid; + jbyte *sid; + overlay_mdp_frame mdp; + + /* fd = this.fd; */ + fd = (*env)->GetIntField(env, this, f_meshsocket_fd); + + /* localport = this.port; */ + localport = (*env)->GetIntField(env, this, f_meshsocket_port); + + /* length = mdppack.length; */ + length = (*env)->GetIntField(env, mdppack, f_meshpacket_length); + + /* Receive data. */ + if (overlay_mdp_recv(fd, &mdp, localport, &ttl)) { + (*env)->ThrowNew(env, cl_meshsocketexception, + "Cannot receive data from servald"); + WHY("Cannot receive data from servald"); + return; + } + + /* offset = mdppack.offset; */ + offset = (*env)->GetIntField(env, mdppack, f_meshpacket_offset); + + /* If payload is too big, it is truncated. */ + buf_length = + length < mdp.in.payload_length ? length : mdp.in.payload_length; + + /* Write payload. */ + jbuf = (jbyteArray) (*env)->GetObjectField(env, mdppack, f_meshpacket_buf); + (*env)->SetByteArrayRegion(env, jbuf, offset, buf_length, + (jbyte *) mdp.in.payload); + + /* Write payload length (received length, not truncated). */ + (*env)->SetIntField(env, mdppack, f_meshpacket_length, + mdp.in.payload_length); + + /* Write source sid. */ + jsid = (*env)->NewByteArray(env, SID_SIZE); + sid = (*env)->GetByteArrayElements(env, jsid, NULL); + memcpy(sid, mdp.in.src.sid, SID_SIZE); + (*env)->ReleaseByteArrayElements(env, jsid, sid, 0); + + /* sid_obj = new SubscriberId(jsid); */ + sid_obj = + (*env)->NewObject(env, cl_subscriberid, m_subscriberid_init, jsid); + (*env)->SetObjectField(env, mdppack, f_meshpacket_sid, sid_obj); + + /* Write source port. */ + (*env)->SetIntField(env, mdppack, f_meshpacket_port, mdp.in.src.port); +} + +JNIEXPORT void JNICALL +Java_org_servalproject_servald_mdp_MeshSocket__1close(JNIEnv * env, + jobject this) +{ + /* fd = this.fd; */ + jint fd = (*env)->GetIntField(env, this, f_meshsocket_fd); + + /* Close socket. */ + overlay_mdp_client_close(fd); +} +#endif diff --git a/mdp_jni.h b/mdp_jni.h new file mode 100644 index 00000000..a4d5cbc2 --- /dev/null +++ b/mdp_jni.h @@ -0,0 +1,61 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class org_servalproject_servald_mdp_MeshSocket */ + +#ifndef _Included_org_servalproject_servald_mdp_MeshSocket +#define _Included_org_servalproject_servald_mdp_MeshSocket +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_servalproject_servald_mdp_MeshSocket + * Method: init + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_servalproject_servald_mdp_MeshSocket_init + (JNIEnv *, jclass); + +/* + * Class: org_servalproject_servald_mdp_MeshSocket + * Method: _create + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_servalproject_servald_mdp_MeshSocket__1create + (JNIEnv *, jobject); + +/* + * Class: org_servalproject_servald_mdp_MeshSocket + * Method: _bind + * Signature: (ILorg/servalproject/servald/SubscriberId;)V + */ +JNIEXPORT void JNICALL Java_org_servalproject_servald_mdp_MeshSocket__1bind + (JNIEnv *, jobject, jint, jobject); + +/* + * Class: org_servalproject_servald_mdp_MeshSocket + * Method: _send + * Signature: (Lorg/servalproject/servald/mdp/MeshPacket;)V + */ +JNIEXPORT void JNICALL Java_org_servalproject_servald_mdp_MeshSocket__1send + (JNIEnv *, jobject, jobject); + +/* + * Class: org_servalproject_servald_mdp_MeshSocket + * Method: _receive + * Signature: (Lorg/servalproject/servald/mdp/MeshPacket;)V + */ +JNIEXPORT void JNICALL Java_org_servalproject_servald_mdp_MeshSocket__1receive + (JNIEnv *, jobject, jobject); + +/* + * Class: org_servalproject_servald_mdp_MeshSocket + * Method: _close + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_servalproject_servald_mdp_MeshSocket__1close + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/serval.h b/serval.h index d6456b67..ed9f8b36 100644 --- a/serval.h +++ b/serval.h @@ -631,8 +631,10 @@ int cli_puts(const char *str); int cli_printf(const char *fmt, ...); int cli_delim(const char *opt); -int overlay_mdp_getmyaddr(int index,unsigned char *sid); -int overlay_mdp_bind(unsigned char *localaddr,int port); +int is_configvarname(const char *arg); + +int overlay_mdp_getmyaddr(int mpd_sockfd, int index, unsigned char *sid); +int overlay_mdp_bind(int mdp_sockfd, unsigned char *localaddr, int port); int overlay_route_node_info(overlay_mdp_nodeinfo *node_info); int overlay_interface_register(char *name, struct in_addr addr, diff --git a/sourcefiles.mk b/sourcefiles.mk index 8a9f842c..36203264 100644 --- a/sourcefiles.mk +++ b/sourcefiles.mk @@ -18,6 +18,7 @@ SERVAL_SOURCES = $(SERVAL_BASE)audiodevices.c \ $(SERVAL_BASE)lsif.c \ $(SERVAL_BASE)main.c \ $(SERVAL_BASE)mdp_client.c \ + $(SERVAL_BASE)mdp_jni.c \ $(SERVAL_BASE)os.c \ $(SERVAL_BASE)mem.c \ $(SERVAL_BASE)instance.c \