{"action":"created","comment":{"url":"https://api.github.com/repos/glyptodon/guacamole-server/pulls/comments/54526471","id":54526471,"diff_hunk":"@@ -124,107 +134,132 @@ guac_stream* guac_client_alloc_stream(guac_client* client) {\n void guac_client_free_stream(guac_client* client, guac_stream* stream) {\n \n     /* Release index to pool */\n-    guac_pool_free_int(client->__stream_pool, stream->index);\n+    guac_pool_free_int(client->__stream_pool, (stream->index - 1) / 2);\n \n     /* Mark stream as closed */\n     stream->index = GUAC_CLIENT_CLOSED_STREAM_INDEX;\n \n }\n \n-guac_object* guac_client_alloc_object(guac_client* client) {\n \n-    guac_object* allocd_object;\n-    int object_index;\n+/**\n+ * The broadcast socket cannot be read from.\n+ */\n+static ssize_t __guac_socket_broadcast_read_handler(guac_socket* socket,\n+        void* buf, size_t count) {\n \n-    /* Refuse to allocate beyond maximum */\n-    if (client->__object_pool->active == GUAC_CLIENT_MAX_OBJECTS)\n-        return NULL;\n+    /* Broadcast socket reads are not allowed */\n+    return -1;\n+\n+}\n+\n+/**\n+ * Writes a chunk of data to a given user.\n+ */\n+static void* __write_chunk_callback(guac_user* user, void* data) {\n \n-    /* Allocate object */\n-    object_index = guac_pool_next_int(client->__object_pool);\n+    __write_chunk* chunk = (__write_chunk*) data;\n \n-    /* Initialize object */\n-    allocd_object = &(client->__objects[object_index]);\n-    allocd_object->index = object_index;\n-    allocd_object->data = NULL;\n-    allocd_object->get_handler = NULL;\n-    allocd_object->put_handler = NULL;\n+    /* Attempt write, disconnect on failure */\n+    if (guac_socket_write(user->socket, chunk->buffer, chunk->length))\n+        guac_user_stop(user);\n \n-    return allocd_object;\n+    return NULL;\n \n }\n \n-void guac_client_free_object(guac_client* client, guac_object* object) {\n+/**\n+ * Socket write handler which operates on each of the sockets of all connected\n+ * users, unifying the results.\n+ */\n+static ssize_t __guac_socket_broadcast_write_handler(guac_socket* socket,\n+        const void* buf, size_t count) {\n+\n+    guac_client* client = (guac_client*) socket->data;\n \n-    /* Release index to pool */\n-    guac_pool_free_int(client->__object_pool, object->index);\n+    /* Build chunk */\n+    __write_chunk chunk;\n+    chunk.buffer = buf;\n+    chunk.length = count;\n+\n+    /* Broadcast chunk to all users */\n+    guac_client_foreach_user(client, __write_chunk_callback, &chunk);\n \n-    /* Mark object as undefined */\n-    object->index = GUAC_CLIENT_UNDEFINED_OBJECT_INDEX;\n+    return count;\n \n }\n \n-/**\n- * Returns a newly allocated string containing a guaranteed-unique connection\n- * identifier string which is 37 characters long and begins with a '$'\n- * character.  If an error occurs, NULL is returned, and no memory is\n- * allocated.\n- */\n-static char* __guac_generate_connection_id() {\n+static void* __flush_callback(guac_user* user, void* data) {\n \n-    char* buffer;\n-    char* identifier;\n-    size_t identifier_length;\n+    /* Attempt flush, disconnect on failure */\n+    if (guac_socket_flush(user->socket))\n+        guac_user_stop(user);\n \n-    uuid_t* uuid;\n+    return NULL;\n \n-    /* Attempt to create UUID object */\n-    if (uuid_create(&uuid) != UUID_RC_OK) {\n-        guac_error = GUAC_STATUS_NO_MEMORY;\n-        guac_error_message = \"Could not allocate memory for UUID\";\n-        return NULL;\n-    }\n+}\n \n-    /* Generate random UUID */\n-    if (uuid_make(uuid, UUID_MAKE_V4) != UUID_RC_OK) {\n-        uuid_destroy(uuid);\n-        guac_error = GUAC_STATUS_NO_MEMORY;\n-        guac_error_message = \"UUID generation failed\";\n-        return NULL;\n-    }\n+static ssize_t __guac_socket_broadcast_flush_handler(guac_socket* socket) {\n \n-    /* Allocate buffer for future formatted ID */\n-    buffer = malloc(UUID_LEN_STR + 2);\n-    if (buffer == NULL) {\n-        uuid_destroy(uuid);\n-        guac_error = GUAC_STATUS_NO_MEMORY;\n-        guac_error_message = \"Could not allocate memory for connection ID\";\n-        return NULL;\n-    }\n+    guac_client* client = (guac_client*) socket->data;\n \n-    identifier = &(buffer[1]);\n-    identifier_length = UUID_LEN_STR + 1;\n+    /* Flush all users */\n+    guac_client_foreach_user(client, __flush_callback, NULL);\n \n-    /* Build connection ID from UUID */\n-    if (uuid_export(uuid, UUID_FMT_STR, &identifier, &identifier_length) != UUID_RC_OK) {\n-        free(buffer);\n-        uuid_destroy(uuid);\n-        guac_error = GUAC_STATUS_INTERNAL_ERROR;\n-        guac_error_message = \"Conversion of UUID to connection ID failed\";\n-        return NULL;\n-    }\n+    return 0;\n \n-    uuid_destroy(uuid);\n+}\n+\n+static void* __lock_callback(guac_user* user, void* data) {\n+\n+    /* Lock socket */\n+    guac_socket_instruction_begin(user->socket);\n+\n+    return NULL;\n+\n+}\n+\n+static void __guac_socket_broadcast_lock_handler(guac_socket* socket) {\n+\n+    guac_client* client = (guac_client*) socket->data;\n+\n+    /* Flush all users */\n+    guac_client_foreach_user(client, __lock_callback, NULL);\n+\n+}\n \n-    buffer[0] = '$';\n-    buffer[UUID_LEN_STR + 1] = '\\0';\n-    return buffer;\n+static void* __unlock_callback(guac_user* user, void* data) {","path":"src/libguac/client.c","position":237,"original_position":237,"commit_id":"3eec831d7cf1268e554fd804d736e64ec8acd8c4","original_commit_id":"3eec831d7cf1268e554fd804d736e64ec8acd8c4","user":{"login":"jmuehlner","id":4633119,"avatar_url":"https://avatars.githubusercontent.com/u/4633119?v=3","gravatar_id":"","url":"https://api.github.com/users/jmuehlner","html_url":"https://github.com/jmuehlner","followers_url":"https://api.github.com/users/jmuehlner/followers","following_url":"https://api.github.com/users/jmuehlner/following{/other_user}","gists_url":"https://api.github.com/users/jmuehlner/gists{/gist_id}","starred_url":"https://api.github.com/users/jmuehlner/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jmuehlner/subscriptions","organizations_url":"https://api.github.com/users/jmuehlner/orgs","repos_url":"https://api.github.com/users/jmuehlner/repos","events_url":"https://api.github.com/users/jmuehlner/events{/privacy}","received_events_url":"https://api.github.com/users/jmuehlner/received_events","type":"User","site_admin":false},"body":"Missing comment","created_at":"2016-03-01T06:09:11Z","updated_at":"2016-03-01T06:09:11Z","html_url":"https://github.com/glyptodon/guacamole-server/pull/109#discussion_r54526471","pull_request_url":"https://api.github.com/repos/glyptodon/guacamole-server/pulls/109","_links":{"self":{"href":"https://api.github.com/repos/glyptodon/guacamole-server/pulls/comments/54526471"},"html":{"href":"https://github.com/glyptodon/guacamole-server/pull/109#discussion_r54526471"},"pull_request":{"href":"https://api.github.com/repos/glyptodon/guacamole-server/pulls/109"}}},"pull_request":{"url":"https://api.github.com/repos/glyptodon/guacamole-server/pulls/109","id":61197356,"html_url":"https://github.com/glyptodon/guacamole-server/pull/109","diff_url":"https://github.com/glyptodon/guacamole-server/pull/109.diff","patch_url":"https://github.com/glyptodon/guacamole-server/pull/109.patch","issue_url":"https://api.github.com/repos/glyptodon/guacamole-server/issues/109","number":109,"state":"open","locked":false,"title":"GUAC-1389: Refactor libguac to allow screen sharing.","user":{"login":"mike-jumper","id":4632905,"avatar_url":"https://avatars.githubusercontent.com/u/4632905?v=3","gravatar_id":"","url":"https://api.github.com/users/mike-jumper","html_url":"https://github.com/mike-jumper","followers_url":"https://api.github.com/users/mike-jumper/followers","following_url":"https://api.github.com/users/mike-jumper/following{/other_user}","gists_url":"https://api.github.com/users/mike-jumper/gists{/gist_id}","starred_url":"https://api.github.com/users/mike-jumper/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mike-jumper/subscriptions","organizations_url":"https://api.github.com/users/mike-jumper/orgs","repos_url":"https://api.github.com/users/mike-jumper/repos","events_url":"https://api.github.com/users/mike-jumper/events{/privacy}","received_events_url":"https://api.github.com/users/mike-jumper/received_events","type":"User","site_admin":false},"body":"Parts of the build that will break have been disabled temporarily.","created_at":"2016-03-01T06:02:50Z","updated_at":"2016-03-01T06:09:11Z","closed_at":null,"merged_at":null,"merge_commit_sha":"f59f653eb44153959fbea1d6701d2416685d6bd8","assignee":{"login":"jmuehlner","id":4633119,"avatar_url":"https://avatars.githubusercontent.com/u/4633119?v=3","gravatar_id":"","url":"https://api.github.com/users/jmuehlner","html_url":"https://github.com/jmuehlner","followers_url":"https://api.github.com/users/jmuehlner/followers","following_url":"https://api.github.com/users/jmuehlner/following{/other_user}","gists_url":"https://api.github.com/users/jmuehlner/gists{/gist_id}","starred_url":"https://api.github.com/users/jmuehlner/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jmuehlner/subscriptions","organizations_url":"https://api.github.com/users/jmuehlner/orgs","repos_url":"https://api.github.com/users/jmuehlner/repos","events_url":"https://api.github.com/users/jmuehlner/events{/privacy}","received_events_url":"https://api.github.com/users/jmuehlner/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/glyptodon/guacamole-server/pulls/109/commits","review_comments_url":"https://api.github.com/repos/glyptodon/guacamole-server/pulls/109/comments","review_comment_url":"https://api.github.com/repos/glyptodon/guacamole-server/pulls/comments{/number}","comments_url":"https://api.github.com/repos/glyptodon/guacamole-server/issues/109/comments","statuses_url":"https://api.github.com/repos/glyptodon/guacamole-server/statuses/3eec831d7cf1268e554fd804d736e64ec8acd8c4","head":{"label":"glyptodon:fake-merge-screen-sharing-001-libguac","ref":"fake-merge-screen-sharing-001-libguac","sha":"3eec831d7cf1268e554fd804d736e64ec8acd8c4","user":{"login":"glyptodon","id":4632960,"avatar_url":"https://avatars.githubusercontent.com/u/4632960?v=3","gravatar_id":"","url":"https://api.github.com/users/glyptodon","html_url":"https://github.com/glyptodon","followers_url":"https://api.github.com/users/glyptodon/followers","following_url":"https://api.github.com/users/glyptodon/following{/other_user}","gists_url":"https://api.github.com/users/glyptodon/gists{/gist_id}","starred_url":"https://api.github.com/users/glyptodon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/glyptodon/subscriptions","organizations_url":"https://api.github.com/users/glyptodon/orgs","repos_url":"https://api.github.com/users/glyptodon/repos","events_url":"https://api.github.com/users/glyptodon/events{/privacy}","received_events_url":"https://api.github.com/users/glyptodon/received_events","type":"Organization","site_admin":false},"repo":{"id":10532458,"name":"guacamole-server","full_name":"glyptodon/guacamole-server","owner":{"login":"glyptodon","id":4632960,"avatar_url":"https://avatars.githubusercontent.com/u/4632960?v=3","gravatar_id":"","url":"https://api.github.com/users/glyptodon","html_url":"https://github.com/glyptodon","followers_url":"https://api.github.com/users/glyptodon/followers","following_url":"https://api.github.com/users/glyptodon/following{/other_user}","gists_url":"https://api.github.com/users/glyptodon/gists{/gist_id}","starred_url":"https://api.github.com/users/glyptodon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/glyptodon/subscriptions","organizations_url":"https://api.github.com/users/glyptodon/orgs","repos_url":"https://api.github.com/users/glyptodon/repos","events_url":"https://api.github.com/users/glyptodon/events{/privacy}","received_events_url":"https://api.github.com/users/glyptodon/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/glyptodon/guacamole-server","description":"The server-side, native components that form the Guacamole proxy.","fork":false,"url":"https://api.github.com/repos/glyptodon/guacamole-server","forks_url":"https://api.github.com/repos/glyptodon/guacamole-server/forks","keys_url":"https://api.github.com/repos/glyptodon/guacamole-server/keys{/key_id}","collaborators_url":"https://api.github.com/repos/glyptodon/guacamole-server/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/glyptodon/guacamole-server/teams","hooks_url":"https://api.github.com/repos/glyptodon/guacamole-server/hooks","issue_events_url":"https://api.github.com/repos/glyptodon/guacamole-server/issues/events{/number}","events_url":"https://api.github.com/repos/glyptodon/guacamole-server/events","assignees_url":"https://api.github.com/repos/glyptodon/guacamole-server/assignees{/user}","branches_url":"https://api.github.com/repos/glyptodon/guacamole-server/branches{/branch}","tags_url":"https://api.github.com/repos/glyptodon/guacamole-server/tags","blobs_url":"https://api.github.com/repos/glyptodon/guacamole-server/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/glyptodon/guacamole-server/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/glyptodon/guacamole-server/git/refs{/sha}","trees_url":"https://api.github.com/repos/glyptodon/guacamole-server/git/trees{/sha}","statuses_url":"https://api.github.com/repos/glyptodon/guacamole-server/statuses/{sha}","languages_url":"https://api.github.com/repos/glyptodon/guacamole-server/languages","stargazers_url":"https://api.github.com/repos/glyptodon/guacamole-server/stargazers","contributors_url":"https://api.github.com/repos/glyptodon/guacamole-server/contributors","subscribers_url":"https://api.github.com/repos/glyptodon/guacamole-server/subscribers","subscription_url":"https://api.github.com/repos/glyptodon/guacamole-server/subscription","commits_url":"https://api.github.com/repos/glyptodon/guacamole-server/commits{/sha}","git_commits_url":"https://api.github.com/repos/glyptodon/guacamole-server/git/commits{/sha}","comments_url":"https://api.github.com/repos/glyptodon/guacamole-server/comments{/number}","issue_comment_url":"https://api.github.com/repos/glyptodon/guacamole-server/issues/comments{/number}","contents_url":"https://api.github.com/repos/glyptodon/guacamole-server/contents/{+path}","compare_url":"https://api.github.com/repos/glyptodon/guacamole-server/compare/{base}...{head}","merges_url":"https://api.github.com/repos/glyptodon/guacamole-server/merges","archive_url":"https://api.github.com/repos/glyptodon/guacamole-server/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/glyptodon/guacamole-server/downloads","issues_url":"https://api.github.com/repos/glyptodon/guacamole-server/issues{/number}","pulls_url":"https://api.github.com/repos/glyptodon/guacamole-server/pulls{/number}","milestones_url":"https://api.github.com/repos/glyptodon/guacamole-server/milestones{/number}","notifications_url":"https://api.github.com/repos/glyptodon/guacamole-server/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/glyptodon/guacamole-server/labels{/name}","releases_url":"https://api.github.com/repos/glyptodon/guacamole-server/releases{/id}","deployments_url":"https://api.github.com/repos/glyptodon/guacamole-server/deployments","created_at":"2013-06-06T17:40:59Z","updated_at":"2016-02-28T21:26:52Z","pushed_at":"2016-03-01T06:02:50Z","git_url":"git://github.com/glyptodon/guacamole-server.git","ssh_url":"git@github.com:glyptodon/guacamole-server.git","clone_url":"https://github.com/glyptodon/guacamole-server.git","svn_url":"https://github.com/glyptodon/guacamole-server","homepage":"http://guac-dev.org/","size":7066,"stargazers_count":821,"watchers_count":821,"language":"C","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":128,"mirror_url":null,"open_issues_count":3,"forks":128,"open_issues":3,"watchers":821,"default_branch":"master"}},"base":{"label":"glyptodon:master","ref":"master","sha":"e8cd669be286aa1a325fd7c2c9c321371b4e9bad","user":{"login":"glyptodon","id":4632960,"avatar_url":"https://avatars.githubusercontent.com/u/4632960?v=3","gravatar_id":"","url":"https://api.github.com/users/glyptodon","html_url":"https://github.com/glyptodon","followers_url":"https://api.github.com/users/glyptodon/followers","following_url":"https://api.github.com/users/glyptodon/following{/other_user}","gists_url":"https://api.github.com/users/glyptodon/gists{/gist_id}","starred_url":"https://api.github.com/users/glyptodon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/glyptodon/subscriptions","organizations_url":"https://api.github.com/users/glyptodon/orgs","repos_url":"https://api.github.com/users/glyptodon/repos","events_url":"https://api.github.com/users/glyptodon/events{/privacy}","received_events_url":"https://api.github.com/users/glyptodon/received_events","type":"Organization","site_admin":false},"repo":{"id":10532458,"name":"guacamole-server","full_name":"glyptodon/guacamole-server","owner":{"login":"glyptodon","id":4632960,"avatar_url":"https://avatars.githubusercontent.com/u/4632960?v=3","gravatar_id":"","url":"https://api.github.com/users/glyptodon","html_url":"https://github.com/glyptodon","followers_url":"https://api.github.com/users/glyptodon/followers","following_url":"https://api.github.com/users/glyptodon/following{/other_user}","gists_url":"https://api.github.com/users/glyptodon/gists{/gist_id}","starred_url":"https://api.github.com/users/glyptodon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/glyptodon/subscriptions","organizations_url":"https://api.github.com/users/glyptodon/orgs","repos_url":"https://api.github.com/users/glyptodon/repos","events_url":"https://api.github.com/users/glyptodon/events{/privacy}","received_events_url":"https://api.github.com/users/glyptodon/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/glyptodon/guacamole-server","description":"The server-side, native components that form the Guacamole proxy.","fork":false,"url":"https://api.github.com/repos/glyptodon/guacamole-server","forks_url":"https://api.github.com/repos/glyptodon/guacamole-server/forks","keys_url":"https://api.github.com/repos/glyptodon/guacamole-server/keys{/key_id}","collaborators_url":"https://api.github.com/repos/glyptodon/guacamole-server/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/glyptodon/guacamole-server/teams","hooks_url":"https://api.github.com/repos/glyptodon/guacamole-server/hooks","issue_events_url":"https://api.github.com/repos/glyptodon/guacamole-server/issues/events{/number}","events_url":"https://api.github.com/repos/glyptodon/guacamole-server/events","assignees_url":"https://api.github.com/repos/glyptodon/guacamole-server/assignees{/user}","branches_url":"https://api.github.com/repos/glyptodon/guacamole-server/branches{/branch}","tags_url":"https://api.github.com/repos/glyptodon/guacamole-server/tags","blobs_url":"https://api.github.com/repos/glyptodon/guacamole-server/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/glyptodon/guacamole-server/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/glyptodon/guacamole-server/git/refs{/sha}","trees_url":"https://api.github.com/repos/glyptodon/guacamole-server/git/trees{/sha}","statuses_url":"https://api.github.com/repos/glyptodon/guacamole-server/statuses/{sha}","languages_url":"https://api.github.com/repos/glyptodon/guacamole-server/languages","stargazers_url":"https://api.github.com/repos/glyptodon/guacamole-server/stargazers","contributors_url":"https://api.github.com/repos/glyptodon/guacamole-server/contributors","subscribers_url":"https://api.github.com/repos/glyptodon/guacamole-server/subscribers","subscription_url":"https://api.github.com/repos/glyptodon/guacamole-server/subscription","commits_url":"https://api.github.com/repos/glyptodon/guacamole-server/commits{/sha}","git_commits_url":"https://api.github.com/repos/glyptodon/guacamole-server/git/commits{/sha}","comments_url":"https://api.github.com/repos/glyptodon/guacamole-server/comments{/number}","issue_comment_url":"https://api.github.com/repos/glyptodon/guacamole-server/issues/comments{/number}","contents_url":"https://api.github.com/repos/glyptodon/guacamole-server/contents/{+path}","compare_url":"https://api.github.com/repos/glyptodon/guacamole-server/compare/{base}...{head}","merges_url":"https://api.github.com/repos/glyptodon/guacamole-server/merges","archive_url":"https://api.github.com/repos/glyptodon/guacamole-server/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/glyptodon/guacamole-server/downloads","issues_url":"https://api.github.com/repos/glyptodon/guacamole-server/issues{/number}","pulls_url":"https://api.github.com/repos/glyptodon/guacamole-server/pulls{/number}","milestones_url":"https://api.github.com/repos/glyptodon/guacamole-server/milestones{/number}","notifications_url":"https://api.github.com/repos/glyptodon/guacamole-server/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/glyptodon/guacamole-server/labels{/name}","releases_url":"https://api.github.com/repos/glyptodon/guacamole-server/releases{/id}","deployments_url":"https://api.github.com/repos/glyptodon/guacamole-server/deployments","created_at":"2013-06-06T17:40:59Z","updated_at":"2016-02-28T21:26:52Z","pushed_at":"2016-03-01T06:02:50Z","git_url":"git://github.com/glyptodon/guacamole-server.git","ssh_url":"git@github.com:glyptodon/guacamole-server.git","clone_url":"https://github.com/glyptodon/guacamole-server.git","svn_url":"https://github.com/glyptodon/guacamole-server","homepage":"http://guac-dev.org/","size":7066,"stargazers_count":821,"watchers_count":821,"language":"C","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":128,"mirror_url":null,"open_issues_count":3,"forks":128,"open_issues":3,"watchers":821,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/glyptodon/guacamole-server/pulls/109"},"html":{"href":"https://github.com/glyptodon/guacamole-server/pull/109"},"issue":{"href":"https://api.github.com/repos/glyptodon/guacamole-server/issues/109"},"comments":{"href":"https://api.github.com/repos/glyptodon/guacamole-server/issues/109/comments"},"review_comments":{"href":"https://api.github.com/repos/glyptodon/guacamole-server/pulls/109/comments"},"review_comment":{"href":"https://api.github.com/repos/glyptodon/guacamole-server/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/glyptodon/guacamole-server/pulls/109/commits"},"statuses":{"href":"https://api.github.com/repos/glyptodon/guacamole-server/statuses/3eec831d7cf1268e554fd804d736e64ec8acd8c4"}}}}