Created
May 9, 2011 11:35
-
-
Save am0c/962378 to your computer and use it in GitHub Desktop.
simulating android af_local
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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