#include "socket_server.h"
|
#include "xcam_obj_debug.h"
|
#include <errno.h>
|
#include <fcntl.h>
|
#include <sys/time.h>
|
|
#ifdef __ANDROID__
|
#include <cutils/sockets.h>
|
#endif
|
|
#ifdef LOG_TAG
|
#undef LOG_TAG
|
#endif
|
#define LOG_TAG "socket_server.cpp"
|
|
#ifdef __ANDROID__
|
#define UNIX_DOMAIN "/dev/socket/camera_tool"
|
#else
|
#define UNIX_DOMAIN "/tmp/UNIX.domain"
|
#endif
|
|
#define RKAIQ_SOCKET_DATA_OFFSET 24
|
#define RKAIQ_SOCKET_DATA_HEADER_LEN 4
|
static const uint8_t RKAIQ_SOCKET_DATA_HEADER[4] = {'R', 0xAA, 0xFF, 'K'};
|
|
typedef enum __aiq_ipc_cmd_id {
|
AIQ_IPC_CMD_UNKNOWN = -1,
|
AIQ_IPC_CMD_WRITE = 0,
|
AIQ_IPC_CMD_READ = 1,
|
} aiq_ipc_cmd_id;
|
|
SocketServer::~SocketServer() {
|
}
|
|
|
void SocketServer::SaveEixt() {
|
LOGD("socket in aiq uit");
|
quit_ = 1;
|
if (_stop_fds[1] != -1) {
|
char buf = 0xf; // random value to write to flush fd.
|
unsigned int size = write(_stop_fds[1], &buf, sizeof(char));
|
if (size != sizeof(char))
|
LOGW("Flush write not completed");
|
}
|
}
|
|
void hexdump2(char* buf, const int num)
|
{
|
int i;
|
for(i = 0; i < num; i++) {
|
LOGE("%02X ", buf[i]);
|
if((i + 1) % 32 == 0) {
|
}
|
}
|
return;
|
}
|
|
unsigned int MurMurHash(const void* key, int len)
|
{
|
const unsigned int m = 0x5bd1e995;
|
const int r = 24;
|
const int seed = 97;
|
unsigned int h = seed ^ len;
|
// Mix 4 bytes at a time into the hash
|
const unsigned char* data = (const unsigned char*)key;
|
while(len >= 4)
|
{
|
unsigned int k = *(unsigned int*)data;
|
k *= m;
|
k ^= k >> r;
|
k *= m;
|
h *= m;
|
h ^= k;
|
data += 4;
|
len -= 4;
|
}
|
// Handle the last few bytes of the input array
|
switch(len)
|
{
|
case 3:
|
h ^= data[2] << 16;
|
case 2:
|
h ^= data[1] << 8;
|
case 1:
|
h ^= data[0];
|
h *= m;
|
};
|
// Do a few final mixes of the hash to ensure the last few
|
// bytes are well-incorporated.
|
h ^= h >> 13;
|
h *= m;
|
h ^= h >> 15;
|
return h;
|
}
|
|
int ProcessText(int client_socket, rk_aiq_sys_ctx_t* ctx, char * data, int size) {
|
char * tmpArray = data;
|
int packetSize = (tmpArray[2] & 0xff) | ((tmpArray[3] & 0xff) << 8) | ((tmpArray[4] & 0xff) << 16) | ((tmpArray[5] & 0xff) << 24);
|
int ret;
|
|
if( size != packetSize) {
|
LOGE("packetSize check failed,returnsize is %d, pack is %d",size, packetSize);
|
return -1;
|
}
|
|
char* receivedPacket = (char*)malloc(packetSize);
|
memset(receivedPacket, 0, packetSize);
|
memcpy(receivedPacket, tmpArray, packetSize);
|
|
//parse data
|
RkAiqSocketData receivedData;
|
int offset = 0;
|
offset += 2;
|
|
//packetSize
|
memcpy(receivedData.packetSize, receivedPacket+offset, 4);
|
offset += 4;
|
//command id
|
memcpy((void*) & (receivedData.commandID), receivedPacket + offset, sizeof(int));
|
offset += sizeof(int);
|
//command id
|
memcpy((void*) & (receivedData.commandResult), receivedPacket + offset, sizeof(int));
|
offset += sizeof(int);
|
|
//data size
|
memcpy((void*) & (receivedData.dataSize), receivedPacket + offset, sizeof(unsigned int));
|
//LOGE("receivedData.dataSize:%d", receivedData.dataSize);
|
|
offset += sizeof(unsigned int);
|
//data
|
receivedData.data = (char*)malloc(receivedData.dataSize);
|
memcpy(receivedData.data, receivedPacket + offset, receivedData.dataSize);
|
offset += receivedData.dataSize;
|
//data hash
|
memcpy((void*) & (receivedData.dataHash), receivedPacket + offset, sizeof(unsigned int));
|
free(receivedPacket);
|
receivedPacket = NULL;
|
|
//hash check
|
unsigned int dataHash = MurMurHash(receivedData.data, receivedData.dataSize);
|
//LOGE("receivedData.dataSize:%d", receivedData.dataSize);
|
//LOGE("dataHash calculated:%x", dataHash);
|
//LOGE("receivedData.dataHash:%x", receivedData.dataHash);
|
|
if(dataHash != receivedData.dataHash) {
|
LOGE("data hash not match.return");
|
free(receivedData.data);
|
receivedData.data = NULL;
|
return -1;
|
}
|
//else {
|
//LOGE("data hash check pass.");
|
//}
|
|
RkAiqSocketData dataReply;
|
ret = ProcessCommand(ctx, &receivedData, &dataReply);
|
free(receivedData.data);
|
receivedData.data = NULL;
|
|
if (ret != -1) {
|
unsigned int packetSize = sizeof(RkAiqSocketData) + dataReply.dataSize - sizeof(char*);
|
memcpy(dataReply.packetSize, &packetSize, 4);
|
char* dataToSend = (char*)malloc(packetSize);
|
int offset = 0;
|
char magic[2] = {'R','K'};
|
memset(dataToSend, 0, packetSize);
|
memcpy(dataToSend, magic, 2);
|
offset += 2;
|
memcpy(dataToSend + offset, dataReply.packetSize, 4);
|
offset += 4;
|
memcpy(dataToSend + offset, (void*)&dataReply.commandID, sizeof(dataReply.commandID));
|
offset += sizeof(dataReply.commandID);
|
memcpy(dataToSend + offset, (void*)&dataReply.commandResult, sizeof(dataReply.commandResult));
|
offset += sizeof(dataReply.commandResult);
|
memcpy(dataToSend + offset, (void*)&dataReply.dataSize, sizeof(dataReply.dataSize));
|
offset += sizeof(dataReply.dataSize);
|
memcpy(dataToSend + offset, dataReply.data, dataReply.dataSize);
|
offset += dataReply.dataSize;
|
//LOGE("offset is %d,packetsize is %d",offset,packetSize);
|
memcpy(dataToSend + offset, (void*)&dataReply.dataHash, sizeof(dataReply.dataHash));
|
send(client_socket, dataToSend, packetSize, 0);
|
if (dataReply.data != NULL){
|
free(dataReply.data);
|
dataReply.data = NULL;
|
}
|
free(dataToSend);
|
dataToSend = NULL;
|
}
|
else {
|
return -1;
|
}
|
return 0;
|
}
|
|
int SocketServer::Send(int cilent_socket, char *buff, int size) {
|
return send(cilent_socket, buff, size, 0);
|
}
|
|
int SocketServer::Recvieve() {
|
char buffer[MAXPACKETSIZE];
|
char* receivedpacket;
|
//int size = sizeof(buffer);
|
int size = 6, offset =0;
|
int packetsize = 0;
|
struct timeval interval = {3, 0};
|
struct RkAiqSocketData AiqData;
|
socklen_t sosize = sizeof(clientAddress);
|
setsockopt(client_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&interval,
|
sizeof(struct timeval));
|
while (!quit_) {
|
int length = 0;
|
if (size < 17000){
|
length = recv(client_socket, buffer, size, 0);
|
}
|
else {
|
length = recv(client_socket, buffer, 17000, 0);
|
}
|
|
if (length <= 0) {
|
//close(client_socket);
|
//client_socket = accept(sockfd, (struct sockaddr *)&clientAddress, &sosize);
|
//setsockopt(client_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&interval,
|
// sizeof(struct timeval));
|
size = 6;
|
offset = 0;
|
//break;
|
} else {
|
if (offset == 0) {
|
if (buffer[0] =='R' && buffer [1] =='K') {
|
packetsize = (buffer[2] & 0xff) | ((buffer[3] & 0xff) << 8) | ((buffer[4] & 0xff) << 16) | ((buffer[5] & 0xff) << 24);
|
receivedpacket = (char*)malloc(packetsize);
|
memset(receivedpacket, 0, packetsize);
|
memcpy(receivedpacket, buffer, 6);
|
size = packetsize - 6;
|
offset += length;
|
memset(buffer,0x00,sizeof(buffer));
|
} else {
|
recv(client_socket, buffer, 8192, 0);
|
memset(buffer,0x00,sizeof(buffer));
|
}
|
} else {
|
memcpy(receivedpacket+offset, buffer, length);
|
offset += length;
|
size = packetsize - offset;
|
//LOGE("packest size is %d,offset is %d,",packetsize,offset);
|
if (size <= 0){
|
//LOGE("%x,%x,%x,%x,pro",receivedpacket[2],receivedpacket[3],receivedpacket[4],receivedpacket[5]);
|
ProcessText(client_socket, aiq_ctx, receivedpacket, packetsize);
|
size = 6;
|
free(receivedpacket);
|
receivedpacket = NULL;
|
offset = 0;
|
}
|
}
|
}
|
if (callback_) {
|
callback_(client_socket, buffer, length);
|
}
|
}
|
return 0;
|
}
|
|
uint8_t* bit_stream_find(uint8_t* data, int size, const uint8_t* dst, int len)
|
{
|
int start_pos = -1;
|
|
if (!data || !size || !dst || !len) {
|
return NULL;
|
}
|
|
if (size < len) {
|
return NULL;
|
}
|
|
for (start_pos=0;start_pos<size-len;start_pos++) {
|
if (0 == memcmp(data + start_pos, dst, len)) {
|
return data + start_pos;
|
}
|
}
|
|
return NULL;
|
}
|
|
int rkaiq_ipc_send(int sockfd, int id, int ack, int seqn,
|
void* data, uint32_t data_len)
|
{
|
uint32_t out_len = sizeof(RkAiqSocketData_t) - sizeof(char*) + data_len;
|
char* out_data = (char*)malloc(out_len);
|
RkAiqSocketData_t *out_res = (RkAiqSocketData_t*)out_data;
|
|
out_res->magic[0] = 'R';
|
out_res->magic[1] = 0xAA;
|
out_res->magic[2] = 0xFF;
|
out_res->magic[3] = 'K';
|
|
out_res->cmd_id = id;
|
out_res->cmd_ret = ack;
|
out_res->payload_size = data_len;
|
out_res->sequence = seqn;
|
out_res->packet_size = data_len;
|
|
memcpy(&out_res->data, data, data_len);
|
|
send(sockfd, out_data, out_len, 0);
|
|
return 0;
|
}
|
|
// return 0 if a sigle packet or payload size
|
int rkaiq_packet_parse(RkAiqSocketData_t* aiq_data, uint8_t* buffer, int len)
|
{
|
uint8_t* start_pos = NULL;
|
uint32_t packet_size = 0;
|
RkAiqSocketData_t* aiq_pkt = NULL;
|
|
start_pos = bit_stream_find(buffer, len,
|
RKAIQ_SOCKET_DATA_HEADER,
|
RKAIQ_SOCKET_DATA_HEADER_LEN);
|
|
if (start_pos) {
|
if ((len - (start_pos - buffer)) < (int)sizeof(RkAiqSocketData_t)) {
|
LOGE("Not a complete packet [%d], discard!\n", len);
|
return -1;
|
}
|
|
aiq_pkt = (RkAiqSocketData_t*) start_pos;
|
packet_size = &buffer[len-1] - start_pos;
|
|
memcpy(aiq_data, aiq_pkt, sizeof(RkAiqSocketData_t));
|
|
// refer to the real offset of data
|
aiq_data->data = (uint8_t*)(&aiq_pkt->data);
|
|
// sigle packet : HEAD:24byte + PAYLOAD + CRC:1byte
|
if (aiq_pkt->payload_size <= (packet_size - 1)) {
|
return 0;
|
}
|
return packet_size;
|
} else {
|
// may be fragment packet, head already parsed just return full size
|
return -1;
|
}
|
}
|
|
int rkaiq_is_uapi(const char* cmd_str)
|
{
|
if (strstr(cmd_str, "uapi/0/")) {
|
return 1;
|
} else {
|
return 0;
|
}
|
}
|
|
int SocketServer::Recvieve(int sync) {
|
uint8_t buffer[MAXPACKETSIZE];
|
std::vector<uint8_t> rawCMDStream;
|
struct timeval interval = {3, 0};
|
|
setsockopt(client_socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&interval,
|
sizeof(struct timeval));
|
while (!quit_) {
|
RkAiqSocketData_t aiq_data;
|
int recv_len = -1;
|
int payload_len = 0;
|
|
memset(&buffer, 0, MAXPACKETSIZE);
|
memset(static_cast<void*>(&aiq_data), 0, sizeof(RkAiqSocketData_t));
|
|
// 1. recv MAX SIZE every timne.
|
recv_len = recv(client_socket, buffer, MAXPACKETSIZE, 0);
|
|
if (recv_len == 0) {
|
break;
|
}
|
|
if (recv_len < 0) {
|
continue;
|
}
|
|
payload_len = rkaiq_packet_parse(&aiq_data, buffer, recv_len);
|
if (payload_len == 0) {
|
goto response;
|
} else if (payload_len > 0) {
|
// Found new magic flag, reset.
|
rawCMDStream.clear();
|
}
|
|
rawCMDStream.insert(rawCMDStream.end(), buffer, buffer + recv_len);
|
|
payload_len = rkaiq_packet_parse(&aiq_data, &rawCMDStream[0],
|
rawCMDStream.size());
|
// packet not complete yet
|
if (payload_len != 0) {
|
continue;
|
}
|
|
response:
|
#if 1
|
printf("[TCP]%d,%d,%d--->PC CMD STRING:\n%s\n", client_socket,
|
aiq_data.cmd_id, aiq_data.payload_size, aiq_data.data);
|
#endif
|
|
switch(aiq_data.cmd_id) {
|
case AIQ_IPC_CMD_WRITE:
|
{
|
if (rkaiq_is_uapi((char*)aiq_data.data)) {
|
char* ret_str_js = NULL;
|
rkaiq_uapi_unified_ctl(aiq_ctx, (char*)aiq_data.data,
|
&ret_str_js, 0);
|
|
} else {
|
rk_aiq_uapi_sysctl_tuning(aiq_ctx, (char*)aiq_data.data);
|
}
|
}
|
break;
|
case AIQ_IPC_CMD_READ:
|
{
|
char* out_data = NULL;
|
if (rkaiq_is_uapi((char*)aiq_data.data)) {
|
rkaiq_uapi_unified_ctl(aiq_ctx, (char*)aiq_data.data,
|
&out_data, 1);
|
} else {
|
out_data = rk_aiq_uapi_sysctl_readiq(aiq_ctx, (char*)aiq_data.data);
|
}
|
|
if (!out_data) {
|
LOGE("[Tuning]: aiq return NULL!\n");
|
break;
|
}
|
#if 1
|
printf("---> read:\n%s\n", out_data);
|
#endif
|
rkaiq_ipc_send(client_socket, AIQ_IPC_CMD_READ, 0, 0, out_data, strlen(out_data));
|
}
|
break;
|
default:
|
break;
|
}
|
|
if (sync) {
|
|
}
|
|
rawCMDStream.clear();
|
}
|
|
return 0;
|
}
|
|
#define POLL_STOP_RET (3)
|
|
int
|
SocketServer::poll_event (int timeout_msec, int fds[])
|
{
|
int num_fds = fds[1] == -1 ? 1 : 2;
|
struct pollfd poll_fds[num_fds];
|
int ret = 0;
|
|
memset(poll_fds, 0, sizeof(poll_fds));
|
poll_fds[0].fd = fds[0];
|
poll_fds[0].events = (POLLIN | POLLOUT | POLLHUP);
|
|
if (fds[1] != -1) {
|
poll_fds[1].fd = fds[1];
|
poll_fds[1].events = POLLPRI | POLLIN | POLLOUT;
|
poll_fds[1].revents = 0;
|
}
|
|
ret = poll (poll_fds, num_fds, timeout_msec);
|
if (fds[1] != -1) {
|
if ((poll_fds[1].revents & POLLIN) || (poll_fds[1].revents & POLLPRI)) {
|
LOGD("%s: Poll returning from flush", __FUNCTION__);
|
return POLL_STOP_RET;
|
}
|
}
|
|
if (ret > 0 && (poll_fds[0].revents & (POLLERR | POLLNVAL | POLLHUP))) {
|
LOGE("polled error");
|
return -1;
|
}
|
|
return ret;
|
}
|
|
void SocketServer::Accepted() {
|
struct timeval interval = {3, 0};
|
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&interval,sizeof(struct timeval));
|
while (!quit_) {
|
//int client_socket;
|
socklen_t sosize = sizeof(clientAddress);
|
int fds[2] = { sockfd, _stop_fds[0] };
|
int poll_ret = poll_event(-1, fds);
|
if (poll_ret == POLL_STOP_RET) {
|
LOG1("poll socket stop success !");
|
break;
|
} else if (poll_ret <= 0) {
|
LOGW("poll socket got error(0x%x) but continue\n");
|
::usleep (10000); // 10ms
|
continue;
|
}
|
client_socket = accept(sockfd, (struct sockaddr *)&clientAddress, &sosize);
|
if (client_socket < 0) {
|
if (errno != EAGAIN)
|
LOGE("Error socket accept failed %d %d\n", client_socket, errno);
|
continue;
|
}
|
LOGD("socket accept ip %s\n", serverAddress);
|
tool_mode_set(true);
|
|
//std::shared_ptr<std::thread> recv_thread;
|
//recv_thread = make_shared<thread>(&SocketServer::Recvieve, this, client_socket);
|
//recv_thread->join();
|
//recv_thread = nullptr;
|
this->Recvieve(0);
|
close(client_socket);
|
LOGD("socket accept close\n");
|
tool_mode_set(false);
|
}
|
LOGD("socket accept exit\n");
|
}
|
|
#ifdef __ANDROID__
|
int SocketServer::getAndroidLocalSocket() {
|
static const char socketName[] = "camera_tool";
|
int sock = android_get_control_socket(socketName);
|
|
if (sock < 0) {
|
// TODO(Cody): will always failed with permission denied
|
// Should let init to create socket
|
sock =
|
socket_local_server(socketName, ANDROID_SOCKET_NAMESPACE_RESERVED,
|
SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK);
|
}
|
|
return sock;
|
}
|
#endif
|
|
int SocketServer::Process(rk_aiq_sys_ctx_t* ctx) {
|
LOGW("SocketServer::Process\n");
|
int opt = 1;
|
aiq_ctx = ctx;
|
|
#ifdef __ANDROID__
|
sockfd = getAndroidLocalSocket();
|
if (sockfd < 0) {
|
LOGE("Error get socket %s\n", strerror(errno));
|
return -1;
|
}
|
fcntl(sockfd, F_SETFD, FD_CLOEXEC);
|
#else
|
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
memset(&serverAddress, 0, sizeof(serverAddress));
|
|
serverAddress.sun_family = AF_LOCAL;
|
strncpy(serverAddress.sun_path,UNIX_DOMAIN,sizeof(serverAddress.sun_path)-1);
|
unlink(UNIX_DOMAIN);
|
|
if ((::bind(sockfd, (struct sockaddr *)&serverAddress,
|
sizeof(serverAddress))) < 0) {
|
LOGE("Error bind %s\n", strerror(errno));
|
return -1;
|
}
|
#endif
|
if (listen(sockfd, 5) < 0) {
|
LOGE("Error listen\n");
|
return -1;
|
}
|
|
if (pipe(_stop_fds) < 0) {
|
LOGE("poll stop pipe error: %s", strerror(errno));
|
} else {
|
if (fcntl(_stop_fds[0], F_SETFL, O_NONBLOCK)) {
|
LOGE("Fail to set stop pipe flag: %s", strerror(errno));
|
}
|
}
|
|
this->accept_threads_ = std::unique_ptr<std::thread>(
|
new std::thread(&SocketServer::Accepted, this));
|
|
return 0;
|
}
|
|
void SocketServer::Deinit(){
|
struct linger so_linger;
|
so_linger.l_onoff = 1;
|
so_linger.l_linger = 0;
|
this->SaveEixt();
|
// setsockopt(client_socket,SOL_SOCKET,SO_LINGER,&so_linger,sizeof(so_linger));
|
// struct timeval interval = {0, 0};
|
// setsockopt(client_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&interval,sizeof(struct timeval));
|
if (this->accept_threads_) this->accept_threads_->join();
|
// shutdown(client_socket, SHUT_RDWR);
|
// close(client_socket);
|
unlink(UNIX_DOMAIN);
|
close(sockfd);
|
this->accept_threads_ = nullptr;
|
if (_stop_fds[0] != -1) close(_stop_fds[0]);
|
if (_stop_fds[1] != -1) close(_stop_fds[1]);
|
LOGD("socekt stop in aiq");
|
}
|