2 * mldonkey.c: MLDonkey stuff for Conky
17 int64 buf_to_int(char *buf, int pos, int size);
18 void int_to_buf(int64 i, char *buf, int pos, int size);
20 #define BUF16_TO_INT(buf, pos) buf_to_int((buf), (pos), 2)
21 #define BUF32_TO_INT(buf, pos) buf_to_int((buf), (pos), 4)
22 #define BUF64_TO_INT(buf, pos) buf_to_int((buf), (pos), 8)
24 #define INT_TO_BUF16(i, buf, pos) int_to_buf((i), (buf), (pos), 2)
25 #define INT_TO_BUF32(i, buf, pos) int_to_buf((i), (buf), (pos), 4)
26 #define INT_TO_BUF64(i, buf, pos) int_to_buf((i), (buf), (pos), 8)
29 mldonkey_config mlconfig;
31 /* Call this function to update the information about mldonkey.
32 * Note that the function will not reconnect to mldonkey if the
33 * pointer to the mldonkey_config has not changed. As it uses static
34 * data, it cannot be used in a multithreaded env.
35 * Returns 1 if connected and info filled, 0 if connected but not filled,
59 Network_info, /* 20 */
69 DownloadedFiles, /* 30 */
79 File_info_v2, /* 40 */
88 Client_stats_v4, /* 49 */
91 #define MLDONKEY_DISCONNECTED 0
92 #define MLDONKEY_CONNECTING 1
93 #define MLDONKEY_AUTHENTICATING 2
94 #define MLDONKEY_CONNECTED 3
96 #define MAX_MESSAGE_LEN 65000
97 static int write_pos = 0;
98 static char write_buf[MAX_MESSAGE_LEN];
99 static char read_buf[MAX_MESSAGE_LEN];
101 static int mldonkey_sock = -1;
102 static int mldonkey_state = MLDONKEY_DISCONNECTED;
103 static mldonkey_config *old_config = NULL;
105 /* int64 ------------------------------ */
107 int64 buf_to_int(char *buf, int pos, int size)
112 for (i = 0; i < size; i++) {
113 res += (buf[pos + i] & 0xFF) << (8 * i);
118 void int_to_buf(int64 i, char *buf, int pos, int size)
122 for (j = 0; j < size; j++) {
123 buf[pos + j] = (i & (-1)) >> (8 * j);
127 /* Write operations --------------------- */
134 void write_int8(int code)
136 write_buf[write_pos++] = code;
139 void write_opcode(int code)
141 write_buf[write_pos++] = code;
144 void write_int16(int code)
146 INT_TO_BUF16(code, write_buf, write_pos);
150 void write_int32(int code)
152 INT_TO_BUF32(code, write_buf, write_pos);
156 void write_int64(int64 code)
158 INT_TO_BUF64(code, write_buf, write_pos);
162 void write_string(char *str)
167 int len = strlen(str);
169 memcpy((void *) (write_buf + write_pos), (void *) str,
176 int write_message(char *mtype)
180 INT_TO_BUF32(write_pos, header, 0);
181 if (4 != write(mldonkey_sock, header, 4) ||
182 write_pos != write(mldonkey_sock, (void *) write_buf,
183 (size_t) write_pos)) {
184 ERR("Error in transmitting %s\n", mtype);
187 /* Immediatly close the connection */
188 close(mldonkey_sock);
189 mldonkey_state = MLDONKEY_DISCONNECTED;
199 /* Read operations ----------------------------*/
203 return read_buf[read_pos++];
208 int i = BUF16_TO_INT(read_buf, read_pos);
215 int i = BUF32_TO_INT(read_buf, read_pos);
222 int64 i = BUF64_TO_INT(read_buf, read_pos);
232 len = BUF16_TO_INT(read_buf, read_pos);
235 buf = (char *) malloc((size_t) len + 1);
236 memmove(read_buf + read_pos, buf, len);
243 /* protocol impl. ----------------------------- */
247 /* This function returns the number of messages read, 0 if it blocks,
249 int cut_messages(int reinit)
252 static int toread = 0;
265 read(mldonkey_sock, read_buf + pos, 4 - pos);
267 if (errno == EAGAIN) {
278 toread = BUF32_TO_INT(read_buf, 0);
283 read(mldonkey_sock, read_buf + pos,
297 /* We have one message !!! */
312 if (mldonkey_sock >= 0)
313 close(mldonkey_sock);
315 mldonkey_state = MLDONKEY_DISCONNECTED;
319 int mldonkey_connect(mldonkey_config * config)
321 if (config != old_config) {
322 struct sockaddr_in sa;
328 /* resolve hostname */
329 memset(&sa, 0, sizeof(sa));
331 if (config->mldonkey_hostname == NULL)
332 config->mldonkey_hostname = "127.0.0.1";
333 if (config->mldonkey_hostname[0] >= '0' &&
334 config->mldonkey_hostname[0] <= '9') {
337 (config->mldonkey_hostname, &sa.sin_addr) == 0)
342 inet_addr(config->mldonkey_hostname);
343 if (sa.sin_addr.s_addr == (unsigned int) -1)
349 hp = gethostbyname(config->mldonkey_hostname);
350 if (hp == (struct hostent *) NULL)
353 (unsigned long) hp->h_addr_list[0];
356 sa.sin_port = htons(config->mldonkey_port);
357 sa.sin_family = AF_INET;
359 if ((mldonkey_sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
360 ERR("Opening socket");
366 (mldonkey_sock, (struct sockaddr *) &sa,
368 if (errno != EAGAIN && errno != EINTR
369 && errno != EINPROGRESS
370 && errno != EWOULDBLOCK) {
371 // ERR("Connection failed");
377 retcode = fcntl(mldonkey_sock, F_GETFL, 0);
379 fcntl(mldonkey_sock, F_SETFL,
380 retcode | O_NONBLOCK) == -1) {
385 mldonkey_state = MLDONKEY_CONNECTING;
392 int mldonkey_can_read()
394 return cut_messages(0);
397 int mldonkey_info_message(mldonkey_info * info)
399 int opcode = read_int16();
406 write_int16(0); /* GUI protocol */
407 write_int32(10); /* Version 10 ! */
408 write_message("GuiProtocol");
410 write_int16(47); /* GUI protocol */
415 write_message("GuiExtensions");
418 write_int16(5); /* Password */
419 write_string(old_config->mldonkey_password);
420 write_message("Password");
425 ERR("Bad Password\n");
430 case Client_stats_v2:
431 case Client_stats_v3:
432 ERR("Client stats format too old...\n");
435 case Client_stats_v4:
436 mldonkey_state = MLDONKEY_CONNECTED;
438 info->upload_counter = read_int64();
439 info->download_counter = read_int64();
440 info->shared_counter = read_int64();
441 info->nshared_files = read_int32();
442 info->tcp_upload_rate = read_int32();
443 info->tcp_download_rate = read_int32();
444 info->udp_upload_rate = read_int32();
445 info->udp_download_rate = read_int32();
446 info->ndownloading_files = read_int32();
447 info->ndownloaded_files = read_int32();
455 int get_mldonkey_status(mldonkey_config * config, mldonkey_info * info)
457 if (mldonkey_connect(config) >= 0) {
458 while (mldonkey_can_read() > 0) {
459 mldonkey_info_message(info);
462 return mldonkey_state;