Initial Commit
This commit is contained in:
commit
e465875622
48
src/db/database.h
Normal file
48
src/db/database.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* database.h
|
||||
*
|
||||
* Created on: Nov 18, 2012
|
||||
* Author: Naim
|
||||
*
|
||||
* This is just a API implementation; Actual management is done in the driver_*.c source.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DATABASE_H_
|
||||
#define DATABASE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct dbConnection dbConnection;
|
||||
|
||||
int db_open (dbConnection **, char *cStr);
|
||||
int db_close (dbConnection *);
|
||||
|
||||
typedef struct {
|
||||
uint8_t *peer_id;
|
||||
uint64_t downloaded;
|
||||
uint64_t uploaded;
|
||||
uint64_t left;
|
||||
|
||||
uint32_t ip; // currently only support IPv4.
|
||||
uint16_t port;
|
||||
} db_peerEntry;
|
||||
|
||||
// adds a peer to the torrent's list.
|
||||
int db_add_peer (dbConnection *, uint8_t [20], db_peerEntry*);
|
||||
|
||||
/*
|
||||
* lst: pointer to an array whose maximum size is passed to sZ.
|
||||
* sZ returns the amount of peers returned.
|
||||
*/
|
||||
int db_load_peers (dbConnection *, uint8_t [20], db_peerEntry **lst, int *sZ);
|
||||
|
||||
int db_get_stats (dbConnection *, uint8_t [20], uint32_t *seeders, uint32_t *leechers, uint32_t *completed);
|
||||
|
||||
/**
|
||||
* Calculates Stats, Removes expired data.
|
||||
*/
|
||||
int db_cleanup (dbConnection *);
|
||||
|
||||
#endif /* DATABASE_H_ */
|
177
src/db/driver_sqlite.c
Normal file
177
src/db/driver_sqlite.c
Normal file
|
@ -0,0 +1,177 @@
|
|||
#include "database.h"
|
||||
|
||||
#include <sqlite3.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
struct dbConnection
|
||||
{
|
||||
sqlite3 *db;
|
||||
HANDLE janitor;
|
||||
};
|
||||
|
||||
static const char hexadecimal[] = "0123456789abcdef";
|
||||
|
||||
static void _to_hex_str (uint8_t hash[20], char *data)
|
||||
{
|
||||
int i;
|
||||
for (i = 0;i < 20;i++)
|
||||
{
|
||||
data[i * 2] = hexadecimal[hash[i] / 16];
|
||||
data[i * 2 + 1] = hexadecimal[hash[i] % 16];
|
||||
}
|
||||
data[40] = '\0';
|
||||
}
|
||||
|
||||
static int _db_make_torrent_table (sqlite3 *db, char *hash)
|
||||
{
|
||||
char sql [2000];
|
||||
sql[0] = '\0';
|
||||
|
||||
strcat(sql, "CREATE TABLE IF NOT EXISTS '");
|
||||
strcat(sql, hash);
|
||||
strcat (sql, "' (");
|
||||
|
||||
strcat (sql, "peer_id blob(20) UNIQUE,"
|
||||
"ip blob(4),"
|
||||
"port blob(2),"
|
||||
"uploaded blob(8)," // uint64
|
||||
"downloaded blob(8),"
|
||||
"left blob(8),"
|
||||
"last_seen INTEGER(8)");
|
||||
|
||||
strcat(sql, ")");
|
||||
|
||||
// create table.
|
||||
char *err_msg;
|
||||
int r = sqlite3_exec(db, sql, NULL, NULL, &err_msg);
|
||||
printf("E:%s\n", err_msg);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void _db_setup (sqlite3 *db)
|
||||
{
|
||||
sqlite3_exec(db, "CREATE TABLE stats ("
|
||||
"info_hash blob(20),"
|
||||
"completed INTEGER DEFAULT 0,"
|
||||
"leechers INTEGER DEFAULT 0,"
|
||||
"seeders INTEGER DEFAULT 0"
|
||||
")", NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
int db_open (dbConnection **db, char *cStr)
|
||||
{
|
||||
FILE *f = fopen (cStr, "rb");
|
||||
int doSetup = 0;
|
||||
if (f == NULL)
|
||||
doSetup = 1;
|
||||
else
|
||||
fclose (f);
|
||||
|
||||
*db = malloc (sizeof(struct dbConnection));
|
||||
int r = sqlite3_open (cStr, &((*db)->db));
|
||||
if (doSetup)
|
||||
_db_setup((*db)->db);
|
||||
|
||||
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int db_close (dbConnection *db)
|
||||
{
|
||||
int r = sqlite3_close(db->db);
|
||||
free (db);
|
||||
return r;
|
||||
}
|
||||
|
||||
int db_add_peer (dbConnection *db, uint8_t info_hash[20], db_peerEntry *pE)
|
||||
{
|
||||
char xHash [50]; // we just need 40 + \0 = 41.
|
||||
|
||||
char *hash = xHash;
|
||||
_to_hex_str(info_hash, hash);
|
||||
|
||||
_db_make_torrent_table(db->db, hash);
|
||||
|
||||
sqlite3_stmt *stmt;
|
||||
|
||||
char sql [1000];
|
||||
sql[0] = '\0';
|
||||
strcat(sql, "REPLACE INTO '");
|
||||
strcat(sql, hash);
|
||||
strcat(sql, "' (peer_id,ip,port,uploaded,downloaded,left,last_seen) VALUES (?,?,?,?,?,?,?)");
|
||||
|
||||
sqlite3_prepare(db->db, sql, -1, &stmt, NULL);
|
||||
|
||||
sqlite3_bind_blob(stmt, 1, pE->peer_id, 20, NULL);
|
||||
sqlite3_bind_blob(stmt, 2, &pE->ip, 4, NULL);
|
||||
sqlite3_bind_blob(stmt, 3, &pE->port, 2, NULL);
|
||||
sqlite3_bind_blob(stmt, 4, &pE->uploaded, 8, NULL);
|
||||
sqlite3_bind_blob(stmt, 5, &pE->downloaded, 8, NULL);
|
||||
sqlite3_bind_blob(stmt, 6, &pE->left, 8, NULL);
|
||||
sqlite3_bind_int64(stmt, 7, time(NULL));
|
||||
|
||||
int r = sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int db_load_peers (dbConnection *db, uint8_t info_hash[20], db_peerEntry **lst, int *sZ)
|
||||
{
|
||||
char sql [1000];
|
||||
sql[0] = '\0';
|
||||
|
||||
char hash [50];
|
||||
_to_hex_str(info_hash, hash);
|
||||
|
||||
strcat(sql, "SELECT ip,port FROM '");
|
||||
strcat(sql, hash);
|
||||
strcat(sql, "' LIMIT ?");
|
||||
|
||||
sqlite3_stmt *stmt;
|
||||
sqlite3_prepare(db->db, sql, -1, &stmt, NULL);
|
||||
sqlite3_bind_int(stmt, 1, *sZ);
|
||||
|
||||
int i = 0;
|
||||
int r;
|
||||
|
||||
while (1)
|
||||
{
|
||||
r = sqlite3_step(stmt);
|
||||
if (r == SQLITE_ROW)
|
||||
{
|
||||
lst[i]->ip = sqlite3_column_int(stmt, 0);
|
||||
lst[i]->port = sqlite3_column_int(stmt, 1);
|
||||
i++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
*sZ = i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int db_get_stats (dbConnection *db, uint8_t hash[20], uint32_t *seeders, uint32_t *leechers, uint32_t *completed)
|
||||
{
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int db_cleanup (dbConnection *db)
|
||||
{
|
||||
printf("Cleanup...\n");
|
||||
|
||||
sqlite3_stmt *stmt;
|
||||
|
||||
return 0;
|
||||
}
|
52
src/main.c
Normal file
52
src/main.c
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
============================================================================
|
||||
Name : udpBitTorrentTracker.c
|
||||
Author :
|
||||
Version :
|
||||
Copyright :
|
||||
Description : Hello World in C, Ansi-style
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
//#include <winsock2.h>
|
||||
//#include <windows.h>
|
||||
#include "multiplatform.h"
|
||||
|
||||
#include "udpTracker.h"
|
||||
#include "tools.h"
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
||||
printf("UDP BitTorrentTracker\t\tCopyright: (C) 2012 Naim Abda.\n\n");
|
||||
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
WSAStartup(MAKEWORD(2, 2), &wsadata);
|
||||
#endif
|
||||
|
||||
udpServerInstance usi;
|
||||
UDPTracker_init(&usi, 6969, 1);
|
||||
|
||||
if (UDPTracker_start(&usi) != 0)
|
||||
{
|
||||
printf("Error While trying to start server.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
system("pause");
|
||||
printf("\n");
|
||||
|
||||
UDPTracker_destroy(&usi);
|
||||
|
||||
#ifdef WIN32
|
||||
WSACleanup();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
26
src/multiplatform.h
Normal file
26
src/multiplatform.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#elif defined (linux)
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define SOCKET int
|
||||
#define DWORD uint64_t
|
||||
typedef struct hostent HOSTENT;
|
||||
typedef struct sockaddr SOCKADDR;
|
||||
typedef struct sockaddr_in SOCKADDR_IN;
|
||||
typedef struct in_addr IN_ADDR;
|
||||
typedef struct hostent HOSTENT;
|
||||
typedef void* LPVOID;
|
||||
typedef void (LPTHREAD_START_ROUTINE)(LPVOID);
|
||||
typedef void* HANDLE;
|
||||
#define IPPROTO_UDP 0 // no protocol set.. SOCK_DGRAM is enough.
|
||||
|
||||
#endif
|
||||
|
17
src/tools.c
Normal file
17
src/tools.c
Normal file
|
@ -0,0 +1,17 @@
|
|||
#include "tools.h"
|
||||
|
||||
uint64_t m_hton64 (uint64_t n)
|
||||
{
|
||||
uint64_t r = m_hton32 (n & 0xffffffff);
|
||||
r <<= 32;
|
||||
r |= m_hton32 (n & 0xffffffff00000000);
|
||||
return r;
|
||||
}
|
||||
|
||||
uint32_t m_hton32 (uint32_t n)
|
||||
{
|
||||
uint32_t r = m_hton16 (n & 0xffff);
|
||||
r <<= 16;
|
||||
r |= m_hton16 (n & 0xffff0000);
|
||||
return r;
|
||||
}
|
19
src/tools.h
Normal file
19
src/tools.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* tools.h
|
||||
*
|
||||
* Created on: Nov 18, 2012
|
||||
* Author: Naim
|
||||
*/
|
||||
|
||||
#ifndef TOOLS_H_
|
||||
#define TOOLS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define m_hton16(n) htons(n)
|
||||
|
||||
uint32_t m_hton32 (uint32_t n);
|
||||
|
||||
uint64_t m_hton64 (uint64_t n);
|
||||
|
||||
#endif /* TOOLS_H_ */
|
230
src/udpTracker.c
Normal file
230
src/udpTracker.c
Normal file
|
@ -0,0 +1,230 @@
|
|||
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include "udpTracker.h"
|
||||
#include "tools.h"
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <winerror.h>
|
||||
|
||||
#define FLAG_RUNNING 0x01
|
||||
#define UDP_BUFFER_SIZE 256
|
||||
|
||||
static DWORD _thread_start (LPVOID);
|
||||
|
||||
void UDPTracker_init (udpServerInstance *usi, uint16_t port, uint8_t threads)
|
||||
{
|
||||
usi->port = port;
|
||||
usi->thread_count = threads;
|
||||
usi->threads = malloc (sizeof(HANDLE) * threads);
|
||||
usi->flags = 0;
|
||||
}
|
||||
|
||||
void UDPTracker_destroy (udpServerInstance *usi)
|
||||
{
|
||||
db_close(usi->conn);
|
||||
free (usi->threads);
|
||||
}
|
||||
|
||||
int UDPTracker_start (udpServerInstance *usi)
|
||||
{
|
||||
SOCKET sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (sock == INVALID_SOCKET)
|
||||
return 1;
|
||||
|
||||
int r;
|
||||
|
||||
SOCKADDR_IN recvAddr;
|
||||
|
||||
recvAddr.sin_addr.S_un.S_addr = 0L;
|
||||
recvAddr.sin_family = AF_INET;
|
||||
recvAddr.sin_port = htons (usi->port);
|
||||
|
||||
BOOL yup = TRUE;
|
||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&yup, sizeof(BOOL));
|
||||
|
||||
r = bind (sock, (SOCKADDR*)&recvAddr, sizeof(SOCKADDR_IN));
|
||||
|
||||
if (r == SOCKET_ERROR)
|
||||
{
|
||||
closesocket (sock);
|
||||
return 2;
|
||||
}
|
||||
|
||||
printf("SOCK=%d\n", sock);
|
||||
usi->sock = sock;
|
||||
|
||||
db_open(&usi->conn, "tracker.db");
|
||||
|
||||
usi->flags |= FLAG_RUNNING;
|
||||
int i;
|
||||
for (i = 0;i < usi->thread_count; i++)
|
||||
{
|
||||
printf("Starting Thread %d of %u\n", (i + 1), usi->thread_count);
|
||||
usi->threads[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)_thread_start, (LPVOID)usi, 0, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t _get_connID (SOCKADDR_IN *remote)
|
||||
{
|
||||
int base = time(NULL);
|
||||
base /= 3600; // changes every day.
|
||||
|
||||
uint64_t x = base;
|
||||
x += remote->sin_addr.S_un.S_addr;
|
||||
return x;
|
||||
}
|
||||
|
||||
static int _send_error (udpServerInstance *usi, SOCKADDR_IN *remote, uint32_t transactionID, char *msg)
|
||||
{
|
||||
struct udp_error_response error;
|
||||
error.action = htonl(3);
|
||||
error.transaction_id = transactionID;
|
||||
error.message = msg;
|
||||
|
||||
|
||||
int msg_sz = 4 + 4 + 1 + strlen(msg);
|
||||
|
||||
char buff [msg_sz];
|
||||
memcpy(buff, &error, 8);
|
||||
int i;
|
||||
for (i = 8;i <= msg_sz;i++)
|
||||
{
|
||||
buff[i] = msg[i - 8];
|
||||
}
|
||||
|
||||
printf("ERROR SENT\n");
|
||||
sendto(usi->sock, buff, msg_sz, 0, (SOCKADDR*)remote, sizeof(*remote));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _handle_connection (udpServerInstance *usi, SOCKADDR_IN *remote, char *data)
|
||||
{
|
||||
ConnectionRequest *req = (ConnectionRequest*)data;
|
||||
|
||||
ConnectionResponse resp;
|
||||
resp.action = htonl(0);
|
||||
resp.transaction_id = req->transaction_id;
|
||||
resp.connection_id = _get_connID(remote);
|
||||
|
||||
int r = sendto(usi->sock, (char*)&resp, sizeof(ConnectionResponse), 0, (SOCKADDR*)remote, sizeof(SOCKADDR_IN));
|
||||
|
||||
printf("_h_c=%d\n", r);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _handle_announce (udpServerInstance *usi, SOCKADDR_IN *remote, char *data)
|
||||
{
|
||||
AnnounceRequest *req = (AnnounceRequest*)data;
|
||||
|
||||
if (req->connection_id != _get_connID(remote))
|
||||
{
|
||||
printf("ConnID mismatch.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
db_peerEntry pE;
|
||||
pE.downloaded = req->downloaded;
|
||||
pE.uploaded = req->uploaded;
|
||||
pE.left = req->left;
|
||||
pE.peer_id = req->peer_id;
|
||||
pE.ip = req->ip_address;
|
||||
pE.port = req->port;
|
||||
|
||||
db_add_peer(usi->conn, req->info_hash, &pE);
|
||||
|
||||
|
||||
// _send_error(usi, remote, req->transaction_id, "Not Implemented :-(.");
|
||||
|
||||
int q = 30;
|
||||
if (req->num_want >= 1)
|
||||
q = min (q, req->num_want);
|
||||
|
||||
db_peerEntry *peers = malloc (sizeof(db_peerEntry) * q);
|
||||
db_load_peers(usi->conn, req->info_hash, &peers, &q);
|
||||
printf("%d peers found.\n", q);
|
||||
|
||||
int bSize = 20; // header is 20 bytes
|
||||
bSize += (6 * q); // + 6 bytes per peer.
|
||||
|
||||
uint8_t buff [bSize];
|
||||
|
||||
AnnounceResponse *resp = (AnnounceResponse*)buff;
|
||||
resp->action = htonl(1);
|
||||
resp->interval = htonl ( 1800 );
|
||||
resp->leechers = htonl( 1);
|
||||
resp->seeders = 0;
|
||||
resp->transaction_id = req->transaction_id;
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0;i < q;i++)
|
||||
{
|
||||
int x = i * 6;
|
||||
// network byte order!!!
|
||||
buff[20 + x] = ((peers[i].ip & (0xff << 24)) >> 24);
|
||||
buff[21 + x] = ((peers[i].ip & (0xff << 16)) >> 16);
|
||||
buff[22 + x] = ((peers[i].ip & (0xff << 8)) >> 8);
|
||||
buff[23 + x] = (peers[i].ip & 0xff);
|
||||
|
||||
buff[24 + x] = ((peers[i].port & (0xff << 8)) >> 8);
|
||||
buff[25 + x] = (peers[i].port & 0xff);
|
||||
|
||||
printf("%u.%u.%u.%u:%u\n", buff[20 + x], buff[21 + x], buff[22 + x], buff[23 + x], peers[i].port);
|
||||
}
|
||||
|
||||
free (peers);
|
||||
|
||||
return sendto(usi->sock, (char*)buff, bSize, 0, (SOCKADDR*)remote, sizeof(SOCKADDR_IN));
|
||||
}
|
||||
|
||||
// returns 1 if connection request. returns 2 if announce. returns 3 if scrape.
|
||||
static int _resolve_request (udpServerInstance *usi, SOCKADDR_IN *remote, char *data)
|
||||
{
|
||||
ConnectionRequest *cR;
|
||||
cR = (ConnectionRequest*)data;
|
||||
|
||||
uint32_t action = htonl(cR->action);
|
||||
|
||||
printf("ACTION=%d\n", action);
|
||||
|
||||
if (action == 0)
|
||||
return _handle_connection(usi, remote, data);
|
||||
else if (action == 1)
|
||||
return _handle_announce(usi, remote, data);
|
||||
else
|
||||
{
|
||||
_send_error(usi, remote, cR->transaction_id, "Method not implemented.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD _thread_start (LPVOID arg)
|
||||
{
|
||||
udpServerInstance *usi = arg;
|
||||
|
||||
SOCKADDR_IN remoteAddr;
|
||||
int addrSz = sizeof (SOCKADDR_IN);
|
||||
int r;
|
||||
|
||||
char *tmpBuff = malloc (UDP_BUFFER_SIZE); // 98 is the maximum request size.
|
||||
|
||||
while ((usi->flags & FLAG_RUNNING) > 0)
|
||||
{
|
||||
fflush(stdout);
|
||||
// peek into the first 12 bytes of data; determine if connection request or announce request.
|
||||
r = recvfrom(usi->sock, tmpBuff, UDP_BUFFER_SIZE, 0, (SOCKADDR*)&remoteAddr, &addrSz);
|
||||
printf("RECV:%d\n", r);
|
||||
r = _resolve_request(usi, &remoteAddr, tmpBuff);
|
||||
printf("R=%d\n", r);
|
||||
}
|
||||
|
||||
free (tmpBuff);
|
||||
|
||||
return 0;
|
||||
}
|
89
src/udpTracker.h
Normal file
89
src/udpTracker.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* udpTracker.h
|
||||
*
|
||||
* Created on: Nov 14, 2012
|
||||
* Author: Naim
|
||||
*/
|
||||
|
||||
#ifndef UDPTRACKER_H_
|
||||
#define UDPTRACKER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "multiplatform.h"
|
||||
#include "db/database.h"
|
||||
|
||||
struct udp_connection_request
|
||||
{
|
||||
uint64_t connection_id;
|
||||
uint32_t action;
|
||||
uint32_t transaction_id;
|
||||
};
|
||||
|
||||
struct udp_connection_response
|
||||
{
|
||||
uint32_t action;
|
||||
uint32_t transaction_id;
|
||||
uint64_t connection_id;
|
||||
};
|
||||
|
||||
struct udp_announce_request
|
||||
{
|
||||
uint64_t connection_id;
|
||||
uint32_t action;
|
||||
uint32_t transaction_id;
|
||||
uint8_t info_hash [20];
|
||||
uint8_t peer_id [20];
|
||||
uint64_t downloaded;
|
||||
uint64_t left;
|
||||
uint64_t uploaded;
|
||||
uint32_t event;
|
||||
uint32_t ip_address;
|
||||
uint32_t key;
|
||||
int32_t num_want;
|
||||
uint16_t port;
|
||||
};
|
||||
|
||||
struct udp_announce_response
|
||||
{
|
||||
uint32_t action;
|
||||
uint32_t transaction_id;
|
||||
uint32_t interval;
|
||||
uint32_t leechers;
|
||||
uint32_t seeders;
|
||||
|
||||
uint8_t *peer_list_data;
|
||||
};
|
||||
|
||||
struct udp_error_response
|
||||
{
|
||||
uint32_t action;
|
||||
uint32_t transaction_id;
|
||||
char *message;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SOCKET sock;
|
||||
uint16_t port;
|
||||
|
||||
uint8_t thread_count;
|
||||
|
||||
uint8_t flags;
|
||||
|
||||
HANDLE *threads;
|
||||
|
||||
dbConnection *conn;
|
||||
} udpServerInstance;
|
||||
|
||||
typedef struct udp_connection_request ConnectionRequest;
|
||||
typedef struct udp_connection_response ConnectionResponse;
|
||||
typedef struct udp_announce_request AnnounceRequest;
|
||||
typedef struct udp_announce_response AnnounceResponse;
|
||||
typedef struct udp_error_response ErrorResponse;
|
||||
|
||||
void UDPTracker_init (udpServerInstance *, uint16_t port, uint8_t threads);
|
||||
void UDPTracker_destroy (udpServerInstance *);
|
||||
|
||||
int UDPTracker_start (udpServerInstance *);
|
||||
|
||||
#endif /* UDPTRACKER_H_ */
|
Loading…
Reference in a new issue