Skip to content

Instantly share code, notes, and snippets.

@suxue
Created March 11, 2014 05:06
Show Gist options
  • Save suxue/9479795 to your computer and use it in GitHub Desktop.
Save suxue/9479795 to your computer and use it in GitHub Desktop.
simple rpc over tcp, for vm integrating?
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <ctype.h>
#include <netdb.h>
#include "config.h"
#include "socket.h"
#define SA struct sockaddr
static char * message = "left_desktop";
void
err_quit(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
exit(1);
}
int
main(int argc, char **argv)
{
if (argc < 2) {
fprintf(stderr, "need at least 1 option\n");
return 1;
}
if (argv[1][0] != '-' || argv[1][1] == 0) {
fprintf(stderr, "mailformed option\n");
return 1;
}
switch (argv[1][1]) {
case 'u':
message = "up_desktop"; break;
case 'd':
message = "down_desktop"; break;
case 'r':
message = "right_desktop"; break;
case 'l':
message = "left_desktop"; break;
case 'n':
message = "next_vt"; break;
case 'p':
message = "previous_vt"; break;
case 'g':
message = "show_desktop_grid"; break;
case 'U':
message = "volume_up"; break;
case 'D':
message = "volume_down"; break;
case '+':
message = "inc_brightness"; break;
case '-':
message = "dec_brightness"; break;
case '<':
message = "previous_track"; break;
case '>':
message = "next_track"; break;
case '/':
message = "play_pause"; break;
case 'M':
message = "volume_toggle"; break;
case 't':
message = "switch_window"; break;
default:
fprintf(stderr, "option -%c no recognized\n", argv[1][1]);
return 1;
}
int sockfd;
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
err_quit("socket error");
servaddr.sin_family = AF_INET;
/* setup port number */
servaddr.sin_port = (argc > 3) ? htons(atol(argv[3]))
: htons(DEFAULT_PORT);
const char *host;
do {
if (argc > 2) {
if (isdigit(argv[2][0])) {
host = argv[2];
} else {
struct hostent *info = gethostbyname(argv[2]);
if (!info) {
err_quit("%s\n", hstrerror(h_errno));
}
memmove(&servaddr.sin_addr, info->h_addr_list[0], 4);
break;
}
} else {
host = DEFAULT_HOST;
}
if (inet_pton(AF_INET, host, &servaddr.sin_addr) <= 0)
err_quit("inet_pton error for %s\n", host);
} while (0);
if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0)
err_quit("connect error\n");
uint16_t len = strlen(message);
uint16_t netlen = htons(len);
if (!write_socket(sockfd, &netlen, sizeof(netlen))) {
if (!write_socket(sockfd, message, len)) {
return 0;
} else {
return 1;
}
}
return 1;
}
#ifndef CONFIG_H_
#define CONFIG_H_
#define DEFAULT_HOST "127.0.0.1"
#define DEFAULT_PORT 7777
#endif
!^Left::Run U:\\AutoHotKey\client.exe -l lfs7, , Hide
!^Up::Run U:\\AutoHotKey\client.exe -u lfs7, , Hide
!^Right::Run U:\\AutoHotKey\client.exe -r lfs7, , Hide
!^Down::Run U:\\AutoHotKey\client.exe -d lfs7, , Hide
!^,::Run U:\\AutoHotKey\client.exe -< lfs7, , Hide
!^.::Run U:\\AutoHotKey\client.exe -> lfs7, , Hide
!^/::Run U:\\AutoHotKey\client.exe -/ lfs7, , Hide
LWin & E::Run U:\\AutoHotKey\client.exe -g lfs7, , Hide
LWin & F11::Run U:\\AutoHotKey\client.exe -D lfs7, , Hide
LWin & F12::Run U:\\AutoHotKey\client.exe -U lfs7, , Hide
LWin & ScrollLock::Run U:\\AutoHotKey\client.exe -M lfs7, , Hide
LWin & Left::Run U:\\AutoHotKey\client.exe -p lfs7, , Hide
LWin & Right::Run U:\\AutoHotKey\client.exe -n lfs7, , Hide
LWin & F7::Run U:\\AutoHotKey\client.exe -- lfs7, , Hide
LWin & F8::Run U:\\AutoHotKey\client.exe -+ lfs7, , Hide
LWin & Tab::Run U:\\AutoHotKey\client.exe -t lfs7, , Hide
~LWin Up:: return
CC=clang -std=c99
CFLAGS=-D_GNU_SOURCE -Wall -g -O2
CXX=clang++ -std=c++03
CXXFLAGS=-Wall -g -O2 `pkg-config --cflags QtDBus`
LDFLAGS=`pkg-config --libs QtDBus`
all: server client
install: server
install -m755 server $(HOME)/.kde/Autostart/
server: server.o server_slave.o msg.o socket.o
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $^
client: client.o socket.o
$(CC) $(CFLAGS) -o $@ $^
client.o: client.c socket.h config.h
$(CC) $(CFLAGS) -c $<
server.o: server.c config.h
$(CC) $(CFLAGS) -c $<
server_slave.o: server_slave.cc msg.h socket.h
$(CXX) $(CXXFLAGS) -c $<
socket.o: socket.c socket.h
$(CC) $(CFLAGS) -c $<
msg.o: msg.c msg.h
$(CC) $(CFLAGS) -c $<
msg.c: msg.gperf
gperf $< --output-file=$@
clean:
rm -f server client msg.c *.o
/* ANSI-C code produced by gperf version 3.0.4 */
/* Command-line: gperf --output-file=msg.c msg.gperf */
/* Computed positions: -k'1' */
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
&& (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
&& ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
&& ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
&& ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
&& ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
&& ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
&& ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
&& ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
&& ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
&& ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
&& ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
&& ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
&& ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
&& ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
&& ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
&& ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
&& ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
&& ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
&& ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
&& ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
&& ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
/* The character set is not based on ISO-646. */
#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
#endif
#line 8 "msg.gperf"
#include <string.h>
#include "msg.h"
#line 13 "msg.gperf"
struct Message { const char *name; enum Operation op; };
/* maximum key range = 18, duplicates = 0 */
#ifdef __GNUC__
__inline
#else
#ifdef __cplusplus
inline
#endif
#endif
static unsigned int
is_message_hash (register const char *str, register unsigned int len)
{
static unsigned char asso_values[] =
{
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
0, 25, 25, 25, 25, 10, 25, 25, 5, 25,
0, 25, 5, 25, 10, 5, 25, 10, 0, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25
};
return len + asso_values[(unsigned char)str[0]];
}
#ifdef __GNUC__
__inline
#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
__attribute__ ((__gnu_inline__))
#endif
#endif
struct Message *
is_message (register const char *str, register unsigned int len)
{
enum
{
TOTAL_KEYWORDS = 16,
MIN_WORD_LENGTH = 7,
MAX_WORD_LENGTH = 17,
MIN_HASH_VALUE = 7,
MAX_HASH_VALUE = 24
};
static struct Message wordlist[] =
{
#line 24 "msg.gperf"
{"next_vt", Next_Vt},
#line 19 "msg.gperf"
{"volume_up", Volume_Up},
#line 27 "msg.gperf"
{"next_track", Next_Track},
#line 20 "msg.gperf"
{"volume_down", Volume_Down},
#line 17 "msg.gperf"
{"down_desktop", Down_Desktop},
#line 21 "msg.gperf"
{"volume_toggle", Volume_Toggle},
#line 26 "msg.gperf"
{"dec_brightness", Dec_Brightness},
#line 29 "msg.gperf"
{"play_pause", Play_Pause},
#line 23 "msg.gperf"
{"previous_vt", Previous_Vt},
#line 15 "msg.gperf"
{"left_desktop", Left_Desktop},
#line 30 "msg.gperf"
{"switch_window", Switch_Window},
#line 28 "msg.gperf"
{"previous_track", Prev_Track},
#line 16 "msg.gperf"
{"up_desktop", Up_Desktop},
#line 22 "msg.gperf"
{"show_desktop_grid", Show_Desktop_Grid},
#line 18 "msg.gperf"
{"right_desktop", Right_Desktop},
#line 25 "msg.gperf"
{"inc_brightness", Inc_Brightness}
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
{
register int key = is_message_hash (str, len);
if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)
{
register struct Message *resword;
switch (key - 7)
{
case 0:
resword = &wordlist[0];
goto compare;
case 2:
resword = &wordlist[1];
goto compare;
case 3:
resword = &wordlist[2];
goto compare;
case 4:
resword = &wordlist[3];
goto compare;
case 5:
resword = &wordlist[4];
goto compare;
case 6:
resword = &wordlist[5];
goto compare;
case 7:
resword = &wordlist[6];
goto compare;
case 8:
resword = &wordlist[7];
goto compare;
case 9:
resword = &wordlist[8];
goto compare;
case 10:
resword = &wordlist[9];
goto compare;
case 11:
resword = &wordlist[10];
goto compare;
case 12:
resword = &wordlist[11];
goto compare;
case 13:
resword = &wordlist[12];
goto compare;
case 15:
resword = &wordlist[13];
goto compare;
case 16:
resword = &wordlist[14];
goto compare;
case 17:
resword = &wordlist[15];
goto compare;
}
return 0;
compare:
{
register const char *s = resword->name;
if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
return resword;
}
}
}
return 0;
}
%language=ANSI-C
%enum
%struct-type
%switch=1
%compare-strncmp
%define hash-function-name is_message_hash
%define lookup-function-name is_message
%{
#include <string.h>
#include "msg.h"
%}
struct Message { const char *name; enum Operation op; }
%%
left_desktop, Left_Desktop
up_desktop, Up_Desktop
down_desktop, Down_Desktop
right_desktop, Right_Desktop
volume_up, Volume_Up
volume_down, Volume_Down
volume_toggle, Volume_Toggle
show_desktop_grid, Show_Desktop_Grid
previous_vt, Previous_Vt
next_vt, Next_Vt
inc_brightness, Inc_Brightness
dec_brightness, Dec_Brightness
next_track, Next_Track
previous_track, Prev_Track
play_pause, Play_Pause
switch_window, Switch_Window
#ifndef MSG_H_
#define MSG_H_
enum Operation {
Left_Desktop,
Right_Desktop,
Down_Desktop,
Up_Desktop,
Volume_Up,
Volume_Down,
Volume_Toggle,
Show_Desktop_Grid,
Previous_Vt,
Next_Vt,
Inc_Brightness,
Dec_Brightness,
Next_Track,
Prev_Track,
Play_Pause,
Switch_Window,
};
#endif
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include "config.h"
#include "msg.h"
#define LISTENQ 1024
#define SA struct sockaddr
#define BUF_SIZE 1024
extern int slave(int fd);
int
main(int argc, char *argv[])
{
int listenfd, connfd;
pid_t childpid;
socklen_t chilen;
struct sockaddr_in cliaddr, servaddr;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = (argc > 1) ? htons(atoi(argv[1]))
: htons(DEFAULT_PORT);
bind(listenfd, (SA*) &servaddr, sizeof(servaddr));
listen(listenfd, LISTENQ);
signal(SIGCHLD, SIG_IGN); /* I'm not interested in the return code
of children */
/* basic iterative server */
for (; ;) {
chilen = sizeof(cliaddr);
connfd = accept(listenfd, (SA*) &cliaddr, &chilen);
if ((childpid = fork()) == 0) {
close(listenfd);
return slave(connfd);
}
close(connfd);
}
}
extern "C" {
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <stdio.h>
#include "msg.h"
#include "socket.h"
struct Message { const char *name; enum Operation op; };
struct Message * is_message(register const unsigned char *str,
register unsigned int len);
}
#include <QtDBus/QDBusConnection>
#include <QtDBus/QDBusMessage>
#include <QtCore/QList>
#include <QtCore/QVariant>
#define MSG_BUFFER_SIZE 128
static unsigned char msgbuf[MSG_BUFFER_SIZE];
void error(const char *err)
{
fprintf(stderr, "%u: %s\n", getpid(), err);
}
int move_desktop(int dir); /* 0 -> horizontal, 1->vertical */
int adjust_volume(int dir); /* @dir: 1-> up, 0->down */
int toggle_volume(void);
int show_desktop_grid(void);
int previous_vt(void);
int next_vt(void);
int dec_brightness(void);
int inc_brightness(void);
int next_track(void);
int prev_track(void);
int play_pause(void);
int switch_window(void);
int process_message(enum Operation op)
{
switch (op) {
case Left_Desktop:
case Right_Desktop:
return move_desktop(0);
case Up_Desktop:
case Down_Desktop:
return move_desktop(1);
break;
case Volume_Up:
return adjust_volume(1);
case Volume_Down:
return adjust_volume(0);
case Volume_Toggle:
return toggle_volume();
case Show_Desktop_Grid:
return show_desktop_grid();
case Previous_Vt:
return previous_vt();
case Next_Vt:
return next_vt();
case Inc_Brightness:
return inc_brightness();
case Dec_Brightness:
return dec_brightness();
case Next_Track:
return next_track();
case Prev_Track:
return prev_track();
case Play_Pause:
return play_pause();
case Switch_Window:
return switch_window();
default:
return 1;
}
}
void myMessageOutput(QtMsgType type, const char *msg)
{
// stub
}
extern "C" int slave(int fd)
{
// disable the annoying qt warning
// "QDBusConnection: session D-Bus connection created before
// QCoreApplication. Application may misbehave."
// see http://qt-project.org/doc/qt-4.8/qtglobal.html#qInstallMsgHandler
qInstallMsgHandler(myMessageOutput);
int rc;
uint16_t msg_len;
struct Message *msg;
rc = read_socket(fd, &msg_len, sizeof(msg_len));
if (rc != 0) {
error("read message length from header");
return rc;
}
msg_len = ntohs(msg_len);
if (msg_len > MSG_BUFFER_SIZE) {
error("invalid message, length overflow");
return 1;
}
rc = read_socket(fd, msgbuf, msg_len);
if (rc != 0) {
error("cannot retrieve message body");
return rc;
}
msg = is_message(msgbuf, msg_len);
if (!msg) {
error("invalid message");
return 1;
} else {
process_message(msg->op);
return 0;
}
}
int
move_desktop(int dir)
{
int old_desktop, new_desktop;
QDBusMessage m = QDBusMessage::createMethodCall("org.kde.kwin",
"/KWin",
"",
"currentDesktop");
QDBusMessage response = QDBusConnection::sessionBus().call(m);
if (response.type() == QDBusMessage::ReplyMessage) {
QList<QVariant> reply = response.arguments();
old_desktop = reply.at(0).toInt();
} else {
return 1;
}
switch (old_desktop) {
case 1: new_desktop = dir ? 3 : 2; break;
case 2: new_desktop = dir ? 4 : 1; break;
case 3: new_desktop = dir ? 1 : 4; break;
case 4: new_desktop = dir ? 2 : 3; break;
default: new_desktop = 1; break;
}
m = QDBusMessage::createMethodCall("org.kde.kwin",
"/KWin",
"",
"setCurrentDesktop");
m << new_desktop;
bool rc = QDBusConnection::sessionBus().send(m);
return !rc;
}
int
adjust_volume(int dir) /* @dir: 1-> up, 0->down */
{
char command[] = "amixer -Dhw set Master 5%-";
size_t len = strlen(command);
if (dir) {
command[len - 1] = '+';
}
return system(command);
}
int
toggle_volume(void)
{
return system("amixer -Dhw set Master toggle");
}
int
show_desktop_grid(void)
{
// check `qdbus org.kde.kglobalaccel /component/kwin org.kde.kglobalaccel.Component.shortcutNames`
QDBusMessage m = QDBusMessage::createMethodCall("org.kde.kglobalaccel",
"/component/kwin",
"",
"invokeShortcut");
QList<QVariant> arglist;
arglist.append(QString::fromLocal8Bit("ShowDesktopGrid"));
m.setArguments(arglist);
return ! QDBusConnection::sessionBus().send(m);
}
int
previous_vt(void)
{
return system("previous_vt");
}
int
next_vt(void)
{
return system("next_vt");
}
int
dec_brightness(void)
{
return system("xbacklight -dec 5 -steps 77");
}
int
inc_brightness(void)
{
return system("xbacklight -inc 5 -steps 77");
}
int
next_track(void)
{
//QDBusMessage m = QDBusMessage::createMethodCall("org.kde.amarok",
//"/org/mpris/MediaPlayer2",
//"",
//"Next");
//return ! QDBusConnection::sessionBus().send(m);
return system("mpc next");
}
int
prev_track(void)
{
//QDBusMessage m = QDBusMessage::createMethodCall("org.kde.amarok",
//"/org/mpris/MediaPlayer2",
//"",
//"Previous");
//return ! QDBusConnection::sessionBus().send(m);
return system("mpc prev");
}
int
play_pause(void)
{
//QDBusMessage m = QDBusMessage::createMethodCall("org.kde.amarok",
//"/org/mpris/MediaPlayer2",
//"",
//"PlayPause");
//return ! QDBusConnection::sessionBus().send(m);
return system("mpc toggle");
}
int
switch_window(void)
{
QDBusMessage m = QDBusMessage::createMethodCall("org.kde.kglobalaccel",
"/component/kwin",
"",
"invokeShortcut");
m << "Walk Through Windows";
return ! QDBusConnection::sessionBus().send(m);
}
#include "socket.h"
int read_socket(int fd, void *buf, size_t len)
{
size_t count, t;
count = 0;
for (; ;) {
t = read(fd, buf+count, len-count);
if (t > 0) {
count += t;
if (count == len)
return 0;
} else if ((t < 0) && (errno == EINTR)) {
continue;
} else {
return 1;
}
}
}
int write_socket(int fd, const void *buf, size_t len)
{
size_t t, count;
count = 0;
while (1) {
t = write(fd, buf, len-count);
if (t > 0) {
count += t;
if (count == len)
return 0;
} else if (t < 0 && errno == EINTR) {
continue;
} else {
return 1;
}
}
}
#ifndef SOCKET_H_
#define SOCKET_H_
#include <unistd.h>
#include <signal.h>
#include <errno.h>
int read_socket(int fd, void *buf, size_t bufsize);
int write_socket(int fd, const void *buf, size_t len);
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment