Skip to content
This repository was archived by the owner on Mar 18, 2025. It is now read-only.

Commit c3fb4cb

Browse files
committed
Cleaning and commenting.
1 parent 273be6c commit c3fb4cb

File tree

1 file changed

+77
-34
lines changed

1 file changed

+77
-34
lines changed

login.c

Lines changed: 77 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
#include <sys/socket.h> // for socket and read
66
#include <errno.h>
77

8+
/*
9+
* Implements the read callback.
10+
* Called when data has been sent by signald and is ready to be handled.
11+
*
12+
* Should probably be moved in another module.
13+
*/
814
void
915
signald_read_cb(gpointer data, gint source, PurpleInputCondition cond)
1016
{
@@ -50,78 +56,103 @@ signald_read_cb(gpointer data, gint source, PurpleInputCondition cond)
5056
}
5157
}
5258

53-
gboolean sockaddr_from_path(struct sockaddr_un * address, const gchar * path) {
54-
memset(address, 0, sizeof(struct sockaddr_un));
55-
address->sun_family = AF_UNIX;
56-
if (strlen(path)-1 > sizeof address->sun_path) {
57-
purple_debug_error(SIGNALD_PLUGIN_ID, "socket path %s exceeds maximum length %lu!\n", path, sizeof address->sun_path); // TODO: show error in ui
58-
return FALSE;
59-
} else {
60-
strcpy(address->sun_path, path);
61-
return TRUE;
62-
}
63-
}
64-
59+
/*
60+
* This struct exchanges data between threads, see @try_connect.
61+
*/
6562
typedef struct {
6663
SignaldAccount *sa;
6764
gchar *socket_path;
6865
gchar *message;
69-
} SignaldConnection;
66+
} SignaldConnectionAttempt;
7067

68+
/*
69+
* See @execute_on_main_thread.
70+
*/
7171
static gboolean
7272
display_connection_error(void *data) {
73-
SignaldConnection *sc = data;
73+
SignaldConnectionAttempt *sc = data;
7474
purple_connection_error(sc->sa->pc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, sc->message);
7575
g_free(sc->message);
7676
g_free(sc);
7777
return FALSE;
7878
}
7979

80+
/*
81+
* See @execute_on_main_thread.
82+
*/
8083
static gboolean
8184
display_debug_info(void *data) {
82-
SignaldConnection *sc = data;
83-
purple_debug_info(SIGNALD_PLUGIN_ID, "%s",sc->message);
85+
SignaldConnectionAttempt *sc = data;
86+
purple_debug_info(SIGNALD_PLUGIN_ID, "%s", sc->message);
8487
g_free(sc->message);
8588
g_free(sc);
8689
return FALSE;
8790
}
8891

92+
/*
93+
* Every function writing to the GTK UI must be executed from the GTK main thread.
94+
* This function is a crutch for wrapping some purple functions:
95+
*
96+
* * purple_debug_info in display_debug_info
97+
* * purple_connection_error in display_connection_error
98+
*
99+
* Can only handle one message string instead of variardic arguments.
100+
*/
101+
static void
102+
execute_on_main_thread(GSourceFunc function, SignaldConnectionAttempt *sc, gchar * message) {
103+
sc->message = message;
104+
purple_timeout_add(0, function, g_memdup2(sc, sizeof *sc));
105+
}
106+
107+
/*
108+
* Tries to connect to a socket at a given location.
109+
* It is ought to be executed in a thread.
110+
* Only in case it does noes not succeed AND is the last thread to stop trying,
111+
* the situation is considered a connection failure.
112+
*/
89113
static void *
90114
do_try_connect(void * arg) {
91-
SignaldConnection * sc = arg;
115+
SignaldConnectionAttempt * sc = arg;
116+
92117
struct sockaddr_un address;
93-
if (sockaddr_from_path(&address, sc->socket_path))
94-
{
118+
if (strlen(sc->socket_path)-1 > sizeof address.sun_path) {
119+
execute_on_main_thread(display_connection_error, sc, g_strdup_printf("socket path %s exceeds maximum length %lu!\n", sc->socket_path, sizeof address.sun_path));
120+
} else {
121+
// convert path to sockaddr
122+
memset(&address, 0, sizeof(struct sockaddr_un));
123+
address.sun_family = AF_UNIX;
124+
strcpy(address.sun_path, sc->socket_path);
125+
95126
// create a socket
96127
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
97128
if (fd < 0) {
98-
sc->message = g_strdup_printf("Could not create socket: %s", strerror(errno));
99-
purple_timeout_add(0, display_connection_error, g_memdup2(sc, sizeof *sc));
129+
execute_on_main_thread(display_connection_error, sc, g_strdup_printf("Could not create socket: %s", strerror(errno)));
100130
} else {
101131
int32_t err = -1;
132+
102133
// connect our socket to signald socket
103134
for(int try = 1; try <= SIGNALD_TIMEOUT_SECONDS && err != 0 && sc->sa->fd == 0; try++) {
104135
err = connect(fd, (struct sockaddr *) &address, sizeof(struct sockaddr_un));
105-
sc->message = g_strdup_printf("Connecting to %s (try #%d)...\n", address.sun_path, try);
106-
purple_timeout_add(0, display_debug_info, g_memdup2(sc, sizeof *sc));
136+
execute_on_main_thread(display_debug_info, sc, g_strdup_printf("Connecting to %s (try #%d)...\n", address.sun_path, try));
107137
sleep(1); // altogether wait SIGNALD_TIMEOUT_SECONDS
108138
}
109139

110140
if (err == 0) {
111141
// successfully connected, tell purple to use our socket
112-
sc->message = g_strdup_printf("Connected to %s.\n", address.sun_path);
113-
purple_timeout_add(0, display_debug_info, g_memdup2(sc, sizeof *sc));
142+
execute_on_main_thread(display_debug_info, sc, g_strdup_printf("Connected to %s.\n", address.sun_path));
114143
sc->sa->fd = fd;
115144
sc->sa->watcher = purple_input_add(fd, PURPLE_INPUT_READ, signald_read_cb, sc->sa);
116145
}
117146
if (sc->sa->fd == 0) {
118-
sc->message = g_strdup_printf("No connection to %s after %d tries.\n", address.sun_path, SIGNALD_TIMEOUT_SECONDS);
119-
purple_timeout_add(0, display_debug_info, g_memdup2(sc, sizeof *sc));
120-
sc->sa->socket_paths_count--;
147+
// no concurrent connection attempt has been successful by now
148+
execute_on_main_thread(display_debug_info, sc, g_strdup_printf("No connection to %s after %d tries.\n", address.sun_path, SIGNALD_TIMEOUT_SECONDS));
149+
150+
sc->sa->socket_paths_count--; // this tread gives up trying
151+
// NOTE: although unlikely, it is possible that above decrement and other modifications or checks happen concurrently.
152+
// TODO: use a mutex where appropriate.
121153
if (sc->sa->socket_paths_count == 0) {
122-
123-
sc->message = g_strdup("Unable to connect to any socket location.");
124-
purple_timeout_add(0, display_connection_error, g_memdup2(sc, sizeof *sc));
154+
// no trying threads are remaining
155+
execute_on_main_thread(display_connection_error, sc, sc->message = g_strdup("Unable to connect to any socket location."));
125156
}
126157
}
127158
}
@@ -131,16 +162,28 @@ do_try_connect(void * arg) {
131162
return NULL;
132163
}
133164

165+
/*
166+
* Starts a connection attempt in background.
167+
*/
134168
static void
135169
try_connect(SignaldAccount *sa, gchar *socket_path) {
136-
SignaldConnection *sc = g_new0(SignaldConnection, 1);
170+
SignaldConnectionAttempt *sc = g_new0(SignaldConnectionAttempt, 1);
137171
sc->sa = sa;
138172
sc->socket_path = socket_path;
139173
pthread_t try_connect_thread;
140-
// TODO: handle error int err =
141-
pthread_create(&try_connect_thread, NULL, do_try_connect, (void*)sc);
174+
int err = pthread_create(&try_connect_thread, NULL, do_try_connect, (void*)sc);
175+
if (err != 0) {
176+
gchar *errmsg = g_strdup_printf("Could not create thread for connecting in background: %s", strerror(err));
177+
purple_connection_error(sa->pc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, errmsg);
178+
g_free(errmsg);
179+
}
142180
}
143181

182+
/*
183+
* Connect to signald socket.
184+
* Tries multiple possible default socket location at once in background.
185+
* In case the user has explicitly defined a socket location, only that one is considered.
186+
*/
144187
void
145188
signald_connect_socket(SignaldAccount *sa) {
146189
purple_connection_set_state(sa->pc, PURPLE_CONNECTION_CONNECTING);

0 commit comments

Comments
 (0)