// September 2015 // Levee Patroller / Dijk Patrouille // This source file is (c) by Deltares. This source file is open source but only available to select users. Do not redistribute without written permission of Stichting Deltares, Delft, The Netherlands. // This header has been automatically generated. class TcpLinkClient extends TcpLink; var PlayerController PC; //reference to our player controller var string TargetHost; //URL or P address of web server var int TargetPort; //port you want to use for the link var string path; //path to file you want to request var string requesttext; //data we will send //var int score; //score the player controller will send us var bool send; //to switch between sending and getting requests var string username; var string password; var string messagetype; var string data; var string computername; // Session id, user and computername are send after logging in once. var string sessionid; var GUIPage menu; var string totaltext; var int blockcount; event PostBeginPlay() { super.PostBeginPlay(); } function ResolveMe() //removes having to send a host { Resolve(targethost); } event Resolved( IpAddr Addr ) { // The hostname was resolved succefully Log("[TcpLinkClient] "$TargetHost$" resolved to "$ IpAddrToString(Addr)); // Make sure the correct remote port is set, resolving doesn't set // the port value of the IpAddr structure Addr.Port = TargetPort; totaltext = ""; //dont comment out this log because it rungs the function bindport Log("[TcpLinkClient] Bound to port: "$ BindPort() ); if (!Open(Addr)) { Log("[TcpLinkClient] Open failed"); } else { Log("[TcpLinkClient] Opened"); } } event ResolveFailed() { Log("[TcpLinkClient] Unable to resolve "$TargetHost); // You could retry resolving here if you have an alternative // remote host. //send failed message to scaleform UI // JunHud(JunPlayerController(PC).myHUD).JunMovie.CallSetHTML("Failed"); } event Opened() { local array cname_in; local array cname_base64; local array lookup; local string sha1pw; // A connection was established Log("[TcpLinkClient] event opened"); Log("[TcpLinkClient] Sending simple HTTP query"); totaltext = ""; //The HTTP GET request //char(13) and char(10) are carrage returns and new lines if(send == false) { Log("Send = false"); SendText("GET /"$path$" HTTP/1.0"); SendText(chr(13)$chr(10)); SendText("Host: "$TargetHost); SendText(chr(13)$chr(10)); SendText("Connection: Close"); SendText(chr(13)$chr(10)$chr(13)$chr(10)); } else if(send == true) { cname_in.length = 1; cname_in[0] = computername; Base64EncodeLookupTable(lookup); cname_base64 = Base64Encode(cname_in, lookup); Log("computer: " $ cname_base64[0]); // Do not send password anymore if we have a sessionid. if (len(sessionid) > 0) { requesttext = "u=" $ username $ "&sid=" $sessionid $ "&c=" $ cname_base64[0] $ "&type=" $ messagetype $ "&data=" $data ; } else { // Only send SHA1's sha1pw = class'SHA1Hash'.static.GetStringHashString("levee_salt_"$password); requesttext = "u=" $ username $ "&p=" $ sha1pw $ "&c=" $ cname_base64[0] $ "&type=" $ messagetype $ "&data=" $data ; //log(requesttext); } //Log(requesttext); SendText("POST /"$path$" HTTP/1.0"$chr(13)$chr(10)); SendText("Host: "$TargetHost$chr(13)$chr(10)); SendText("User-Agent: HTTPTool/1.0"$Chr(13)$Chr(10)); SendText("Content-Type: application/x-www-form-urlencoded"$chr(13)$chr(10)); //we use the length of our requesttext to tell the server //how long our content is SendText("Content-Length: "$len(requesttext)$Chr(13)$Chr(10)); SendText(chr(13)$chr(10)); SendText(requesttext); SendText(chr(13)$chr(10)); SendText("Connection: Close"); SendText(chr(13)$chr(10)$chr(13)$chr(10)); Log("text send"); } Log("[TcpLinkClient] end HTTP query"); } event Closed() { // In this case the remote client should have automatically closed // the connection, because we requested it in the HTTP request. Log("[TcpLinkClient] event closed: " $ messagetype $ " content length: " $ len(totaltext)); GeoPlayercontroller(PC).ReceiveClosed(messagetype, totaltext); // After the connection was closed we could establish a new // connection using the same TcpLink instance. } event ReceivedText( string Text ) { local AssociativeArray A; //local AssociativeArrayIterator ai; local int pos; local string newtext; local array parts; local int i; local array comps; // receiving some text, note that the text includes line breaks // Log("[TcpLinkClient] ReceivedText:: "$Text); //we dont want the header info, so we split the string after two new lines //newtext = Split(Text, chr(13)$chr(10)$chr(13)$chr(10), true); // Find position of double newline: pos = InStr(Text, chr(13)$chr(10)$chr(13)$chr(10)); newtext = Mid(Text, pos+4); // Skip header message ([type] is always the first): pos = InStr(newtext, chr(13)$chr(10)); totaltext = totaltext $ "block" $blockcount $ " " $Mid(newtext, pos+2); Split2(newtext, chr(13)$chr(10), parts, true); // construct a new, initially empty associative array A = new(None) class'AssociativeArray'; for(i = 0; i < parts.Length; i++) { Split2(parts[i], "=", comps, true); if (comps.length == 1) { parts.length = parts.length+1; parts[parts.length-1] = ""; } if (comps.length >= 2) { // Log("item: " $ comps[0] $ " value: " $comps[1]); // Insert value in dictionary: A.insert(comps[0], comps[1]); } } // Log("[TcpLinkClient] SplitText:: " $newtext); // Store return messagetype //messagetype = A.lookup("type"); GeoPlayercontroller(PC).ReceivedData(A); blockcount++; // JunHud(JunPlayerController(PC).myHUD).JunMovie.CallSetHTML(Text); //First we will recieve data from the server via GET if (send == false) { //send data to our UI // JunHud(JunPlayerController(PC).myHUD).JunMovie.CallSetHTML(Text); send = true; //next time we resolve, we will send player score } } static final function int Split2(coerce string src, string delim, out array parts, optional bool ignoreEmpty, optional string quotechar) { local string temp; Parts.Remove(0, Parts.Length); if (delim == "" || Src == "" ) return 0; while (src != "") { temp = StrShift(src, delim, quotechar); if (temp == "") { if (!ignoreEmpty) { parts.length = parts.length+1; parts[parts.length-1] = temp; } } else { parts.length = parts.length+1; parts[parts.length-1] = temp; } } return parts.length; } static final function string StrShift(out string line, string delim, optional string quotechar) { local int delimpos, quotepos; local string result; if ( quotechar != "" && Left(line, Len(quotechar)) == quotechar ) { do { quotepos = InstrFrom(line, quotechar, quotepos + 1); } until (quotepos == -1 || quotepos + Len(quotechar) == Len(line) || Mid(line, quotepos + len(quotechar), len(delim)) == delim); } if ( quotepos != -1 ) { delimpos = InstrFrom(line, delim, quotepos); } else { delimpos = Instr(line, delim); } if (delimpos == -1) { result = line; line = ""; } else { result = Left(line,delimpos); line = Mid(line,delimpos+len(delim)); } if ( quotechar != "" && Left(result, Len(quotechar)) == quotechar ) { result = Mid(result, Len(quotechar), Len(result)-(Len(quotechar)*2)); } return result; } // InStr starting from an offset static final function int InStrFrom(coerce string StrText, coerce string StrPart, optional int OffsetStart) { local int OffsetPart; OffsetPart = InStr(Mid(StrText, OffsetStart), StrPart); if (OffsetPart >= 0) OffsetPart += OffsetStart; return OffsetPart; } static final function array Base64Encode(array indata, out array B64Lookup) { local array result; local int i, dl, n; local string res; local array inp; local array outp; if (B64Lookup.length != 64) Base64EncodeLookupTable(B64Lookup); // convert string to byte array for (n = 0; n < indata.length; n++) { res = indata[n]; outp.length = 0; inp.length = 0; for (i = 0; i < len(res); i++) { inp[inp.length] = Asc(Mid(res, i, 1)); } dl = inp.length; // fix byte array if ((dl%3) == 1) { inp[inp.length] = 0; inp[inp.length] = 0; } if ((dl%3) == 2) { inp[inp.length] = 0; } i = 0; while (i < dl) { outp[outp.length] = B64Lookup[(inp[i] >> 2)]; outp[outp.length] = B64Lookup[((inp[i]&3)<<4) | (inp[i+1]>>4)]; outp[outp.length] = B64Lookup[((inp[i+1]&15)<<2) | (inp[i+2]>>6)]; outp[outp.length] = B64Lookup[(inp[i+2]&63)]; i += 3; } // pad result if ((dl%3) == 1) { outp[outp.length-1] = "="; outp[outp.length-2] = "="; } if ((dl%3) == 2) { outp[outp.length-1] = "="; } res = ""; for (i = 0; i < outp.length; i++) { res = res$outp[i]; } result[result.length] = res; } return result; } /** Decode a base64 encoded string */ static final function array Base64Decode(array indata) { local array result; local int i, dl, n, padded; local string res; local array inp; local array outp; // convert string to byte array for (n = 0; n < indata.length; n++) { res = indata[n]; outp.length = 0; inp.length = 0; padded = 0; for (i = 0; i < len(res); i++) { dl = Asc(Mid(res, i, 1)); // convert base64 ascii to base64 index if ((dl >= 65) && (dl <= 90)) dl -= 65; // cap alpha else if ((dl >= 97) && (dl <= 122)) dl -= 71; // low alpha else if ((dl >= 48) && (dl <= 57)) dl += 4; // digits else if (dl == 43) dl = 62; else if (dl == 47) dl = 63; else if (dl == 61) padded++; inp[inp.length] = dl; } dl = inp.length; i = 0; while (i < dl) { outp[outp.length] = Chr((inp[i] << 2) | (inp[i+1] >> 4)); outp[outp.length] = Chr(((inp[i+1]&15)<<4) | (inp[i+2]>>2)); outp[outp.length] = Chr(((inp[i+2]&3)<<6) | (inp[i+3])); i += 4; } outp.length = outp.length-padded; res = ""; for (i = 0; i < outp.length; i++) { res = res$outp[i]; } result[result.length] = res; } return result; } /** Generate the base 64 encode lookup table */ static final function Base64EncodeLookupTable(out array LookupTable) { local int i; for (i = 0; i < 26; i++) { LookupTable[i] = Chr(i+65); } for (i = 0; i < 26; i++) { LookupTable[i+26] = Chr(i+97); } for (i = 0; i < 10; i++) { LookupTable[i+52] = Chr(i+48); } LookupTable[62] = "+"; LookupTable[63] = "/"; } defaultproperties { TargetHost="leveepatroller.deltares.nl" TargetPort=80 //default for HTTP path = "index.php/leveecontrol/process_leveeusercheck" username = "" password = "" messagetype = "" send = true blockcount=0 }