#include "config.h" #include #include #include #include #include #include #include #include #include #include #include "evas_cs2.h" static int socketfd = -1; static unsigned int _rid_count = 1; static int _evas_cserve2_debug_log_dom = -1; static struct sockaddr_un socksize; #ifndef UNIX_PATH_MAX #define UNIX_PATH_MAX sizeof(socksize.sun_path) #endif #ifdef ERR #undef ERR #endif #define ERR(...) EINA_LOG_DOM_ERR(_evas_cserve2_debug_log_dom, __VA_ARGS__) #ifdef DBG #undef DBG #endif #define DBG(...) EINA_LOG_DOM_DBG(_evas_cserve2_debug_log_dom, __VA_ARGS__) #ifdef WRN #undef WRN #endif #define WRN(...) EINA_LOG_DOM_WARN(_evas_cserve2_debug_log_dom, __VA_ARGS__) #ifdef INF #undef INF #endif #define INF(...) EINA_LOG_DOM_INFO(_evas_cserve2_debug_log_dom, __VA_ARGS__) static void _socket_path_set(char *path) { char *env; char buf[UNIX_PATH_MAX]; env = getenv("EVAS_CSERVE2_SOCKET"); if (env && env[0]) { strncpy(path, env, UNIX_PATH_MAX - 1); return; } snprintf(buf, sizeof(buf), "/tmp/.evas-cserve2-%x.socket", (int)getuid()); /* FIXME: check we can actually create this socket */ strcpy(path, buf); } static Eina_Bool _server_connect(void) { int s, len; struct sockaddr_un remote; if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { ERR("socket"); return EINA_FALSE; } remote.sun_family = AF_UNIX; _socket_path_set(remote.sun_path); len = strlen(remote.sun_path) + sizeof(remote.sun_family); if (connect(s, (struct sockaddr *)&remote, len) == -1) { ERR("connect"); return EINA_FALSE; } fcntl(s, F_SETFL, O_NONBLOCK); socketfd = s; DBG("connected to cserve2 server."); return EINA_TRUE; } static void _server_disconnect(void) { close(socketfd); socketfd = -1; } static Eina_Bool _server_send(const void *data, int size) { int sent = 0; ssize_t ret; const char *msg = data; while (sent < size) { ret = send(socketfd, msg + sent, size - sent, MSG_NOSIGNAL); if (ret < 0) { if ((errno == EAGAIN) || (errno == EINTR)) continue; return EINA_FALSE; } sent += ret; } return EINA_TRUE; } static int sr_size = 0; static int sr_got = 0; static char *sr_buf = NULL; static void * _server_read(int *size) { int n; void *ret; if (sr_size) goto get_data; n = recv(socketfd, &sr_size, sizeof(sr_size), 0); if (n < 0) return NULL; sr_buf = malloc(sr_size); get_data: n = recv(socketfd, sr_buf + sr_got, sr_size - sr_got, 0); if (n < 0) return NULL; sr_got += n; if (sr_got < sr_size) return NULL; *size = sr_size; sr_size = 0; sr_got = 0; ret = sr_buf; sr_buf = NULL; return ret; } static void _debug_msg_send(void) { Msg_Base msg; int size; memset(&msg, 0, sizeof(msg)); msg.type = CSERVE2_FONT_DEBUG; msg.rid = _rid_count++; size = sizeof(msg); if (!_server_send(&size, sizeof(size))) { ERR("Could not send usage msg size to server."); return; } if (!_server_send(&msg, size)) { ERR("Could not send usage msg body to server."); return; } } typedef struct _Font_Entry Font_Entry; typedef struct _Cache_Entry Cache_Entry; typedef struct _Glyph_Entry Glyph_Entry; struct _Font_Entry { const char *file; const char *name; unsigned int rend_flags; unsigned int size; unsigned int dpi; unsigned int unused; Eina_List *caches; }; struct _Cache_Entry { const char *shmname; unsigned int size; unsigned int usage; Eina_List *glyphs; }; struct _Glyph_Entry { unsigned int index; unsigned int offset; unsigned int size; unsigned int rows; unsigned int width; unsigned int pitch; unsigned int num_grays; unsigned int pixel_mode; }; #define READIT(_dst, _src) \ do { \ memcpy(&_dst, _src, sizeof(_dst)); \ _src += sizeof(_dst); \ } while(0) static Glyph_Entry * _parse_glyph_entry(char **msg) { Glyph_Entry *ge; char *buf = *msg; ge = calloc(1, sizeof(*ge)); READIT(ge->index, buf); READIT(ge->offset, buf); READIT(ge->size, buf); READIT(ge->rows, buf); READIT(ge->width, buf); READIT(ge->pitch, buf); READIT(ge->num_grays, buf); READIT(ge->pixel_mode, buf); *msg = buf; return ge; } static Cache_Entry * _parse_cache_entry(char **msg) { Cache_Entry *ce; char *buf = *msg; unsigned int n; ce = calloc(1, sizeof(*ce)); READIT(n, buf); ce->shmname = eina_stringshare_add_length(buf, n); buf += n; READIT(ce->size, buf); READIT(ce->usage, buf); READIT(n, buf); while (n--) { Glyph_Entry *ge; ge = _parse_glyph_entry(&buf); ce->glyphs = eina_list_append(ce->glyphs, ge); } *msg = buf; return ce; } static Font_Entry * _parse_font_entry(char **msg) { Font_Entry *fe; char *buf = *msg; unsigned int n; fe = calloc(1, sizeof(*fe)); READIT(n, buf); if (n) fe->file = eina_stringshare_add_length(buf, n); buf += n; READIT(n, buf); if (n) fe->name = eina_stringshare_add_length(buf, n); buf += n; READIT(fe->rend_flags, buf); READIT(fe->size, buf); READIT(fe->dpi, buf); READIT(fe->unused, buf); READIT(n, buf); while (n--) { Cache_Entry *ce; ce = _parse_cache_entry(&buf); fe->caches = eina_list_append(fe->caches, ce); } *msg = buf; return fe; } static Eina_List * _debug_msg_read(void) { Msg_Base *msg = NULL; char *buf; int size; unsigned int nfonts; Eina_List *fonts = NULL; printf("Requesting server debug info.\n\n"); while (!msg) msg = _server_read(&size); if (msg->type != CSERVE2_FONT_DEBUG) { ERR("Invalid message received from server." "Something went badly wrong."); return NULL; } buf = (char *)msg + sizeof(*msg); READIT(nfonts, buf); while (nfonts--) { Font_Entry *fe; fe = _parse_font_entry(&buf); fonts = eina_list_append(fonts, fe); } return fonts; } static void _glyph_entry_free(Glyph_Entry *ge) { free(ge); } static void _cache_entry_free(Cache_Entry *ce) { Glyph_Entry *ge; EINA_LIST_FREE(ce->glyphs, ge) _glyph_entry_free(ge); eina_stringshare_del(ce->shmname); free(ce); } static void _font_entry_free(Font_Entry *fe) { Cache_Entry *ce; EINA_LIST_FREE(fe->caches, ce) _cache_entry_free(ce); eina_stringshare_del(fe->name); eina_stringshare_del(fe->file); free(fe); } static void _glyph_entry_print(Glyph_Entry *ge) { const char *pxmode[] = { "FT_PIXEL_MODE_NONE", "FT_PIXEL_MODE_MONO", "FT_PIXEL_MODE_GRAY", "FT_PIXEL_MODE_GRAY2", "FT_PIXEL_MODE_GRAY4", "FT_PIXEL_MODE_LCD", "FT_PIXEL_MODE_LCD_V" }; printf("\t\tGLYPH %u offset: %u size: %u %ux%u pitch: %u grays: %u " "pixel mode: %s\n", ge->index, ge->offset, ge->size, ge->width, ge->rows, ge->pitch, ge->num_grays, pxmode[ge->pixel_mode]); } static void _cache_entry_print(Cache_Entry *ce) { Eina_List *l; Glyph_Entry *ge; printf("\tSHM %s used %u/%u\n", ce->shmname, ce->usage, ce->size); EINA_LIST_FOREACH(ce->glyphs, l, ge) _glyph_entry_print(ge); } static void _font_entry_print(Font_Entry *fe) { Eina_List *l; Cache_Entry *ce; printf("FONT %s:%s size: %u dpi: %u %s%s%s %s\n", fe->file, fe->name, fe->size, fe->dpi, fe->rend_flags == 0 ? "REGULAR " : "", fe->rend_flags & 1 ? "SLANT " : "", fe->rend_flags & 2 ? "WEIGHT" : "", fe->unused ? "(unused)" : ""); EINA_LIST_FOREACH(fe->caches, l, ce) _cache_entry_print(ce); putchar('\n'); } int main(void) { Eina_List *fonts; Font_Entry *fe; eina_init(); _evas_cserve2_debug_log_dom = eina_log_domain_register ("evas_cserve2_debug", EINA_COLOR_BLUE); if (!_server_connect()) { ERR("Could not connect to server."); return -1; } _debug_msg_send(); fonts = _debug_msg_read(); EINA_LIST_FREE(fonts, fe) { _font_entry_print(fe); _font_entry_free(fe); } _server_disconnect(); eina_shutdown(); }