I've implemented a C native function with for android NDK, to send UDP packets.
I have a working receiver but i seem to get nothing when i use the sender.
How can i get more info from the return value of sendto? I'm having a hard time debugging native functions - no "debug step mode"
can anyone see anything wrong about the sender code? is there something im not doing right?
Thanks!
jstring
Java_com_example_adhocktest_SenderUDP_SendUdpJNI( JNIEnv* env,
jobject thiz, jstring ip, jstring message)
{
int PORT = 8888;
int i;
int sock_fd;
char *_ip = (*env)->GetStringUTFChars(env, ip, 0);
char *send_buf = (*env)->GetStringUTFChars(env, message, 0);
////////////////
//////// create socket
////////////////
if (( sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
return (*env)->NewStringUTF(env,"Cannot create socket");
}
struct sockaddr_in myaddr;
////////////////
//////// send
////////////////
struct sockaddr_in servaddr;
memset((char*)&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = 8888;
if ((inet_aton(_ip,&servaddr.sin_addr)) == 0) {
return (*env)->NewStringUTF(env,"Cannot decode IP address");
}
int retval = sendto(sock_fd, send_buf, strlen(send_buf), 0, (struct sockaddr*)&servaddr, sizeof(servaddr));
close(sock_fd);
char str[100];
if ( retval < 0) {
sprintf(str, "sendto failed with %d", retval);
} else {
sprintf(str, "sendto success with %d", retval);
}
return (*env)->NewStringUTF(env,str);
}
The problem in the code was this line
servaddr.sin_port = 8888;
the correct line would be
servaddr.sin_port = htons(8888);
the reason for this was explained here by
bornruffians:
" htons() stands for "host-to-network short". On a given platform
(called the host), it converts the endianness of a short (16-bit
generally) integer to the endianness required for sending on the
network (generally big endian).
sendto() returns the number of bytes sent. You should check that
retval is the string length of your 'send_buf' variable, not just a
positive value."
Thanks all for your help,
Ben.
If it's still not working, did you give your app the necessary permissions for manipulating sockets?
<uses-permission android:name="android.permission.INTERNET" />
htons() stands for "host-to-network short". On a given platform (called the host), it converts the endianness of a short (16-bit generally) integer to the endianness required for sending on the network (generally big endian).
sendto() returns the number of bytes sent. You should check that retval is the string length of your 'send_buf' variable, not just a positive value.
Related
I am writting an application for Android which passes a JAVA fd taken from ParcelFileDescriptor.getFd() which according to [1] states that the int I get back is a native fd.
Now, with this fd, I am trying to write it over a unix domain socket to the existing process which is listening. To do this, I am using JNI and I pass the int received above to the JNI function as an argument named fdToSend.
When my JNI code attempts to call sendmsg(), an error occurs stating "Bad file number".
With some help from google, It seems like the socket connection might be closed when I call sendmsg(), but I cannot see how this would be the case.
The sendfd() method is exactly as found in [2].
Below is my bridging JNI function:
JNIEXPORT jint JNICALL Java_com_example_myapp_AppManager_bridgeSendFd(JNIEnv *env, jint fdToSend) {
int fd;
struct sockaddr_un addr;
if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
__android_log_print(ANDROID_LOG_ERROR, APPNAME, "socket() failed: %s (socket fd = %d)\n", strerror(errno), fd);
return (jint)-1;
}
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, "/data/data/com.example.myapp/sock_path", sizeof(addr.sun_path)-1);
if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
__android_log_print(ANDROID_LOG_ERROR, APPNAME, "connect() failed: %s (fd = %d)\n", strerror(errno), fd);
return (jint)-1;
}
return (jint)sendfd(fd, (int)fdToSend);
}
[1] http://developer.android.com/reference/android/os/ParcelFileDescriptor.html#getFd()
[2] https://stackoverflow.com/a/4491203/2796346
Turns out the issue was the JNI function declaration.
The first arg is JNIEnv, the second is jclass THEN it's the values passed in from Java (i.e. for me, fdToSend).
So, my guess is that since I was using the second arg (supposed to be a jclass), then I'm probably getting a memory reference or something weird like that.
As seen here: https://stackoverflow.com/a/10743451/2796346
I write the Android application using libusb-1.0.9 and NDK (Android 4.0.4+) which has to read out audio-data from the USB-audiocard. The USB device from libusb opens successfully, and for it it is possible to receive all interfaces/EndPoint list. But when making ISOC transfer I faced with following unclear me error:
Debugging C code of making transfer:
static uint8_t buf[12];
static void cb_xfr(struct libusb_transfer *xfr)
{
LOGD("USB callback\n");
libusb_free_transfer(xfr);
}
JNIEXPORT jlong JNICALL
Java_com_usbtest_libusb_Libusb_makeISOCTransfer(JNIEnv *env, jobject this, jlong ms)
{
static struct libusb_transfer *xfr;
int num_iso_pack = 1;
unsigned char ep = 0x84;
xfr = libusb_alloc_transfer(num_iso_pack);
if (!xfr) {
LOGD("libusb_alloc_transfer: errno=%d\n", errno);
return -1000;
}
LOGD("libusb_fill_iso_transfer: ep=%x, buf=%d, num iso=%d\n", ep, sizeof(buf), num_iso_pack);
libusb_fill_iso_transfer(xfr, handle, ep, buf, sizeof(buf), num_iso_pack, cb_xfr, NULL, 0);
libusb_set_iso_packet_lengths(xfr, sizeof(buf)/num_iso_pack);
int res = libusb_submit_transfer(xfr);
LOGD("libusb_submit_transfer: %d, errno=%d\n", res, errno);
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
libusb_handle_events_timeout(NULL, &tv);
return res;
}
After a call of libusb_submit_transfer I received a mistake: libusb_submit_transfer: -1, errno -2
And text messages:
need 1 32k URBs for transfer
first URB failed, easy peasy
EndPoint 0x84 is true for audio-in. The buf[] size = 12 - corresponds to the field wMaxPacketSize of this EndPoint. I request 1 transfer. Field of xfr->status = 0, but callback isn't caused.
I thought that it is necessary to increase the buf buffer to 32K - I increased, but it didn't help.
I tried to increase quantity of transfers. Same error.
Prompt me please in what there can be a error?
I found the solution of this problem.
In this topic http://en.it-usenet.org/thread/14995/14985/ there was a similar question, and the decision appeared to make detach for device HID USB interfaces.
I've used libusb_detach_kernel to detach the 2 hid drivers and submit
transfer returned 0!!
I made libusb_detach_kernel_driver(handle, interface) for all interfaces of the device (0..3) after device opening, and as a result of libusb_submit_transfer return SUCCESS of transfer.
I have implemented a UDP client on android's native part(i.e. in C). Inorder to receive data from the server(PC) both my device and PC are connected over a wifi connection.
When the client is put on a rooted device, it is able to receive data from the server perfectly. However on a non-rooted device, although it doesnt show any error, it is not able to send/receive data form/to the server.
Below is my server code:
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<sys/stat.h>
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<fcntl.h>
int main()
{
int cont,create_socket,new_socket,addrlen,fd;
int bufsize = 3000;
int nameLen=0;
int client_address_size=0;
char *buffer = malloc(bufsize);
char fname[256];
struct sockaddr_in address,client;
if ((create_socket = socket(AF_INET,SOCK_DGRAM,0)) > 0)
printf("The socket was created\n");
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(15000);
if (bind(create_socket,(struct sockaddr *)&address,sizeof(address))== 0)
printf("Binding Socket\n");
nameLen=sizeof(address);
if (getsockname(create_socket,(struct sockaddr *)&address,&nameLen)<0)
{
printf("\n\ngetsockname() error\n");
exit(3);
}
printf("Port assigned is %d\n", ntohs(address.sin_port));
client_address_size=sizeof(client);
if(recvfrom(create_socket,fname, 255,0,(struct sockaddr *) &client,&client_address_size)<0)
{
printf("\n\nrecvfrom() failed\n");
exit(4);
}
printf("A request for filename %s Received..\n", fname);
if ((fd=open(fname, O_RDONLY))<0)
{
perror("File Open Failed");
exit(0);
}
while((cont=read(fd, buffer, bufsize))>0)
{
sleep(1);
sendto(create_socket,buffer,cont,0,(struct sockaddr *) &client,client_address_size);
printf("\n\nPacket sent\n");
}
sendto(create_socket,"*",1,0,(struct sockaddr *) &client,client_address_size);
printf("Request Completed\n");
return close(create_socket);
}
client code on android NDK:
JNIEXPORT void JNICALL Java_com_examplemyPlayer_startClient
(JNIEnv *env, jclass jobj, jint portNo, jstring argv1)
{
__android_log_print(ANDROID_LOG_DEBUG,"MYAPP","start client has entered....",NULL);
//int portno=portNo;
const char *servIP = (*env)->GetStringUTFChars(env, argv1, 0);
__android_log_print(ANDROID_LOG_DEBUG,"MYAPP","Server IP address:%s",servIP);
__android_log_print(ANDROID_LOG_DEBUG,"MYAPP","Server Port No.:%d",portno);
qBuff=(unsigned char *)malloc(sizeof(char)*Q_SIZE);//qBuff is a global pointer
int create_socket,cont;
int bytesWritten=0;
int bufsize = 3000;
int server_address_size=0;
char *buffer = malloc(bufsize);
char reqFname[8]="Bub.bin";
struct sockaddr_in address,server;
int serv_addr_size = sizeof(address);
if ((create_socket = socket(AF_INET,SOCK_DGRAM,0)) < 0)
__android_log_print(ANDROID_LOG_DEBUG,"MYAPP","The Socket was NOT created",NULL);
__android_log_print(ANDROID_LOG_DEBUG,"MYAPP","The Socket was successfully created",NULL);
address.sin_family = AF_INET;
address.sin_port = htons(15000);
address.sin_addr.s_addr=inet_addr(servIP);
if((sendto(create_socket, reqFname, sizeof(reqFname), 0,(struct sockaddr *) &address,sizeof(address)))==-1)
__android_log_print(ANDROID_LOG_DEBUG,"MYAPP","Error sending filename to server",NULL);
__android_log_print(ANDROID_LOG_DEBUG,"MYAPP","Request Accepted... \n\nReceiving File...",NULL);
server_address_size=sizeof(server);
__android_log_print(ANDROID_LOG_DEBUG,"MYAPP","Contents of the file are:",NULL);
while((cont=recvfrom(create_socket, buffer, bufsize, 0,(struct sockaddr *) &address,&serv_addr_size))>0)
{
if(buffer[cont-1]=='*')
break;
memcpy(qBuff+r,buffer,cont);//copying received data to a circular queue
r=(r+3000)%Q_SIZE;
__android_log_print(ANDROID_LOG_DEBUG,"MYAPP","Bytes received:%d",cont);
//write(1, buffer, cont);
}
__android_log_print(ANDROID_LOG_DEBUG,"MYAPP","EOF",NULL);
free(qBuff);
close(create_socket);
}
The above code works fine for a rooted device, but not on an unrooted one. Since the application that i'm creating should be able to run on both rooted and unrooted devices, i need to make the code run on an unrooted device also.
The server was able to connect to the rooted device only after diabling the Linux firewall using /sbin/services iptable stop. So is there a firewall for unrooted device which is blocking the communication port. In the above code i'm trying port no 15000. However i have also tried for other ports also but did'nt workout.
So i kindly request the readers to provide useful answers or reference links for the same. Thanks in advance.
When I call recvfrom using the Android NDK, I get NULL returned to my sockaddr_in from. This same exact code works fine on my desktop environment, but not on the device.
int MyClass::ReceiveData(char *buffer, int bufferLength)
{
int numBytes = 0;
struct sockaddr_in from;
socklen_t fromLength = sizeof(struct sockaddr_in);
numBytes = recvfrom(mConnectionSocket,
buffer,
bufferLength,
0,
(struct sockaddr *)&from,
&fromLength);
if (numBytes == -1)
perror("recvfrom");
int fromAddress = ntohl(from.sin_addr.s_addr);
return fromAddress;
}
Anybody have any ideas?
I get NULL returned to my sockaddr_in 'from'
That's not possible with that code. from isn't a pointer that can become NULL. More probably your sockaddr_in structure named by from is getting zeroed. Which would be caused by using this on a TCP socket. If this is TCP you should be calling getpeername() on the socket to get the peer address.
I'm trying to produce a simple server that will allow me test the Androids security features. I need to develop an application that will open a socket.
I've produced something similar in C, but I am having no look with java. Here's the application in C
// simpleserver3.c
#define MY_PORT 9999
#define MAXBUF 99
void indata(int clientfd, struct sockaddr_in client_addr)
{
char buffer[12];
printf("%s:%d connected\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
recv(clientfd, buffer, MAXBUF, 0); //this is will overflow the buffer
printf("%X \n", &buffer);
}
int main(int Count, char *Strings[])
{
struct sockaddr_in self, client_addr;
int sockfd,clientfd;
/*---Create streaming socket---*/
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) //socketfd = handle for socket
{
perror("Socket");
exit(errno);
}
/*---Initialize address/port structure---*/
bzero(&self, sizeof(self));
self.sin_family = AF_INET;
self.sin_port = htons(MY_PORT);
self.sin_addr.s_addr = INADDR_ANY;
/*---Bind the structure to the socket handle ---*/
if ( bind(sockfd, (struct sockaddr*)&self, sizeof(self)) != 0 )
{
perror("socket--bind");
exit(errno);
}
/*---Make it a "listening socket"---*/
if ( listen(sockfd, 20) != 0 )
{
perror("socket--listen");
exit(errno);
}
//set socklen_t to length of client address
socklen_t addrlen=sizeof(client_addr);
/*---accept a connection (creating a data pipe)---*/
clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &addrlen); //create handle for communicating
indata(clientfd, client_addr);
close(clientfd);
close(sockfd);
return;
}
Any sugguestion would be great, Aneel
It's been a while since I used C, so I can't comment on your C code, but you should probably take a look at the Android documentation for the Socket class:
http://developer.android.com/reference/java/net/Socket.html
Check out this example: http://thinkandroid.wordpress.com/2010/03/27/incorporating-socket-programming-into-your-applications/