462 lines
10 KiB
C
462 lines
10 KiB
C
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <pthread.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
#include <sys/select.h>
|
|
#include <errno.h>
|
|
#include <sys/prctl.h>
|
|
#include <poll.h>
|
|
#include <sys/eventfd.h>
|
|
|
|
#ifdef BUILD_FOR_ANDROID
|
|
#include <netinet/tcp.h>
|
|
#endif
|
|
|
|
#include "dataserver_inner.h"
|
|
|
|
#include "list.h"
|
|
|
|
#ifdef LOG_LOGCAT
|
|
|
|
#define LOG_TAG "ccdataserver"
|
|
#include <log/log.h>
|
|
#define ds_inf(_fmt_,...) ALOGI("%s:%d "_fmt_, __func__, __LINE__, ##__VA_ARGS__)
|
|
#define ds_err(_fmt_,...) ALOGE("%s:%d "_fmt_, __func__, __LINE__, ##__VA_ARGS__)
|
|
|
|
#else
|
|
|
|
#define ds_inf(_fmt_,...) printf("I %s:%d "_fmt_"\n", __func__, __LINE__, ##__VA_ARGS__)
|
|
#define ds_err(_fmt_,...) printf("E %s:%d "_fmt_"\n", __func__, __LINE__, ##__VA_ARGS__)
|
|
|
|
#endif
|
|
|
|
|
|
/*The global ipc server*/
|
|
static ds_server_t server;
|
|
|
|
|
|
static int do_read(ds_connection_t *conn, void *buf, size_t count)
|
|
{
|
|
int fd = conn->fd;
|
|
int n = read(fd, buf, count);
|
|
if (n < 0) {
|
|
ds_err("fd[%d] read error, err(%d:%s)", fd, errno, strerror(errno));
|
|
return -1;
|
|
} else if (n == 0) {
|
|
ds_inf("fd[%d] EOF", fd);
|
|
return -1;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
static int do_write(ds_connection_t *conn, void *buf, size_t count)
|
|
{
|
|
int fd = conn->fd;
|
|
int sent = 0;
|
|
while (sent < count) {
|
|
int n = write(fd, (uint8_t *)buf + sent, count - sent);
|
|
if (n <= 0)
|
|
return -1;
|
|
sent += n;
|
|
}
|
|
return sent;
|
|
}
|
|
|
|
static void *connection_read_task(void *args)
|
|
{
|
|
ds_connection_t *conn = (ds_connection_t *)args;
|
|
|
|
{
|
|
char name[32];
|
|
snprintf(name, 32, "DAConnR-%d", conn->fd);
|
|
prctl(PR_SET_NAME, name);
|
|
}
|
|
|
|
ds_inf("connection fd[%d] session(read) started", conn->fd);
|
|
|
|
int n;
|
|
|
|
while (conn->active) {
|
|
fd_set rfds;
|
|
struct timeval timeout = {1, 0};
|
|
int maxfd;
|
|
int ret;
|
|
|
|
FD_ZERO(&rfds);
|
|
FD_SET(conn->fd, &rfds);
|
|
maxfd = conn->fd + 1;
|
|
|
|
ret = select(maxfd, &rfds, NULL, NULL, &timeout);
|
|
if (ret < 0) /*error*/
|
|
break;
|
|
else if (ret == 0) /*timeout*/
|
|
continue;
|
|
|
|
if (!conn->active)
|
|
break;
|
|
|
|
if (FD_ISSET(conn->fd, &rfds)) {//data_in proc
|
|
|
|
ret = ds_connection_manage_data_in(conn);
|
|
if (ret == -3)
|
|
break;
|
|
if (ret == -1)
|
|
continue;
|
|
}
|
|
}
|
|
|
|
end:
|
|
/*cleanup the connection, [connection death state]*/
|
|
ds_connection_cleanup(conn);
|
|
|
|
ds_inf("connection to [%s] fd[%d] session(read) finished", conn->client, conn->fd);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void *connection_write_task(void *args)
|
|
{
|
|
ds_connection_t *conn = (ds_connection_t *)args;
|
|
|
|
{
|
|
char name[32];
|
|
snprintf(name, 32, "DAConnW-%d", conn->fd);
|
|
prctl(PR_SET_NAME, name);
|
|
}
|
|
|
|
ds_inf("connection fd[%d] session(write) started", conn->fd);
|
|
|
|
int n;
|
|
|
|
while (conn->active) {
|
|
fd_set wfds;
|
|
struct timeval timeout = {1, 0};
|
|
int maxfd;
|
|
int ret;
|
|
|
|
FD_ZERO(&wfds);
|
|
FD_SET(conn->fd, &wfds);
|
|
maxfd = conn->fd + 1;
|
|
|
|
ret = select(maxfd, NULL, &wfds, NULL, &timeout);
|
|
if (ret < 0) /*error*/
|
|
break;
|
|
else if (ret == 0) /*timeout*/
|
|
continue;
|
|
|
|
if (!conn->active)
|
|
break;
|
|
|
|
if (FD_ISSET(conn->fd, &wfds)) {//data_out proc
|
|
|
|
ret = ds_connection_manage_data_out(conn);
|
|
if (ret == -3)
|
|
break;
|
|
if (ret == -1)
|
|
continue;
|
|
}
|
|
}
|
|
|
|
end:
|
|
/*cleanup the connection, [connection death state]*/
|
|
ds_connection_cleanup(conn);
|
|
|
|
ds_inf("connection to [%s] fd[%d] session(write) finished", conn->client, conn->fd);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int init_connection(ds_connection_t *conn, void *priv)
|
|
{
|
|
conn->fd = (int)priv;
|
|
return 0;
|
|
}
|
|
|
|
static void deinit_connection(ds_connection_t *conn)
|
|
{
|
|
close(conn->fd);
|
|
}
|
|
|
|
static int start_connection(ds_connection_t *conn)
|
|
{
|
|
#ifdef BUILD_FOR_ANDROID
|
|
{
|
|
int val = 1;
|
|
errno = 0;
|
|
if (setsockopt(conn->fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val))) {
|
|
ds_err("setsockopt SO_KEEPALIVE failed. err(%d/%s)", errno, strerror(errno));
|
|
}
|
|
int keepidle = 20;
|
|
int keepinterval = 3;
|
|
setsockopt(conn->fd, SOL_TCP, TCP_KEEPIDLE, &keepidle, sizeof(keepidle));
|
|
setsockopt(conn->fd, SOL_TCP, TCP_KEEPINTVL, &keepinterval, sizeof(keepinterval));
|
|
|
|
}
|
|
#endif
|
|
|
|
int ret = pthread_create(&conn->wr_thread, NULL, connection_write_task, conn);
|
|
if (ret == 0)
|
|
ret = pthread_create(&conn->rd_thread, NULL, connection_read_task, conn);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void stop_connection(ds_connection_t *conn)
|
|
{
|
|
ds_inf("connection closing... fd[%d] dev[%s] cli[%s]",
|
|
conn->fd, conn->device, conn->client);
|
|
|
|
conn->active = 0;
|
|
|
|
//todo: fixme
|
|
//close(conn->fd);
|
|
ds_rb_set_flag(&conn->rb, DS_RB_FLAG_EXIT);
|
|
|
|
pthread_join(conn->wr_thread, NULL);
|
|
pthread_join(conn->rd_thread, NULL);
|
|
|
|
ds_inf("connection closed, fd[%d] dev[%s] cli[%s]",
|
|
conn->fd, conn->device, conn->client);
|
|
}
|
|
|
|
static void *server_task(void *args)
|
|
{
|
|
ds_server_t *server = (ds_server_t *)args;
|
|
|
|
{
|
|
char name[32];
|
|
snprintf(name, 32, "DAServer-%d", server->fd);
|
|
prctl(PR_SET_NAME, name);
|
|
}
|
|
|
|
ds_inf("daserver fd[%d] accepting connections....",
|
|
server->fd);
|
|
|
|
struct sockaddr_un c_un;
|
|
socklen_t c_len = sizeof(c_un);
|
|
int connfd;
|
|
|
|
while (server->running) {
|
|
int ret;
|
|
struct pollfd fds[2];
|
|
|
|
memset(fds, 0, sizeof(fds));
|
|
|
|
fds[0].fd = server->fd;
|
|
fds[1].fd = server->evt_fd;
|
|
fds[0].events = fds[1].events = POLLIN | POLLERR;
|
|
|
|
ret = poll(fds, 2, 1000);
|
|
if (ret < 0)
|
|
break;
|
|
else if (ret == 0)
|
|
goto next;
|
|
|
|
if (!server->running)
|
|
break;
|
|
|
|
if (!(fds[0].revents & POLLIN))
|
|
goto next;
|
|
|
|
if ((connfd = accept(server->fd, (struct sockaddr *)&c_un, &c_len)) < 0) {
|
|
ds_err("accept error, err(%d:%s)", errno, strerror(errno));
|
|
goto next;
|
|
}
|
|
|
|
ds_inf("connection fd[%d], start session... ",
|
|
connfd);
|
|
|
|
ds_connection_t *conn = ds_connection_create();
|
|
|
|
if (conn) {
|
|
|
|
conn->init = init_connection;
|
|
conn->deinit = deinit_connection;
|
|
conn->start = start_connection;
|
|
conn->stop = stop_connection;
|
|
conn->read = do_read;
|
|
conn->write = do_write;
|
|
|
|
ret = ds_connection_start(server, conn, (void *)(long)connfd);
|
|
if (ret != 0) {
|
|
ds_err("connection fd[%d], session start fail", connfd);
|
|
}
|
|
|
|
} else {
|
|
ds_err("memory fail");
|
|
}
|
|
|
|
next:
|
|
ds_server_cleanup_connections(server, 0);
|
|
}
|
|
|
|
ds_server_cleanup_connections(server, 1);
|
|
|
|
server->running = 0;
|
|
|
|
ds_inf("daserver fd[%d] exit", server->fd);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int init_server(ds_server_t *server, void *arg1, void *arg2)
|
|
{
|
|
server->fd = (int)arg1;
|
|
server->evt_fd = (int)arg2;
|
|
return 0;
|
|
}
|
|
|
|
static void deinit_server(ds_server_t *server)
|
|
{
|
|
if (server->fd != -1) {
|
|
close(server->fd);
|
|
server->fd = -1;
|
|
}
|
|
if (server->evt_fd != -1) {
|
|
close(server->evt_fd);
|
|
server->evt_fd = -1;
|
|
}
|
|
}
|
|
|
|
static void stop_server(ds_server_t *server)
|
|
{
|
|
{
|
|
int64_t pad = 1;
|
|
write(server->evt_fd, &pad, sizeof(pad));
|
|
}
|
|
}
|
|
|
|
int socket_server_start_unix(const char *socket_path)
|
|
{
|
|
int fd;
|
|
int evt_fd;
|
|
|
|
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
|
|
ds_err("open socket fail");
|
|
return -1;
|
|
}
|
|
|
|
struct sockaddr_un s_un;
|
|
int size;
|
|
memset(&s_un, 0, sizeof(s_un));
|
|
s_un.sun_family = AF_UNIX;
|
|
strncpy(s_un.sun_path, socket_path, sizeof(s_un.sun_path) - 1);
|
|
size = offsetof(struct sockaddr_un, sun_path) + strlen(s_un.sun_path);
|
|
unlink(socket_path);
|
|
|
|
if (bind(fd, (struct sockaddr *)&s_un, size) < 0) {
|
|
ds_err("bind error, err(%d:%s)", errno, strerror(errno));
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
|
|
ds_inf("socket ready.");
|
|
|
|
if (listen(fd, 20) < 0) {
|
|
ds_err("listen error, err(%d:%s)", errno, strerror(errno));
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
|
|
evt_fd = eventfd(0, 0);
|
|
|
|
server.init = init_server;
|
|
server.deinit = deinit_server;
|
|
server.stop = stop_server;
|
|
|
|
int ret = ds_server_start(&server, (void*)(long)fd, (void*)(long)evt_fd, server_task);
|
|
|
|
if (ret != 0) {
|
|
close(evt_fd);
|
|
close(fd);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int socket_server_stop_unix(void)
|
|
{
|
|
ds_inf("unix server closing...");
|
|
ds_server_stop(&server);
|
|
ds_inf("unix server closed.");
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef DS_SUPPORT_IP
|
|
|
|
#include <netinet/in.h>
|
|
|
|
static ds_server_t ip_server;
|
|
|
|
int socket_server_start_ip(int socket_port)
|
|
{
|
|
/*init the server inst*/
|
|
INIT_LIST_HEAD(&ip_server.conns);
|
|
|
|
ip_server.fd = -1;
|
|
ip_server.running = 0;
|
|
|
|
if ((ip_server.fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
|
ds_err("open socket fail");
|
|
return -1;
|
|
}
|
|
|
|
int opt = 1;
|
|
if (setsockopt(ip_server.fd, SOL_SOCKET,
|
|
SO_REUSEADDR | SO_REUSEPORT,
|
|
&opt, sizeof(opt))) {
|
|
ds_err("setsockopt fail");
|
|
close(ip_server.fd);
|
|
return -1;
|
|
}
|
|
|
|
struct sockaddr_in s_in;
|
|
memset(&s_in, 0, sizeof(s_in));
|
|
s_in.sin_family = AF_INET;
|
|
s_in.sin_addr.s_addr = INADDR_ANY;
|
|
s_in.sin_port = htons(socket_port);
|
|
|
|
if (bind(ip_server.fd, (struct sockaddr *)&s_in, sizeof(s_in)) < 0) {
|
|
ds_err("bind fail");
|
|
close(ip_server.fd);
|
|
return -1;
|
|
}
|
|
|
|
ds_inf("socket ready.");
|
|
|
|
if (listen(ip_server.fd, 20) < 0) {
|
|
ds_err("listen fail");
|
|
close(ip_server.fd);
|
|
return -1;
|
|
}
|
|
|
|
ip_server.running = 1;
|
|
int ret = pthread_create(&ip_server.thread, NULL, server_task, &ip_server);
|
|
|
|
if (ret != 0)
|
|
close(ip_server.fd);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int socket_server_stop_ip(void)
|
|
{
|
|
ip_server.running = 0;
|
|
close(ip_server.fd);
|
|
|
|
ds_inf("ip server closing...");
|
|
|
|
pthread_join(ip_server.thread, NULL);
|
|
|
|
ds_inf("ip server closed.");
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|