androidc++tcpandroid-source

Cannot receive text over local TCP connection


Sending text over local TCP connection succeeds! Sending text from Ubuntu to AOSP over local ip address. For some reason it works to accept text with a third-party apk app. But it does not work in C++ environment inside the service. I've tried different variations of the code. I can't accept the text. Error: "Connection refused" OR "Failed recv: Transport endpoint is not connected".

The service is successfully allowed to use the internet. Checked with.

static const String16 sAccessWifiStatePermission("android.permission.ACCESS_WIFI_STATE");
static const String16 sInternetPermission("android.permission.INTERNET");
static const String16 sAccessNetworkStatePermission("android.permission.ACCESS_NETWORK_STATE");
...
bool checksAccessNetworkStatePermission = permissionChecker.checkPermissionForPreflight(
            sAccessNetworkStatePermission, attributionSource, String16(), AppOpsManager::OP_NONE)!= permission::PermissionChecker::PERMISSION_HARD_DENIED;
...

I use different ports, for example, 5030..5033. And use local ip address of smartphone: 192.168.2.110. I specify this address in c++ code in AOSP or use INADDR_ANY. Why can't I accept the text ?

One of the code variants that can't accept text:

std::string receiveTextTcp(int port) {

    struct sockaddr_in serv_addr;
    int fd = socket(AF_INET, SOCK_STREAM, 0);
  if (fd < 0) {
     ALOGI("Failed socket: %s", strerror(errno));
    return "";
  }
ALOGI("fd : %d, port:%d", fd, port);
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(port);
    int reuse_flag = 1;

int result = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse_flag, sizeof(reuse_flag));
if (result < 0) {
    ALOGI("Failed setsockopt: %s, port:%d", strerror(errno), port);
}

int bind_result = bind(fd, reinterpret_cast<sockaddr*>(&serv_addr), sizeof(serv_addr));

if (bind_result < 0) {
    ALOGI("Failed bind: %s, port:%d", strerror(errno), port);
}

result = listen(fd, 1);
if (result < 0) {
    ALOGI("Failed listen: %s, port:%d", strerror(errno), port);
}

  char buffer[1024];
  int bytes_received = recv(fd, buffer, sizeof(buffer), 0);
  if (bytes_received < 0) {
    ALOGI("Failed recv: %s, port:%d", strerror(errno), port);
    
  }

  ALOGI("Failed buffer: %s, port:%d", buffer, port);


  close(fd);


   return "";
}

A successful code variant that successfully sends text to a PC:

bool SendData(const std::string& ip, int port, const std::string& text) {

  int sockfd = socket(AF_INET, SOCK_STREAM, 0);
  if (sockfd < 0) {
    ALOGI("Failed to create socket: %s, sockfd:%d", strerror(errno), sockfd);
    return false;
  }

  struct sockaddr_in servaddr;
  memset(&servaddr, 0, sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_port = htons(port);

  // Use inet_pton instead of inet_addr
  if (inet_pton(AF_INET, ip.c_str(), &servaddr.sin_addr) <= 0) {
     ALOGI("Invalid IP address: %s", ip.c_str() );
    close(sockfd);
    return false;
  }

  if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {
     ALOGI("Failed to connect to server: %s", strerror(errno) );
    close(sockfd);
    return false;
  }


const char* message = text.c_str();
size_t message_len = strlen(message);

if (send(sockfd, message, message_len, 0) < 0) {
     ALOGI("Failed send, err: %s . message:%s", strerror(errno), message );
    close(sockfd);
    return false;
  } else{
    ALOGI("send ok. message:%s", message );
  } 

  close(sockfd);

  return true;
}

Solution

  • A "Transport endpoint is not connected" error is errno 107, aka ENOTCONN. Android runs on top of Linux, and the Linux recv() documentation says:

    ENOTCONN
    The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and accept(2)).

    You cannot use recv() (or send()) on a TCP socket that you are listen()'ing on. Instead, you must first accept() a client that is connect()'ing to you, to establish a connection between them. Then you can use recv() (and send()) on the new socket descriptor that accept() returns to you, eg:

    ...
    result = listen(fd, 1);
    if (result < 0) {
        ALOGI("Failed listen: %s, port:%d", strerror(errno), port);
    }
    
    // ADD THIS!!!
    int clientfd = accept(fd, NULL, NULL);
    if (clientfd < 0) {
        ALOGI("Failed accept: %s, port:%d", strerror(errno), port);
    }
    
    // use client fd not listening fd!!!
    char buffer[1024];
    int bytes_received = recv(/*fd*/clientfd, buffer, sizeof(buffer), 0);
    ...
    
    // don't forget to close the client when finished...
    close(clientfd);
    ...