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.
Related
I have successfully connected my android phone as client to a raspberry pi as server.
The next step is sending data to the raspberry pi using bytes. Am I doing it correctly for the Android in Java?
socket.getOutputStream().write(String.valueOf(progress).getBytes());
Thereafter, on my raspberry pi side, I will have to receive the bytes in C. I am facing problems in receiving data on server. Here is my code.
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
int main(){
int welcomeSocket,clientSocket;
char buffer[1024];
struct sockaddr_in serverAddr;
struct sockaddr_storage serverStorage;
socklen_t addr_size;
ssize_t nread;
/*---- Create the socket. The three arguments are: ----*/
/* 1) Internet domain 2) Stream socket 3) Default protocol (TCP in this case) */
welcomeSocket = socket(PF_INET, SOCK_STREAM, 0);
/*---- Configure settings of the server address struct ----*/
/* Address family = Internet */
serverAddr.sin_family = AF_INET;
/* Set port number, using htons function to use proper byte order */
serverAddr.sin_port = htons(9999);
/* Set IP address to localhost */
serverAddr.sin_addr.s_addr = INADDR_ANY;
/* Set all bits of the padding field to 0 */
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
/*---- Bind the address struct to the socket ----*/
bind(welcomeSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr));
/*---- Listen on the socket, with 5 max connection requests queued ----*/
if(listen(welcomeSocket,5)==0){
printf("Listening\n");
}
else
printf("Error\n");
/*---- Accept call creates a new socket for the incoming connection ----*/
addr_size = sizeof serverStorage;
clientSocket = accept(welcomeSocket, (struct sockaddr *) &serverStorage, &addr_size);
printf("Successfully Connected!!!\n\r");
//Receive data from android
//recv(welcomeSocket,buffer,1024,0);
nread = recvfrom(clientSocket, buffer,1024, 0, (struct sockaddr *) &serverStorage, &addr_size);
if(nread==-1)
perror("Error!");
else
printf("Data received: %s",buffer);
return 0;
}
As from Pravin's comment, I tried using the Recvfrom and perror, it showed an error of -1.
Okay! I realised the problem. I realised I didnt use the client socket created previously. I kept on using the Server's socket lol. Didn't notice it at first. I used an example to see what was different between my server and the example server, which really helped!
http://www.binarytides.com/server-client-example-c-sockets-linux/
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.
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.
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 having some troubles with the Android NDK.
My project requires software components written in C that can receive data over TCP to be executed on the Android OS.
To that end, I've made a simple server and client in C using BSD sockets and can send messages back and forth successfully across the connection on PCs. Now I've moved the clientside code into the NDK, and can't connect to my server from the emulator or from an actual android device. NDK compiles without warnings or errors, the emulator/phone are on wifi and have internet permissions enabled in the manifest. What gives?
All it does is make a socket, fill in host/port info and attempt to connect: If it does connect, send a message, else return an error. Android always returns a negative value for connect
This client code, compiled/executed on Mac/Windows/Linux, works:
PC Client code:
int tcp_socket = socket(AF_INET, SOCK_STREAM,0);
if(tcp_socket< 0 ) {
cerr << "Failed to create TCP socket." << endl;
return 2;
}
sockaddr_in server_tcp_add;
server_tcp_add.sin_family = AF_INET;
server_tcp_add.sin_port = htons(tcp_port); //set via command line: Yes, they are the same for the android
hostent *hostp = gethostbyname(server_host);
memcpy(&server_tcp_add.sin_addr, hostp->h_addr, hostp->h_length);
socklen_t slen = sizeof(server_tcp_add);
if(connect(tcp_socket,(sockaddr*)&server_tcp_add, slen) <0 ){
cerr<< "Failed to connect to server with TCP. " << endl;
close(tcp_socket);
return 3;
}
char* myString = "This is my message";
send(tcp_socket, myString, strlen(myString), 0);
close(tcp_socket);
This code, executed on the Android NDK, does not
Code: NDK Client
jstring Java_networking_client_activate_initiateTcpConnection(JNIEnv* env, jobject javaThis){
int tcp_socket = socket(AF_INET, SOCK_STREAM,0);
if(tcp_socket < 0){
return (*env)->NewStringUTF(env, "ERROR CREATING SOCKET");
}
const char* server_host = "some.numbers.that.work"; //It's a valid IP I don't feel like sharing
unsigned short server_port = 43000;
struct sockaddr_in server_tcp_addr;
server_tcp_addr.sin_family = AF_INET;
server_tcp_addr.sin_port = htons(server_port);
struct hostent *hostp = gethostbyname(server_host);
memcpy(&server_tcp_addr, hostp->h_addr, hostp->h_length);
socklen_t slen = sizeof(server_tcp_addr);
if(connect(tcp_socket,(struct sockaddr*)&server_tcp_addr, slen) < 0){ //fails here
close(tcp_socket);
return (*env)->NewStringUTF(env, "ERROR CONNECTING TO SERVER");
}
char* message = "hello from android!";
send(tcp_socket, &message, sizeof(message),0);
return (*env)->NewStringUTF(env, "TCP message sent!");
}
Largely identical; required to put struct in front of everything for NDK to compile.
--edit--I should also mention, I have been able to send data over sockets in Java with this app. Just the C sockets that's really screwing stuff up. Even a sample of someone else that has C sockets working via NDK would be tremendously appreciated.
This is a very late answer, however it might still be useful...
I changed this line:
memcpy(&server_tcp_addr, hostp->h_addr, hostp->h_length);
to this:
memcpy(&server_tcp_addr.sin_addr.s_addr, hostp->h_addr, hostp->h_length);
and that did the trick for me.