1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
//! Jokolink allows you to request GW2 MumbleLink over udp socket instead of sharedmemory

//! Joko link is a windows only crate. designed to primarily get the MumbleLink or the window
//! size of the GW2 window via shared memory and expose the data through a socket.
//! It can multiple accessing data of multiple MumbleLinks, and allows multiple clients
//! to request the data. it is single threaded for now.

//! ## Usage:
//! create a new engine with Engine::create(port), it will bind to localhost
//! at that port. and make a request via udp socket or just access the pointer
//! directly. if a key does not exist, Jokolink will create one and store it in the map.
//! beware of too many requests with wrong keys, as that means Joko link will keep all
//! those shared memory segments it created, alive.

//! ### RequestFor:
//! requesting data from Jokolink is easy. send its udp socket a buffer of 64 bytes.
//! the first byte should be an enum (or its u8 value) of what you want to request.
//! the second byte should be the length of the key (utf-8) in bytes
//! followed by the key in valid utf-8 sequence upto a maximum of 60 bytes.

pub mod engine;

use std::net::SocketAddr;

use crate::engine::{mumble_link::MUMBLE_LINK_SIZE, RequestFor, Response};
use engine::Engine;
use num_traits::cast::FromPrimitive;

#[cfg(target_os="windows")]
pub fn start_server(mut engine: Engine) {
    let mut response: [u8; MUMBLE_LINK_SIZE + 2] = [0; MUMBLE_LINK_SIZE + 2];
    let mut request: [u8; 64] = [0; 64];
    loop {
        let (_, s) = engine.socket.recv_from(&mut request).unwrap();
        respond_to_request(&mut engine, &request, &mut response, s);
    }
}
/// parses request, prepares response to store it.
#[cfg(target_os="windows")]
pub fn respond_to_request(engine: &mut Engine, request: &[u8], response: &mut [u8], s: SocketAddr) {
    match RequestFor::from_u8(request[0]) {
        Some(RequestFor::MumbleLinkData) => {
            let key_size = request[1];
            if !(1..=60).contains(&key_size) {
                response[0] = Response::InvalidKey as u8;
                engine.socket.send_to(&response[0..1], s).unwrap();
                return;
            }
            let key_end: usize = (key_size + 2).into();
            let key = match std::str::from_utf8(&request[2..key_end]) {
                Ok(key) => key,
                Err(_e) => {
                    response[0] = Response::InvalidKey as u8;
                    engine.socket.send_to(&response[0..1], s).unwrap();
                    return;
                }
            };

            let handle = engine.get_link_ptr(key);
            unsafe {
                if (*handle).is_valid() {
                    (*handle).copy_bytes_into(&mut response[1..MUMBLE_LINK_SIZE + 1]);
                    response[0] = Response::Success as u8;
                    engine
                        .socket
                        .send_to(&response[..MUMBLE_LINK_SIZE + 1], s)
                        .unwrap();
                } else {
                    response[0] = Response::MumbleLinkNotInit as u8;
                    engine.socket.send_to(&response[0..1], s).unwrap();
                }
            }
        }
        Some(RequestFor::WindowSize) => {
            let key_size = request[1];
            if !(1..=60).contains(&key_size) {
                response[0] = Response::InvalidKey as u8;
                engine.socket.send_to(&response[0..1], s).unwrap();
                return;
            }
            let key_end: usize = (key_size + 2).into();
            let key = match std::str::from_utf8(&request[2..key_end]) {
                Ok(key) => key,
                Err(_e) => {
                    response[0] = Response::InvalidKey as u8;
                    engine.socket.send_to(&response[0..1], s).unwrap();
                    return;
                }
            };

            let handle = engine.get_link_ptr(key);
            unsafe {
                if (*handle).is_valid() {
                    match (*handle).get_win_pos_dim() {
                        Some(win_pos_dim) => {
                            response[0] = Response::Success as u8;
                            win_pos_dim.copy_bytes_into(&mut response[1..17]);
                            engine.socket.send_to(&response[0..17], s).unwrap();
                            return;
                        }
                        None => {
                            response[0] = Response::MumbleLinkNotInit as u8;
                            engine.socket.send_to(&response[0..1], s).unwrap();
                            return;
                        }
                    };
                } else {
                    response[0] = Response::MumbleLinkNotInit as u8;
                    engine.socket.send_to(&response[0..1], s).unwrap();
                }
            }
        }
        _ => {
            response[0] = Response::InvalidRequest as u8;
            engine.socket.send_to(&response[0..1], s).unwrap();
            return;
        }
    }
}