/soc/2012/sanket/statscollector-2.x.y: b06289b476c9: Memory leak...

Sanket Agarwal sanket at soc.pidgin.im
Sun Mar 31 00:37:40 EDT 2013


Changeset: b06289b476c9ea080409efe8f82b824425510d71
Author:	 Sanket Agarwal <sanket at soc.pidgin.im>
Date:	 2013-03-30 20:35 +0530
Branch:	 mxit-2.x.y
URL: https://hg.pidgin.im/soc/2012/sanket/statscollector-2.x.y/rev/b06289b476c9

Description:

Memory leak management with Valgrind.

Partially fix nagging memory leaks with the code. It's not a complete or
exhaustive list of bugs by any chance, but lots of leaks have been fixed. Work
is still in progress to fix the remaining memory leaks reported by valgrind.

Hy: Leave message empty to abort commit.

diffstat:

 libpurple/plugins/statscollector.c      |  1305 +++++++++++++++++++++++++++++++
 libpurple/protocols/mxit/actions.c      |    30 +-
 libpurple/protocols/mxit/filexfer.c     |    21 +-
 libpurple/protocols/mxit/formcmds.c     |     4 +-
 libpurple/protocols/mxit/http.c         |     2 +-
 libpurple/protocols/mxit/login.c        |    75 +-
 libpurple/protocols/mxit/multimx.c      |     2 +-
 libpurple/protocols/mxit/mxit.c         |    47 +-
 libpurple/protocols/mxit/mxit.h         |     2 +-
 libpurple/protocols/mxit/profile.c      |    18 +-
 libpurple/protocols/mxit/protocol.c     |    52 +-
 libpurple/protocols/mxit/roster.c       |    58 +-
 libpurple/protocols/mxit/splashscreen.c |     2 +-
 libpurple/protocols/mxit/voicevideo.c   |     6 +-
 pidgin/plugins/Makefile.am              |     4 +
 15 files changed, 1466 insertions(+), 162 deletions(-)

diffs (truncated from 2427 to 300 lines):

diff --git a/libpurple/plugins/statscollector.c b/libpurple/plugins/statscollector.c
new file mode 100644
--- /dev/null
+++ b/libpurple/plugins/statscollector.c
@@ -0,0 +1,1305 @@
+/* Log the activity of users */
+
+#include "internal.h"
+
+#include "debug.h"
+#include "log.h"
+#include "notify.h"
+#include "signals.h"
+#include "util.h"
+#include "version.h"
+#include "cipher.h"
+#include "prpl.h"
+#include "core.h"
+#include "accountopt.h"
+#include "request.h"
+
+#include <glib.h>
+
+#ifdef _WIN32
+#include<windows.h>
+#endif
+
+#ifdef __APPLE__
+#include<CoreServices/CoreServices.h>
+#include<sys/types.h>
+#include<sys/sysctl.h>
+#endif
+
+/* Prefs constants */
+#define PREF_PREFIX     "/plugins/core/statscollector"
+#define PREF_ALLOW      PREF_PREFIX "/allow"
+
+/* Allow/Deny Constants */
+enum
+{
+  ALLOW,
+  DENY,
+  ASK
+} AllowSettings;
+
+/* Timeout */
+#define RESEND_SEC (7*24*3600)
+#define PUBLIC_SERVER_CACHE_REFRESH (24*3600)
+
+/* Sending URL */
+#define SEND_URL "http://stats.pidgin.im/collect/"
+#define PUBLIC_SERVER_URL "http://stats.pidgin.im/public/"
+
+/* Version of XML this plugin supports writing */
+
+#define STATS_XML_V "0.2" /* 0 -- Dev purposes */
+
+/* POSIX compliance is an issue that I have looked into some detail now
+ * It seems like presence of unistd.h and _POSIX_VERSION being defined
+ * confirms the presence of POSIX compliance. For this ofcourse we need
+ * to ensure that unistd.h is defined. As it is *already* a part of
+ * internal.h, we could directly go ahead with the testing if the
+ * system is POSIX or not
+ */
+
+#ifdef _POSIX_VERSION
+# include <sys/utsname.h>
+# include <dlfcn.h>
+#endif
+
+PurplePlugin *plugin_g;
+xmlnode *root_stats, *cpuinfo_xml, *ui_info;
+GHashTable *stats_acc_ht, *stats_plugins_ht, *stats_uis_ht;
+GHashTable *public_server_cache_ht=NULL;
+
+int save_timer = 0, send_handle = 0, pref_cb_id = -1, public_server_handle = 0;
+
+/* Types of Operating Systems */
+enum OS_TYPES {WINDOWS, APPLE, UNIX};
+enum BIT_32_64 {BIT_32, BIT_64};
+
+static void schedule_send(void);
+static gboolean send_stats();
+static gboolean plugin_load(PurplePlugin *);
+static gboolean plugin_unload(PurplePlugin *plugin);
+static gboolean refresh_public_server_cache(gpointer data);
+static xmlnode *init_stats();
+static void acc_sign_on_event(PurpleAccount *account);
+
+static void
+confirm_allow(){
+  /* Set the allow variable in prefs to ALLOW */
+  purple_prefs_set_int("/plugins/core/statscollector/allow", ALLOW);
+}
+
+static void
+confirm_deny(){
+  /* Set the allow variable in prefs to ALLOW */
+  purple_prefs_set_int("/plugins/core/statscollector/allow", DENY);
+}
+
+static void
+confirm_later(){
+  /* No-op right now, but can contain logic wherein we have
+   * a timeout before the next callout for authorize/deny
+   */
+}
+
+static glong
+get_time_sec(){
+  /* Gets current time in seconds */
+  GTimeVal res;
+  g_get_current_time(&res);
+  return res.tv_sec;
+}
+
+static void
+save_xml(){
+  /* Uses the Hash tables and other XML nodes
+   * that have been saved/modified and create
+   * final modified XML out of it to be flushed
+   */
+  GHashTableIter iter;
+  gpointer key, value;
+  xmlnode *nroot, *nacc, *nplugins, *nuis;
+  char *data, *version;
+
+  nroot = xmlnode_new("stats");
+
+  /* Set the string information */
+  version = g_strdup_printf("%s", STATS_XML_V);
+  xmlnode_set_attrib(nroot, "version", version);
+
+  /* Load CPUinfo strucutre */
+  xmlnode_insert_child(nroot, xmlnode_copy(cpuinfo_xml));
+
+  /* Load UI info */
+  xmlnode_insert_child(nroot, xmlnode_copy(ui_info));
+
+  nacc = xmlnode_new_child(nroot, "accounts");
+  nplugins = xmlnode_new_child(nroot, "plugins");
+  nuis = xmlnode_new_child(nroot, "uis");
+
+  /* Use the hash tables to populate acc and plugins */
+  g_hash_table_iter_init(&iter, stats_acc_ht);
+  while(g_hash_table_iter_next(&iter, &key, &value)){
+    xmlnode_insert_child(nacc, xmlnode_copy((xmlnode *)value));
+  }
+  g_hash_table_iter_init(&iter, stats_plugins_ht);
+  while(g_hash_table_iter_next(&iter, &key, &value)){
+    xmlnode_insert_child(nplugins, xmlnode_copy((xmlnode *)value));
+  }
+  g_hash_table_iter_init(&iter, stats_uis_ht);
+  while(g_hash_table_iter_next(&iter, &key, &value)){
+    xmlnode_insert_child(nuis, xmlnode_copy((xmlnode *)value));
+  }
+
+  data = xmlnode_to_formatted_str(nroot, NULL);
+  purple_util_write_data_to_file("stats.xml", data, -1);
+  xmlnode_free(nroot);
+  g_free(data);
+}
+
+static gboolean
+save_cb(gpointer data){
+  save_xml();
+  save_timer = 0;
+  return FALSE;
+}
+
+static void
+schedule_stats_save(void){
+  if(save_timer == 0)
+    save_timer = purple_timeout_add_seconds(5, save_cb, NULL);
+}
+
+static void
+refresh_accounts(){
+  /* Scan through each of the currently available accounts,
+   * and refresh them if we get more info
+   */
+  GList *loaded_accounts;
+  loaded_accounts = purple_accounts_get_all_active();
+  g_list_foreach(loaded_accounts, (GFunc)acc_sign_on_event, NULL);
+}
+
+/*
+ * Check if the header has HTTP/1.1 200 ...
+ * I am assuming that the first few characters will always follow
+ * the following format:
+ * HTTP/1.x xyz reason
+ */
+static void
+refresh_public_server_cache_cb(PurpleUtilFetchUrlData *url_data,
+    gpointer user_data, const gchar *url_text, gsize len,
+    const gchar *error_message)
+{
+  int code = -1;
+  char *header = g_strdup_printf("%s", url_text);
+  char *data_loc=NULL;
+  const char *hash_id;
+  xmlnode *public_server_hash_root, *start;
+
+  if(header && strlen(header) >= 14)
+  {
+    header += 9;
+    header[3] = '\0';
+    code = atoi(header);
+  }
+
+  purple_debug_info("STATS", "Code returned: %d\n", code);
+  if(code == 200)
+  {
+    /* Extract the data to be converted to XML => GList */
+    data_loc = strstr(url_text, "\r\n\r\n");
+    public_server_hash_root = xmlnode_from_str(data_loc, -1);
+    if(public_server_hash_root != NULL){
+      /* Now load a Hash Table of accepted Hashes, currently they won't
+       * contain any data, but this is to keep space for any extra info
+       * that the server might give away!
+       */
+      start = xmlnode_get_child(public_server_hash_root, "hash");
+      for(;start;start = xmlnode_get_next_twin(start))
+      {
+        hash_id = xmlnode_get_attrib(start, "id");
+        g_hash_table_insert(public_server_cache_ht, (void *)hash_id, NULL);
+      }
+      public_server_handle = purple_timeout_add_seconds(PUBLIC_SERVER_CACHE_REFRESH, refresh_public_server_cache, NULL);
+
+      /* Check all account split hashes */
+      refresh_accounts();
+
+    }
+  } else {
+     public_server_handle = purple_timeout_add_seconds(10, refresh_public_server_cache, NULL);
+  }
+}
+
+static gboolean
+refresh_public_server_cache(gpointer data)
+{
+  /* Refresh the stored cache of information about IRC/Jabber
+   * servers which are in-effect public using md5 hashes!
+   */
+
+  /* Obtain the list through a webservice */
+  gchar *host, *path, *request, *url= PUBLIC_SERVER_URL;
+  gboolean *send_success;
+  int port;
+
+  purple_debug_info("STATS", "requesting public server ...");
+  purple_url_parse(url, &host, &port, &path, NULL, NULL);
+  send_success = g_new0(gboolean, 1);
+  request = g_strdup_printf(\
+          "GET /%s HTTP/1.0\r\n"
+          "Connection: keep-alive\r\n"
+          "Host: %s\r\n\r\n",
+          path, host);
+  purple_debug_info("STATS", "%s", request);
+  purple_util_fetch_url_request(url, TRUE, NULL, FALSE, request, TRUE, refresh_public_server_cache_cb, send_success);
+
+  g_free(host);
+  g_free(path);
+  g_free(request);
+
+  return FALSE;
+}
+
+/* Determines if the application is running in 32 or 64 bit mode */
+static xmlnode *
+get_app_32_64(){
+  int pt_size;
+  xmlnode *bit_size_xml;
+
+  pt_size = sizeof(int *)*8;
+  bit_size_xml = xmlnode_new("app-bit");
+  xmlnode_insert_data(bit_size_xml, g_strdup_printf("%d",pt_size), -1);
+  return bit_size_xml;
+}
+
+/* Determines whether the kernel we are running is 32 or 64 bit */
+static xmlnode *
+get_os_32_64(){
+  int bit_size=-1;
+  xmlnode *bit_size_xml;
+#ifdef _WIN32
+  BOOL bIsWow64;
+  typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
+  LPFN_ISWOW64PROCESS fnIsWow64Process;
+#elif defined _POSIX_VERSION
+  struct utsname os_utsname;
+  char *m_name, *bit_size_str;
+#endif
+  bit_size_xml = xmlnode_new("os-bit");
+#ifdef _WIN64
+  bit_size = 64;
+#elif defined _WIN32
+  /* Check if we are running as wow64 process */
+  bIsWow64 = FALSE;
+  fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress( \



More information about the Commits mailing list