环境:
PC sys:windows xp
JDK:1.6
NDK:采用Android NDK,R9B
编译环境:MinGW
Descrpiton:
我正在开发一个sip端点应用程序,该应用程序基于Android设备中的开源sip堆栈" doubango"套接字函数使用NDK调用,但不是直接使用JAVA调用。正常使用时,没问题。然后使用某些软件清洁设备的内存,或者手动停止服务,并使其异常退出。似乎它在没有调用函数关闭(套接字)的情况下停止。下次我使用时,会抛出错误调用套接字函数:sendto(),errno = 1表示"操作不允许"。
我已添加" uses-permission android:name =" android.permission.INTERNET""
有人可以帮我一把吗?
PS:我在没有ROOT权限的设备中进行测试,这个问题就会发生。但我测试了一个具有ROOT权限的设备,它并没有发生。这有关系吗?
工作完成。我在Java层中犯了一些错误。我在Sip堆栈中设置的一些参数是错误的。
以下是代码段:
int tnet_sockfd_sendto(tnet_fd_t fd, const struct sockaddr *to, const void* buf, tsk_size_t size)
{
tsk_size_t sent = 0;
int ret = -1;
if(fd == TNET_INVALID_FD){
TSK_DEBUG_ERROR("Using invalid FD to send data.");
goto bail;
}
if(!buf || !size){
TSK_DEBUG_ERROR("Using invalid BUFFER.");
ret = -2;
goto bail;
}
while(sent < size){
int try_guard = 10;
#if TNET_UNDER_WINDOWS
WSABUF wsaBuffer;
DWORD numberOfBytesSent = 0;
wsaBuffer.buf = ((CHAR*)buf) + sent;
wsaBuffer.len = (size - sent);
try_again:
ret = WSASendTo(fd, &wsaBuffer, 1, &numberOfBytesSent, 0, to, tnet_get_sockaddr_size(to), 0, 0); // returns zero if succeed
if(ret == 0){
ret = numberOfBytesSent;
}
#else
try_again:
ret = sendto(fd, (((const uint8_t*)buf)+sent), (size-sent), 0, to, tnet_get_sockaddr_size(to)); // returns number of sent bytes if succeed
#endif
if(ret <= 0){
if(tnet_geterrno() == TNET_ERROR_WOULDBLOCK){
TSK_DEBUG_INFO("SendUdp() - WouldBlock. Retrying...");
if(try_guard--){
tsk_thread_sleep(10);
goto try_again;
}
}
else{
***/* Just throw error here*/***
TSK_DEBUG_INFO("errno: %d",tnet_geterrno());
TNET_PRINT_LAST_ERROR("sendto() failed");
}
goto bail;
}
else{
sent += ret;
}
}
bail:
return (size == sent) ? sent : ret;
}
#define tnet_soccket(family, type, protocol) socket((family), (type), (protocol))
tnet_socket_t* tnet_socket_create_2(const char* host, tnet_port_t port_,tnet_socket_type_t type, tsk_bool_t nonblocking, tsk_bool_t bindsocket)
{
tnet_socket_t *sock;
if((sock = tsk_object_new(tnet_socket_def_t))){
int status;
tsk_istr_t port;
struct addrinfo *result = tsk_null;
struct addrinfo *ptr = tsk_null;
struct addrinfo hints;
tnet_host_t local_hostname;
sock->port = port_;
tsk_itoa(sock->port, &port);
sock->type = type;
memset(local_hostname, 0, sizeof(local_hostname));
/* Get the local host name */
if(host != TNET_SOCKET_HOST_ANY && !tsk_strempty(host)){
memcpy(local_hostname, host, tsk_strlen(host)>sizeof(local_hostname)-1 ? sizeof(local_hostname)-1 : tsk_strlen(host));
}
else{
if(TNET_SOCKET_TYPE_IS_IPV6(sock->type)){
memcpy(local_hostname, "::", 2);
}
else{
memcpy(local_hostname, "0.0.0.0", 7);
}
}
TSK_DEBUG_INFO("local_hostname: %s",local_hostname);
/* hints address info structure */
memset(&hints, 0, sizeof(hints));
hints.ai_family = TNET_SOCKET_TYPE_IS_IPV46(sock->type) ? AF_UNSPEC : (TNET_SOCKET_TYPE_IS_IPV6(sock->type) ? AF_INET6 : AF_INET);
hints.ai_socktype = TNET_SOCKET_TYPE_IS_STREAM(sock->type) ? SOCK_STREAM : SOCK_DGRAM;
hints.ai_protocol = TNET_SOCKET_TYPE_IS_STREAM(sock->type) ? IPPROTO_TCP : IPPROTO_UDP;
hints.ai_flags = AI_PASSIVE
#if !TNET_UNDER_WINDOWS || _WIN32_WINNT>=0x600
| AI_ADDRCONFIG
#endif
;
/* Performs getaddrinfo */
if((status = tnet_getaddrinfo(local_hostname, port, &hints, &result))){
TNET_PRINT_LAST_ERROR("tnet_getaddrinfo(family=%d, hostname=%s and port=%s) failed: [%s]",
hints.ai_family, local_hostname, port, tnet_gai_strerror(status));
goto bail;
}
/* Find our address. */
for(ptr = result; ptr; ptr = ptr->ai_next){
sock->fd = tnet_soccket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if(ptr->ai_family != AF_INET6 && ptr->ai_family != AF_INET){
continue;
}
/* To avoid "Address already in use" error
* Check issue 368 (https://code.google.com/p/doubango/issues/detail?id=368) to understand why it's not used for UDP/DTLS.
*/
//
if (TNET_SOCKET_TYPE_IS_STREAM(sock->type)) {
TSK_DEBUG_INFO("Socket Type: Stream");
if ((status = tnet_sockfd_reuseaddr(sock->fd, 1))) {
// do not break...continue
}
}
if(bindsocket){
/* Bind the socket */
if((status = bind(sock->fd, ptr->ai_addr, ptr->ai_addrlen))){
TNET_PRINT_LAST_ERROR("bind to [%s:%s]have failed", local_hostname, port);
tnet_socket_close(sock);
continue;
}
/* Get local IP string. */
if((status = tnet_get_ip_n_port(sock->fd , tsk_true/*local*/, &sock->ip, &sock->port))) /* % */
//if((status = tnet_getnameinfo(ptr->ai_addr, ptr->ai_addrlen, sock->ip, sizeof(sock->ip), 0, 0, NI_NUMERICHOST)))
{
TNET_PRINT_LAST_ERROR("Failed to get local IP and port.");
tnet_socket_close(sock);
continue;
}
}
/* sets the real socket type (if ipv46) */
if(ptr->ai_family == AF_INET6) {
TNET_SOCKET_TYPE_SET_IPV6Only(sock->type);
}
else{
TNET_SOCKET_TYPE_SET_IPV4Only(sock->type);
}
break;
}
/* Check socket validity. */
if(!TNET_SOCKET_IS_VALID(sock)) {
TNET_PRINT_LAST_ERROR("Invalid socket.");
goto bail;
}
#if TNET_UNDER_IPHONE || TNET_UNDER_IPHONE_SIMULATOR
/* disable SIGPIPE signal */
{
int yes = 1;
if(setsockopt(sock->fd, SOL_SOCKET, SO_NOSIGPIPE, (char*)&yes, sizeof(int))){
TNET_PRINT_LAST_ERROR("setsockopt(SO_NOSIGPIPE) have failed.");
}
}
#endif /* TNET_UNDER_IPHONE */
/* Sets the socket to nonblocking mode */
if(nonblocking){
if((status = tnet_sockfd_set_nonblocking(sock->fd))){
goto bail;
}
}
bail:
/* Free addrinfo */
tnet_freeaddrinfo(result);
/* Close socket if failed. */
if(status){
if(TNET_SOCKET_IS_VALID(sock)){
tnet_socket_close(sock);
}
return tsk_null;
}
}
return sock;
}
int tnet_sockfd_reuseaddr(tnet_fd_t fd, int reuseAddr)
{
if (fd != TNET_INVALID_FD) {
int ret;
#if defined(SOLARIS)
static const char yes = '1';
static const char no = '0';
#else
static const int yes = 1;
static const int no = 0;
#endif
if ((ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char*)(reuseAddr ? &yes : &no), sizeof(int)))) {
TNET_PRINT_LAST_ERROR("setsockopt(SO_REUSEADDR, fd=%d) have failed", fd);
return ret;
}
// #if defined(SO_REUSEPORT)
if ((ret = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char*)(reuseAddr ? &yes : &no), sizeof(int)))) {
TNET_PRINT_LAST_ERROR("setsockopt(SO_REUSEPORT, fd=%d) have failed", fd);
return ret;
}
// #endif
return 0;
}
return -1;
}
#define tnet_sockfd_set_nonblocking(fd) tnet_sockfd_set_mode(fd, 1)
int tnet_sockfd_set_mode(tnet_fd_t fd, int nonBlocking)
{
if(fd != TNET_INVALID_FD)
{
#if TNET_UNDER_WINDOWS
ULONG mode = nonBlocking;
if(ioctlsocket(fd, FIONBIO, &mode))
//if(WSAIoctl(fd, FIONBIO, &nonblocking, sizeof(nonblocking), NULL, 0, NULL, NULL, NULL) == SOCKET_ERROR)
{
TNET_PRINT_LAST_ERROR("ioctlsocket(FIONBIO) have failed.");
return -1;
}
#else
int flags;
if((flags = fcntl(fd, F_GETFL, 0)) < 0) {
TNET_PRINT_LAST_ERROR("fcntl(F_GETFL) have failed.");
return -1;
}
if(fcntl(fd, F_SETFL, flags | (nonBlocking ? O_NONBLOCK : ~O_NONBLOCK)) < 0){
TNET_PRINT_LAST_ERROR("fcntl(O_NONBLOCK/O_NONBLOCK) have failed.");
return -1;
}
#endif
// int on = 1;
// ioctl(fd, FIONBIO, (char *)&on);
}
return 0;
}