/* mldonkey tools: Quick'n Dirty Lib to access mldonkey core. * Copyright (c) 2004 Christophe Badoit * * Original Author: Christophe Badoit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place, Suite 330, Boston, MA 02111-1307 USA * */ /* Quick'n Dirty Lib to access mldonkey core. * Made for Gkremldk, a gkrellm plugin. * * Please send me feedback if you ever use it :-) * * Based on * - http://www.g2gui.net/wiki/index.php/GuiProtocol * - http://royale.zerezo.com/jmoule/protocol.php * - and tcpdump ! :-) * */ #include #include #include #include #include #include #include #include #include "mldonkeytools.h" // debug - dump the buffer buf of length len, prefixed with msg void dumpBuf(char *msg, char *buf, int len) { int i; printf("[%s] DUMP %d chars:", msg, len); for (i = 0; i < len; i++) { if (i % 16 == 0) printf("\n%.4d", i); if (i % 8 == 0) printf(" "); if (i % 2 == 0) printf(" "); printf("%.2X ", buf[i] & 255); } printf("\n"); } /* assert we can read/write ahead n chars in the msg */ int canAdvance(donkeyMsg *m, int n) { if (m->pos + n > MAX_MSG_LEN) return 0; return 1; } /* Write functions */ void writeByte(donkeyMsg *m, unsigned char c) { if (!canAdvance(m, 1)) return; m->payload[m->pos] = c; m->pos = m->pos + 1; } void writeInt(donkeyMsg *m, unsigned short int i) { char c; if (!canAdvance(m, 2)) return; c = i & 255; writeByte(m, c); c = (i >> 8) & 255; writeByte(m, c); } void writeLong(donkeyMsg *m, unsigned int l) { char c; if (!canAdvance(m, 4)) return; int i; for (i = 0; i < 32; i += 8) { c = (l >> i) & 255; writeByte(m, c); } } void writeLong64(donkeyMsg *m, unsigned long l) { char c; if (!canAdvance(m, 8)) return; int i; for (i = 0; i < 64; i += 8) { c = (l >> i) & 255; writeByte(m, c); } } void writeString(donkeyMsg *m, char *string) { int length = strlen(string); if (!canAdvance(m, length + 2)) return; writeInt(m, length); memcpy(m->payload + m->pos, string, length); m->pos = m->pos + length; } // Send a donkey message into the socket. int sendMsg(int sockfd, donkeyMsg *m) { m->size = m->pos - 4; m->pos = 0; writeLong(m, m->size); DUMP_BUF("<<<", m->payload, m->size + 4); return write(sockfd, m->payload, m->size + 4); } /* Read functions */ unsigned char readByte(donkeyMsg *m) { unsigned char c; if (!canAdvance(m, 1)) return 0; c = m->payload[m->pos]; m->pos = m->pos + 1; return c; } unsigned short int readInt(donkeyMsg *m) { unsigned char c; unsigned short int i; if (!canAdvance(m, 2)) return 0; c = readByte(m); i = c; c = readByte(m); i += c << 8; return i; } unsigned int readLong(donkeyMsg *m) { unsigned char c; unsigned int l = 0; int i; if (!canAdvance(m, 4)) return 0; for (i = 0; i < 32; i += 8) { c = readByte(m); l += c << i; } return l; } unsigned long readLong64(donkeyMsg *m) { unsigned char c; unsigned long l = 0; int i; if (!canAdvance(m, 8)) return 0; for (i = 0; i < 64; i += 8) { c = readByte(m); l += c << i; } return l; } char* readString(donkeyMsg *m) { unsigned short int length; char *s; if (!canAdvance(m, 2)) return NULL; length = readInt(m); if (!canAdvance(m, length)) return NULL; s = malloc(length + 1); memcpy(s, m->payload + m->pos, length); s[length] = '\0'; m->pos = m->pos + length; return s; } /* Read a donkey message from a socket */ int readMsg(int sockfd, donkeyMsg *m) { int n, i; unsigned long sizeRead; char buf[4]; unsigned char c; m->size = 0; sizeRead = 0; while (sizeRead != 4) { n = read(sockfd, buf + sizeRead, 4 - sizeRead); if (n <= 0) { /* printf("ERROR reading payload from socket : %d\n", n);*/ return n; } sizeRead += n; } for (i = 0; i < 4; i ++) { c = buf[i]; m->size += c << i*8; } m->payload = malloc(m->size); sizeRead = 0; while (sizeRead != m->size) { n = read(sockfd, m->payload + sizeRead, m->size - sizeRead); if (n <= 0) { /* printf("ERROR reading payload from socket: %d\n", n);*/ return n; } sizeRead += n; } DUMP_BUF(">>>>", m->payload, m->size); m->pos=0; m->opcode = readInt(m); return m->size; } /* Prepare a message for sending, giving the opcode */ void prepareMsg(donkeyMsg *m, short int opcode) { m->opcode = opcode; m->size = 0; m->pos = 4; // leave some place for length m->payload = malloc(MAX_MSG_LEN); writeInt(m, m->opcode); } /* Free payload from a message */ void freeMsg(donkeyMsg *m) { free(m->payload); } /* Tempt to connect to a core. return 1 on success, 0 on failure */ int donkeyConnect(int *sockfd, char *host, int portno, char *login, char *password) { struct sockaddr_in serv_addr; struct hostent *server; donkeyMsg msg; *sockfd = socket(AF_INET, SOCK_STREAM, 0); if (*sockfd < 0) return 0; server = gethostbyname(host); if (server == NULL) { /* fprintf(stderr,"ERROR, no such host\n");*/ return 0; } bzero((char *) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length); serv_addr.sin_port = htons(portno); if (connect(*sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { /* perror("donkeyConnect");*/ return 0; } readMsg(*sockfd, &msg); freeMsg(&msg); // send version prepareMsg(&msg, 0); writeLong(&msg, 0x19); sendMsg(*sockfd, &msg); freeMsg(&msg); // login prepareMsg(&msg, 52); writeString(&msg, password); writeString(&msg, login); sendMsg(*sockfd, &msg); freeMsg(&msg); return 1; }