Skip to content

Instantly share code, notes, and snippets.

@am0c
Created May 9, 2011 11:35
Show Gist options
  • Select an option

  • Save am0c/962378 to your computer and use it in GitHub Desktop.

Select an option

Save am0c/962378 to your computer and use it in GitHub Desktop.
simulating android af_local
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stddef.h>
#include <errno.h>
#include <fcntl.h>
#define PROP_SERVICE_NAME "mysocket"
#define PROP_PATH_SYSTEM_BUILD "/system/build.prop"
#define PROP_PATH_SYSTEM_DEFAULT "/system/default.prop"
#define PROP_PATH_LOCAL_OVERRIDE "/data/local/prop"
#define PROP_MSG_SETPROP 1
#define PROP_NAME_MAX 32
#define PROP_VALUE_MAX 92
#define ERROR(...) printf(__VA_ARGS__)
#define INFO(...) printf(__VA_ARGS__)
#define NOP_YET do {} while (0);
#define ueventd() NOP_YET
#define blah_blah() NOP_YET
#define load_persistent_properties() NOP_YET
static int property_set_fd = -1;
static int property_area_inited = 0;
static int persistent_properties_loaded = 0;
typedef struct prop_msg prop_msg;
struct prop_msg
{
unsigned cmd;
char name[PROP_NAME_MAX];
char value[PROP_VALUE_MAX];
};
static int set_init_properties_action(void);
static int property_set(const char *key, const char *value);
static int send_prop_msg(prop_msg *msg);
static int socket_local_client(const char *name, int type);
static int socket_local_client_connect(int fd, const char *name);
static int socket_make_sockaddr_un(const char *name, struct sockaddr_un *p_addr, socklen_t *alen);
static void load_properties_from_file(const char *fn);
static int property_service_init_action(void);
static int start_property_service(void);
static void handle_property_set_fd();
static void dump_prop_msg(prop_msg *msg);
static int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid);
int main()
{
int i;
int fd_count = 1;
/* early-init */
ueventd();
/* many calls for property_set */
set_init_properties_action();
/* and than start init action */
property_service_init_action();
blah_blah();
blah_blah();
/* event loop */
for (;;) {
blah_blah();
blah_blah();
/* event dispatch */
for (i = 0; i < fd_count; i++) {
handle_property_set_fd();
}
}
}
/**************************************
* section for setting property or
* connecting to socket
*/
static int set_init_properties_action(void)
{
property_set("ro.serialno", "stfcawsc");
property_set("ro.bootmode", "rm.dd");
}
static int property_set(const char *key, const char *value)
{
prop_msg msg;
unsigned resp;
if (strlen(key) >= PROP_NAME_MAX) return -1;
if (strlen(value) >= PROP_VALUE_MAX) return -1;
msg.cmd = PROP_MSG_SETPROP;
strcpy((char *) msg.name, key);
strcpy((char *) msg.value, value);
return send_prop_msg(&msg);
}
static int send_prop_msg(prop_msg *msg)
{
int s;
int r;
s = socket_local_client(PROP_SERVICE_NAME, SOCK_STREAM);
if (s < 0) return -1;
while((r = send(s, msg, sizeof(prop_msg), 0)) < 0) {
if((errno == EINTR) || (errno == EAGAIN)) continue;
break;
}
if (r == sizeof(prop_msg)) {
r = 0;
} else {
r = -1;
}
close(s);
return r;
}
static int socket_local_client(const char *name, int type)
{
int s;
s = socket(AF_LOCAL, type, 0);
if (s < 0) return -1;
if ( 0 > socket_local_client_connect(s, name)) {
close(s);
return -1;
}
return s;
}
static int socket_local_client_connect(int fd, const char *name)
{
struct sockaddr_un addr;
socklen_t alen;
size_t namelen;
int err;
err = socket_make_sockaddr_un(name, &addr, &alen);
if (err < 0)
goto error;
if (connect(fd, (struct sockaddr *) &addr, alen) < 0)
goto error;
return fd;
error:
return -1;
}
static int socket_make_sockaddr_un(const char *name,
struct sockaddr_un *p_addr,
socklen_t *alen)
{
size_t namelen;
memset(p_addr, 0, sizeof(*p_addr));
namelen = strlen(name);
strcpy(p_addr->sun_path, name);
p_addr->sun_family = AF_LOCAL;
*alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
return 0;
}
static void load_properties_from_file(const char *fn)
{
property_set("test.load", fn);
}
/**************************************
* section for getting property or
* listening to socket
*/
static int property_service_init_action(void)
{
start_property_service();
return 0;
}
static int start_property_service(void)
{
int fd;
load_properties_from_file(PROP_PATH_SYSTEM_BUILD);
load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);
load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE);
load_persistent_properties();
fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, getuid(), getgid());
if (fd < 0) return;
fcntl(fd, F_SETFD, FD_CLOEXEC);
fcntl(fd, F_SETFL, O_NONBLOCK);
listen(fd, 8);
property_set_fd = fd;
}
static void handle_property_set_fd()
{
prop_msg msg;
int s;
int r;
int res;
struct sockaddr_un addr;
socklen_t addr_size = sizeof(addr);
if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
return;
}
r = recv(s, &msg, sizeof(msg), 0);
close(s);
if(r != sizeof(prop_msg)) {
ERROR("sys_prop: mis-match msg size recieved: %d expected: %d\n",
r, sizeof(prop_msg));
return;
}
switch(msg.cmd) {
case PROP_MSG_SETPROP:
msg.name[PROP_NAME_MAX-1] = 0;
msg.value[PROP_VALUE_MAX-1] = 0;
dump_prop_msg(&msg);
}
}
static void dump_prop_msg(prop_msg *msg)
{
printf(
"==dump==\n"
"key: %s\n"
"val: %s\n"
"\n",
msg->name, msg->value
);
}
static int create_socket(const char *name, int type,
mode_t perm, uid_t uid,
gid_t gid)
{
struct sockaddr_un addr;
int fd, ret;
fd = socket(PF_UNIX, type, 0);
if (fd < 0) {
ERROR("Failed to open socket '%s': %s\n", name, strerror(errno));
return -1;
}
memset(&addr, 0 , sizeof(addr));
addr.sun_family = AF_UNIX;
//snprintf(addr.sun_path, sizeof(addr.sun_path), name);
strcpy(addr.sun_path, name);
ret = unlink(addr.sun_path);
if (ret != 0 && errno != ENOENT) {
ERROR("Failed to unlink old socket '%s': %s\n", name, strerror(errno));
goto out_close;
}
ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
if (ret) {
ERROR("Failed to bind socket '%s': %s\n", name, strerror(errno));
goto out_unlink;
}
chown(addr.sun_path, uid, gid);
chmod(addr.sun_path, perm);
INFO("Created socket '%s' with mode '%o', user '%d', group '%d'\n",
addr.sun_path, perm, uid, gid);
return fd;
out_unlink:
unlink(addr.sun_path);
out_close:
close(fd);
return -1;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment