Login Code

From libopenmetaverse - libomv - Developer Wiki

Jump to: navigation, search

This code uses the Practical C++ Sockets wrapper library, available here: http://cs.ecs.baylor.edu/~donahoo/practical/CSockets/practical/

 
#include <iostream>
#include <string>
#include <curl/curl.h>
 
#include "PracticalSocket.h"
 
using namespace std;
 
#define VERSION    "myslclient 0.0.1"
#define EMAIL    "your@email.here"
#define SERVER_URL "https://login.agni.lindenlab.com/cgi-bin/login.cgi"
 
typedef struct login_parameters {
 string session_id;
 string secure_session_id;
 string start_location;
 string first_name;
 string last_name;
 int region_x;
 int region_y;
 string home;
 string message;
 int circuit_code;
 int sim_port;
 string sim_ip;
 string look_at;
 string agent_id;
 int seconds_since_epoch;
} login_parameters;
 
struct login_packet {
    char priority;
    char counter[3];
    unsigned int id;
    char agent_id[16];
    char unknown[20];
};
 
// This should be a 24-bit number
unsigned char counter = 1;
 
#define isdigit(c) (c >= '0' && c <= '9')
 
__inline static int atoin(char *s, unsigned int n)
{
 int i = 0;
 while (isdigit(*s) && n) {
  i = i*10 + *(s++) - '0';
  --n;
 }
 return i;
}
 
static int hex2num(char c)
{
    if (c >= '0' && c <= '9')
     return c - '0';
    if (c >= 'a' && c <= 'f')
        return c - 'a' + 10;
    if (c >= 'A' && c <= 'F')
        return c - 'A' + 10;
    return -1;
}
 
static int hex2byte(const char* hex)
{
    int a, b;
 
    a = hex2num(*hex++);
 if (a < 0)
        return -1;
 
    b = hex2num(*hex++);
 if (b < 0)
        return -1;
 
    return (a << 4) | b;
}
 
int hexstr2bin(const char* hex, char* buf, size_t len)
{
 unsigned int i;
 unsigned char a;
 const char* ipos = hex;
 char* opos = buf;
 
 for (i = 0; i < len; i++) {
  a = hex2byte(ipos);
  if (a < 0)
   return -1;
  *opos++ = a;
  ipos += 2;
 }
 
 return 0;
}
 
string get_string_value(char* buffer, const char* name)
{
 char* pos = strstr(buffer, name);
 char* pos2 = NULL;
 unsigned int i = 0;
 string value = "";
 
 if (pos) {
  if (pos = strstr(pos, "<string>")) {
   pos += 8;
 
   if (pos2 = strstr(pos, "</string>")) {
    value = string(pos);
    value = value.substr(0, (pos2 - pos));
   }
  }
 }
 
 // Replace newline characters
 i = value.find_first_of('\n');
 while (i != string::npos) {
  value.replace(i, 1, " ");
  i = value.find_first_of('\n', i);
 }
 
 return value;
}
 
unsigned int get_int_value(char* buffer, const char* name)
{
 char* pos = strstr(buffer, name);
 char* pos2 = NULL;
 unsigned int value = 0;
 
 if (pos) {
  if (pos = strstr(pos, "<i4>")) {
   pos += 4;
 
   if (pos2 = strstr(pos, "</i4>")) {
    if (pos2 > pos) {
     value = atoin(pos, (int)(pos2 - pos));
    }
   }
  }
 }
 
 return value;
}
 
string packed_uuid(string uuid)
{
 if (uuid.length() == 36) {
  uuid.erase(8, 1);
  uuid.erase(12, 1);
  uuid.erase(16, 1);
  uuid.erase(20, 1);
 } else if (uuid.length() != 32) {
  uuid = "";
 }
 
 return uuid;
}
 
int login_to_sim(struct login_parameters login)
{
 char* payload;
 int payload_len;
 char recv_buffer[2048];
 int recv_message_len;
 string source_address;
 unsigned short source_port;
 struct login_packet packet;
 
 packet.priority = 0x40;
 packet.counter[0] = 0x00;
 packet.counter[1] = 0x00;
 packet.counter[2] = counter;
 packet.id = 0x0300FFFF;
 hexstr2bin(packed_uuid(login.agent_id).c_str(), packet.agent_id, 16);
 
 payload = (char*)&packet.priority;
 payload_len = 44;
 
 try {
  UDPSocket sock;
 
  sock.sendTo(payload, payload_len, login.sim_ip, login.sim_port); // We only send one packet, and the last 20 bytes are bad. Help!
 
  for (;;) {
   // Block until receive message from a client
   recv_message_len = sock.recvFrom(recv_buffer, 2048, source_address, source_port);
     
   cout << "Received packet from " << source_address << ":"
     << source_port << endl;
   
   //sock.sendTo(echoBuffer, recvMsgSize, sourceAddress, sourcePort);
  }
 } catch (SocketException &e) {
  cerr << e.what() << endl;
  return -1;
 }
 
 return 0;
}
 
size_t login_reply(void *buffer, size_t size, size_t nmemb, void *userp)
{
 char* reply = (char*)buffer;
 string msg;
 struct login_parameters login;
 
 msg = get_string_value(reply, "<name>reason</name>");
 if (msg.length()) {
  cout << "Login failed.\nReason: " << msg << "\n";
 
  msg = get_string_value(reply, "<name>message</name>");
  if (msg.length()) {
   cout << "Message: " << msg << "\n";
  } else {
   cout << "Couldn't find an error message, dumping server response\n\n" << reply << "\n";
  }
 } else {
  msg = get_string_value(reply, "login</name><value><string>true");
  if (msg.length()) {
   cout << "Login successful\n";
 
   // Put all of the login parameters in to our struct
   login.session_id = get_string_value(reply, "<name>session_id</name>");
   login.secure_session_id = get_string_value(reply, "<name>secure_session_id</name>");
   login.start_location = get_string_value(reply, "<name>start_location</name>");
   login.first_name = get_string_value(reply, "<name>first_name</name>");
   login.last_name = get_string_value(reply, "<name>last_name</name>");
   login.region_x = get_int_value(reply, "<name>region_x</name>");
   login.region_y = get_int_value(reply, "<name>region_y</name>");
   login.home = get_string_value(reply, "<name>home</name>");
   login.message = get_string_value(reply, "<name>message</name>");
   login.circuit_code = get_int_value(reply, "<name>circuit_code</name>");
   login.sim_port = get_int_value(reply, "<name>sim_port</name>");
   login.sim_ip = get_string_value(reply, "<name>sim_ip</name>");
   login.look_at = get_string_value(reply, "<name>look_at</name>");
   login.agent_id = get_string_value(reply, "<name>agent_id</name>");
   login.seconds_since_epoch = get_int_value(reply, "<name>seconds_since_epoch</name>");
 
   login_to_sim(login);
  } else {
   cout << "Unknown login error, dumping server response\n\n" << reply << "\n";
  }
 }
 
 return nmemb;
}
 
int main(int const argc, const char** const argv)
{
 CURL* curl;
 CURLcode response;
 char login_error[CURL_ERROR_SIZE] = {0x00};
 struct curl_slist* headers = NULL;
 string login_request;
 string first = "First";
 string last = "Last";
 string passwd = "password_hash_here";
 string mac = "00:D0:5D:36:0B:34";
 
 login_request = "<?xml version=\"1.0\"?><methodCall><methodName>login_to_simulator</methodName><params><param><value><struct>"
        "<member><name>first</name><value><string>" + first + "</string></value></member>"
        "<member><name>last</name><value><string>" + last + "</string></value></member>"
        "<member><name>passwd</name><value><string>" + passwd + "</string></value></member>"
        "<member><name>start</name><value><string>last</string></value></member>"
        "<member><name>major</name><value><string>1</string></value></member>"
        "<member><name>minor</name><value><string>9</string></value></member>"
        "<member><name>patch</name><value><string>0</string></value></member>"
        "<member><name>build</name><value><string>21</string></value></member>"
        "<member><name>platform</name><value><string>Win</string></value></member>"
        "<member><name>mac</name><value><string>" + mac + "</string></value></member>"
        "<member><name>viewer_digest</name><value><string>68920a26-9f41-b742-a5e6-db6a713dcd96</string></value></member>"
        "<member><name>user-agent</name><value><string>" + VERSION + "</string></value></member>"
     "<member><name>author</name><value><string>" + EMAIL + "</string></value></member>"
        "</struct></value></param></params></methodCall>";
 
 curl = curl_easy_init();
 
 if (curl) {
  headers = curl_slist_append(headers, "Accept-Encoding: gzip");
  headers = curl_slist_append(headers, "Content-Type: text/xml");
 
  curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, login_error);
  curl_easy_setopt(curl, CURLOPT_URL, SERVER_URL);
  curl_easy_setopt(curl, CURLOPT_TIMEOUT, 9);
  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, login_request.c_str());
  curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, login_request.length());
  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, login_reply);
 
  response = curl_easy_perform(curl);
  
  if (response) {
   cout << "Error connecting to the login server.\n" << login_error << "\n";
  }
 
  curl_slist_free_all(headers);
  curl_easy_cleanup(curl);
 }
 
 return 0;
}