#include <dbus/dbus.h>
#include <iostream>
#include <unistd.h>
#include <sys/select.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/fcntl.h>
#include <assert.h>
using namespace std;
/**
* A watch bind with a fd(owned by the socket),
* when fd is ready to read data or write from transport, a notify event occurs
*/
struct watchlist_t {
DBusWatch *watch;
struct watchlist_t *next;
};
static struct watchlist_t *watchlist = NULL;
struct timeoutlist_t{
DBusTimeout *timeout;
struct timeoutlist_t *next;
};
static struct timeoutlist_t *timeoutlist = NULL;
const char *objectPaths[] = {
"/com/redflag",
"/test/signal/server" /*//org/freedesktop/csy",*/
};
/* Object handlers and object path handlers */
DBusHandlerResult subsection_com_redflag_handler(DBusConnection*, DBusMessage*, void*);
DBusHandlerResult object_dbus_handler(DBusConnection*, DBusMessage*, void*);
void object_unregister_handler(DBusConnection*, void*);
int wait_socket(int port);
DBusObjectPathVTable objectPathVTable[] =
{
{
.unregister_function = NULL,
.message_function = subsection_com_redflag_handler
},
{
.unregister_function = NULL,
.message_function = object_dbus_handler
}
};
struct seriallist_t {
dbus_uint32_t serial;
struct seriallist_t *next;
};
static seriallist_t *seriallist = NULL;
// debug facilities
void err_quit(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
fprintf(stderr, fmt, args);
va_end(args);
exit(1);
}
void set_nonblock(int socket) {
int flags;
flags = fcntl(socket,F_GETFL,0);
assert(flags != -1);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}
char* _verbose_watch(DBusWatch *watch)
{
const char *s_flags[] = { "readable", "writeable"};
static char p[1024] = "", ret[1024] = "";
if (dbus_watch_get_flags(watch) & DBUS_WATCH_READABLE)
{
strncpy(p, s_flags[0], strlen(s_flags[0]));
}
else if (dbus_watch_get_flags(watch) & DBUS_WATCH_WRITABLE)
{
if (p[0])
{
strncat(p, "&", strlen("&"));
}
strncat(p, s_flags[1], strlen(s_flags[1]));
}
int on=1;
int fd = dbus_watch_get_socket(watch);
set_nonblock(fd);
sprintf(ret, ":fd is %d, %s", fd, p);
return ret;
}
char *_verbose_message(DBusMessage *msg) {
static char s_msg[1024] = "", ret[1024] = "";
int bc = sprintf(s_msg, "\ttype: %s\n\tpath: %s\n\tmember: %s\n\t",
dbus_message_type_to_string(dbus_message_get_type(msg)),
dbus_message_get_path(msg),
dbus_message_get_member(msg));
strncpy(ret, s_msg, bc + 1);
if (dbus_message_get_serial(msg))
{
bc = sprintf(s_msg, "serial: %ud\n\t", dbus_message_get_reply_serial(msg));
strncat(ret, s_msg, bc + 1);
}
DBusMessageIter args, subargs;
char *s;
int i;
dbus_message_iter_init(msg, &args);
bc = sprintf(s_msg, "args: ");
strncat(ret, s_msg, bc + 1);
while (DBUS_TYPE_INVALID != dbus_message_iter_get_arg_type(&args))
{
switch (dbus_message_iter_get_arg_type(&args))
{
case DBUS_TYPE_STRING:
{
dbus_message_iter_get_basic(&args, &s);
bc = sprintf(s_msg, " %s", s);
strncat(ret, s_msg, bc + 1);
}
break;
case DBUS_TYPE_INT32:
{
dbus_message_iter_get_basic(&args, &i);
bc = sprintf(s_msg, " %d", i);
strncat(ret, s_msg, bc + 1);
}
break;
case DBUS_TYPE_ARRAY:
{
dbus_message_iter_recurse(&args, &subargs);
strcat(ret, " [ ");
while (dbus_message_iter_get_arg_type(&subargs) != DBUS_TYPE_INVALID)
{
switch (dbus_message_iter_get_arg_type(&subargs))
{
case DBUS_TYPE_STRING:
{
dbus_message_iter_get_basic(&subargs, &s);
bc = sprintf(s_msg, " %s", s);
strncat(ret, s_msg, bc + 1);
}
break;
case DBUS_TYPE_INT32:
{
dbus_message_iter_get_basic(&subargs, &i);
bc = sprintf(s_msg, " %d", i);
strncat(ret, s_msg, bc + 1);
}
break;
default:
break;
}
dbus_message_iter_next(&subargs);
}
strcat(ret, " ] ");
}
break;
default:
break;
}
dbus_message_iter_next(&args);
}
return ret;
}
char * _verbose_timeout(DBusTimeout *timeout)
{
static char ret[1024] = "";
sprintf(ret, "timeout: %d\n", dbus_timeout_get_interval(timeout));
return ret;
}
DBusHandlerResult handle_method_return(DBusConnection *conn, DBusMessage *reply)
{
struct seriallist_t *sl = seriallist;
while (sl != NULL)
{
if (sl->serial == dbus_message_get_reply_serial(reply))
{
printf("reply_msg:\t%s\n", _verbose_message(reply));
return DBUS_HANDLER_RESULT_HANDLED;
}
sl = sl->next;
}
return DBUS_HANDLER_RESULT_HANDLED;
}
int reply_to_method_call(DBusMessage *msg, DBusConnection *conn)
{
DBusMessage *reply;
DBusMessageIter args;
DBusError err;
if (!dbus_message_iter_init(msg, &args))
{
err_quit("arg init error.\n");
}
dbus_int32_t id;
char *content;
dbus_error_init(&err);
dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &id,
DBUS_TYPE_STRING, &content, DBUS_TYPE_INVALID);
if (dbus_error_is_set(&err))
{
err_quit("get arg error.\n");
}
reply = dbus_message_new_method_return(msg);
if (NULL == reply)
{
err_quit("Memory is not enough.\n");
}
printf("received call args: %d: %s\n", id, content);
const char *comment = "reply to method call from com.redflag.csy.";
dbus_message_iter_init_append(reply, &args);
dbus_message_append_args( reply,
DBUS_TYPE_STRING, &comment, DBUS_TYPE_INVALID);
dbus_uint32_t serial;
dbus_connection_send(conn, reply, &serial);
dbus_connection_flush(conn);
printf("build reply msg and send: \n%s\n", _verbose_message(reply));
dbus_message_unref(reply);
return 0;
}
dbus_bool_t watchAddNotify(DBusWatch *watch, void *data)
{
struct watchlist_t *wl;
for (wl = watchlist; wl != NULL; wl = wl->next)
{
if (wl->watch == watch)
{
return TRUE;
}
}
printf("watchAdd: %s\n", _verbose_watch(watch));
wl = dbus_new(struct watchlist_t, 1);
if (NULL == wl)
return FALSE;
wl->watch = watch;
wl->next = watchlist;
watchlist = wl;
return TRUE;
}
void watchRemoveNotify(DBusWatch *watch, void *data)
{
struct watchlist_t *wl, *pre;
for (pre = wl = watchlist; wl != NULL; pre = wl, wl = wl->next)
{
if (wl->watch == watch)
{
printf("watchRemove: %d\n", dbus_watch_get_socket(watch));
if (wl == watchlist)
{
watchlist = wl->next;
dbus_free(wl);
}
else{
pre->next = wl->next;
dbus_free(wl);
}
break;
}
}
}
void watchToggleNotify(DBusWatch *watch, void *data)
{
if (watch == NULL)
{
err_quit("line %d: watch shold not be null.", __LINE__);
}
printf("toggleNotify: watch %d toggled %s",
dbus_watch_get_socket(watch),
dbus_watch_get_enabled(watch) ? "enable":"disabled");
}
dbus_bool_t watchHandler(int sockfd) {
struct watchlist_t *wl;
fd_set rfds, wfds, efds;
int maxid = -1, fd;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_ZERO(&efds);
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
char buffer[256];
// prepare all readble and writeable fds
for (wl = watchlist; wl != NULL; wl = wl->next)
{
if (!dbus_watch_get_enabled(wl->watch))
{
continue;
}
fd = dbus_watch_get_socket(wl->watch);
if (fd & DBUS_WATCH_READABLE)
{
FD_SET(fd, &rfds);
maxid = (maxid < fd ? fd : maxid);
}
/* if (fd & DBUS_WATCH_WRITABLE)
{
FD_SET(fd, &wfds);
maxid = (maxid < fd ? fd : maxid);
}
if (fd & DBUS_WATCH_ERROR)
{
FD_SET(fd, &efds);
maxid = (maxid < fd ? fd : maxid);
}*/
}
FD_SET(sockfd, &rfds);
maxid = (maxid < sockfd ? sockfd : maxid);
cout<<"before select"<<endl;
//int ret = select(maxid + 1, &rfds, &wfds, &efds, NULL);
int ret = select(maxid + 1, &rfds, NULL, NULL, &timeout);
cout<<"select get ret is "<<ret<<endl;
if (ret <= 0)
return FALSE;
if (FD_ISSET(sockfd, &rfds))
{
cout<<"sockfd get data, OK"<<endl;
int newSocketFd = accept(sockfd, NULL, NULL);
if (newSocketFd >= 0)
{
cout<<"new socket fd is "<<newSocketFd<<endl;
memset(buffer, 0, sizeof(buffer));
int rc = recv(newSocketFd, buffer, sizeof(buffer), 0);
if (rc >= 0)
{
int len = rc;
cout<<rc<<" bytes received, data is: "<< buffer;
rc = send(newSocketFd, buffer, len, 0);
}
}
}
//call dbus_watch_handler is a must, it uses internal predefined watch handler to do some thing
for (wl = watchlist; wl != NULL; wl = wl->next)
{
fd = dbus_watch_get_socket(wl->watch);
if (FD_ISSET(fd, &rfds))
{
printf("read fd is %d, ret is %d\n", fd, ret);
dbus_watch_handle(wl->watch, DBUS_WATCH_READABLE);
}
if (FD_ISSET(fd, &wfds))
{
printf("write fd is %d, ret is %d\n", fd, ret);
dbus_watch_handle(wl->watch, DBUS_WATCH_WRITABLE);
}
if (FD_ISSET(fd, &efds))
{
printf("error fd is %d, ret is %d\n", fd, ret);
dbus_watch_handle(wl->watch, DBUS_WATCH_ERROR);
}
}
return TRUE;
}
dbus_bool_t timeoutAddNotify(DBusTimeout *timeout, void *data)
{
struct timeoutlist_t *tl;
for (tl = timeoutlist; tl != NULL; tl = tl->next)
{
if (tl->timeout == timeout)
return TRUE;
}
tl = dbus_new(struct timeoutlist_t, 1);
if (NULL == tl)
return FALSE;
tl->timeout = timeout;
fprintf(stdout, "timeoutAdd: %s\n", _verbose_timeout(timeout));
tl->next = timeoutlist;
timeoutlist = tl;
return TRUE;
}
void timeoutRemoveNotify(DBusTimeout *timeout, void *data)
{
struct timeoutlist_t *pre = NULL, *tl = timeoutlist;
while (tl != NULL)
{
if (tl->timeout == timeout)
{
if (pre == NULL)
timeoutlist = tl->next;
else
pre->next = tl->next;
fprintf(stdout, "timeoutRemove:%s\n", _verbose_timeout(timeout));
break;
}
pre = tl;
tl = tl->next;
}
}
void timeoutToggleNotify(DBusTimeout *timeout, void *data)
{
fprintf(stdout, "timeoutToggle: %s\n", _verbose_timeout(timeout));
}
/**
* in this function, we vall dbus_timeout_handle to handle all timeout events,
* it will call internal predefined handler to process
*/
void timeoutHandle()
{
struct timeoutlist_t *tl = timeoutlist;
for (; tl != NULL; tl = tl->next)
{
if (dbus_timeout_get_enabled(tl->timeout))
{
printf("timeoutHandle: %s\n", _verbose_timeout(tl->timeout));
dbus_timeout_handle(tl->timeout);
}
}
}
DBusHandlerResult msgFilter(DBusConnection *conn, DBusMessage *msg, void* data)
{
printf("incomming msg: %s\n", _verbose_message(msg));
switch (dbus_message_get_type(msg))
{
case DBUS_MESSAGE_TYPE_METHOD_CALL:
{
cout<<"msg Filter method "<<__LINE__<<endl;
if (!strcmp(dbus_message_get_member(msg), "ignore"))
{
DBusMessage *errMsg;
errMsg = dbus_message_new_error(msg,
"com.redflag.csy.IgnoreService",
"this demonstrate the filter.");
dbus_connection_send(conn, errMsg, NULL);
cout<<"method call "<<endl;
return DBUS_HANDLER_RESULT_HANDLED;
}
else{
break;
}
}
case DBUS_MESSAGE_TYPE_METHOD_RETURN:
// never reach here.
break;
case DBUS_MESSAGE_TYPE_SIGNAL:
cout<<"msgFilter signal "<<__LINE__<<endl;
break;
case DBUS_MESSAGE_TYPE_ERROR:
break;
default:
break;
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
DBusHandlerResult subsection_com_redflag_handler(DBusConnection* conn, DBusMessage* msg, void* data)
{
if ( strncmp(dbus_message_get_path(msg), objectPaths[0], strlen(objectPaths[0])) != 0 )
{
printf("subsection_com_redflag_handler: something wrong.\n");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
if ( strncmp(dbus_message_get_member(msg), "pseudo", 6) == 0 )
{
reply_to_method_call(msg, conn);
printf("subsection_com_redflag_handler: handled.\n");
return DBUS_HANDLER_RESULT_HANDLED;
}
else
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
DBusHandlerResult object_dbus_handler(DBusConnection* conn,
DBusMessage* msg, void* data)
{
if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_RETURN)
{
printf("object_dbus_handler: method_return.\n");
DBusHandlerResult ret = handle_method_return( conn, msg );
printf("object_dbus_handler: handled.\n");
return ret;
}
fprintf(stdout, "object_dbus_handler: cannot handle.\n");
fprintf(stdout, "\t%s\n", _verbose_message(msg));
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
void object_unregister_handler(DBusConnection* conn, void* data)
{
printf("object_unregister_handler:\n");
}
// send dbus signal to other dbus program
void send_random_signal(DBusConnection *conn)
{
//DBusMessage *msg;
}
void pendingCallNotify(DBusPendingCall *pending, void *data)
{
DBusMessage *msg = dbus_pending_call_steal_reply(pending);
printf("pendingCallNotify: %s\n", _verbose_message(msg));
}
//call other dbus program method and get reply
void send_random_method_expecting_reply(DBusConnection *conn)
{
//DBusMessage *msg;
}
int dbus_process_msg_loop(int sockfd)
{
DBusConnection *conn;
DBusError *perr;
//1. connect to dbus
perr = dbus_new(DBusError, 1);
dbus_error_init(perr);
conn = dbus_bus_get(DBUS_BUS_SESSION, perr);
if (dbus_error_is_set(perr))
{
err_quit("connection failed.\n");
}
//2. request dbus name
int ret = dbus_bus_request_name(conn, "test.signal.server",
DBUS_NAME_FLAG_REPLACE_EXISTING, perr);
// ret = dbus_bus_request_name(conn, "test.signal.method",
// DBUS_NAME_FLAG_REPLACE_EXISTING, perr);
if (dbus_error_is_set(perr))
{
err_quit("request name failed\n");
}
if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret)
{
err_quit("not primary owner\n");
}
//3. register some handler
//dbus_bus_add_match(conn,
// "type='method_call',path='/org/freedesktop/csy'"
// ",interface='com.redflag.sycao',member='faked'", perr);
dbus_bus_add_match(conn, "type='signal'",perr);
if (dbus_error_is_set(perr))
{
printf("%s\n", perr->message);
err_quit("add match failed\n");
}
//dbus_connection_add_filter(conn, msgFilter, NULL, NULL);
dbus_connection_set_watch_functions(conn,
watchAddNotify,
watchRemoveNotify,
watchToggleNotify,
NULL, NULL);
dbus_connection_set_timeout_functions(conn,
timeoutAddNotify,
timeoutRemoveNotify,
timeoutToggleNotify,
NULL, NULL);
printf("main: registered path\n");
uint i;
for (i = 0; i < sizeof(objectPaths) / sizeof(objectPaths[0]); i++)
{
if (i < 1)
{
//dbus_connection_register_fallback(conn,
// objectPaths[i],
// &objectPathVTable[i], NULL);
// dbus_connection_register_object_path(conn2,
// objectPaths[i],
// &objectPathVTable[i], NULL);
}
else
{
dbus_connection_register_object_path(conn,
objectPaths[i],
&objectPathVTable[i], NULL);
}
}
printf("main: registered %d objectHandlers.\n", i);
//4. main loop: wait and process incoming msgs
// there are several steps :
// a. check if any watch is ready for read (incoming data prepared)
// or write (outgoing data prepared), and process it.
// b. check if any timeout occurred ( i know now method_call that
// needs a reply will set a timeout ), and process it.
// c. call dispatch will do:
// i. parse incoming raw data if has.
// ii. process any pending call ( bind with a reply message );
// ii. call any filter registered.
// iv. call any object path handler registered.
// ps: a single dispatch call processes at most one message.
int isockfd = wait_socket(5125);
while (true)
{
DBusDispatchStatus status;
watchHandler(isockfd);
timeoutHandle();
status = dbus_connection_dispatch(conn);
switch (status)
{
case DBUS_DISPATCH_DATA_REMAINS:
printf("DBUS_DISPATCH_DATA_REMAINS\n");
continue;
case DBUS_DISPATCH_COMPLETE:
break;
case DBUS_DISPATCH_NEED_MEMORY:
break;
default:
break;
}
send_random_signal(conn);
send_random_method_expecting_reply(conn);
sleep(2);
}
return 0;
}
int wait_socket(int port)
{
int sockfd, portno;
struct sockaddr_in serv_addr;
sockfd = socket(AF_INET, SOCK_STREAM|O_NONBLOCK, 0);
if (sockfd < 0)
{
printf("ERROR opening socket\n");
return -1;
}
cout<<"create socket\n";
int reuse = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))<0)
{
printf("error in set sockopt\n");
return -1;
}
int on = 1;
// set socket to be nonblocking
int rc = ioctl(sockfd, FIONBIO, (char*)&on);
if (rc < 0)
{
perror("ioctl");
close(sockfd);
exit(EXIT_FAILURE);
}
//initialize serv_addr to zeros
bzero((char*)&serv_addr, sizeof(serv_addr));
portno = port;//*(int *)arg;//atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(portno);
serv_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("Error on binding\n");
return -1;
}
cout<<"bind socket\n";
listen(sockfd, 5);
cout<<"listen socket\n";
return sockfd;
}
int main(int argc, char* argv[])
{
int sockfd = 0;
cout<<"sockfd is "<<sockfd<<endl;
dbus_process_msg_loop(sockfd);
return 0;
}
一个select同时监听socket和dbus。
g++ -o myserver main.cpp -ldbus-1
来源:CSDN
作者:gdizcm
链接:https://blog.csdn.net/gdizcm/article/details/90737089