| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524 |
- /*----------------------------------------------------------------------------*\
- =================================
- y_php - PHP synchronisation.
- =================================
- Description:
- Sends and receives data from a PHP server with shmop installed.
- Legal:
- Version: MPL 1.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
-
- The Original Code is the YSI utils include.
-
- The Initial Developer of the Original Code is Alex "Y_Less" Cole.
- Portions created by the Initial Developer are Copyright (C) 2011
- the Initial Developer. All Rights Reserved.
-
- Contributors:
- ZeeX, koolk, JoeBullet/Google63, g_aSlice/Slice
-
- Thanks:
- JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
- ZeeX - Very productive conversations.
- koolk - IsPlayerinAreaEx code.
- TheAlpha - Danish translation.
- breadfish - German translation.
- Fireburn - Dutch translation.
- yom - French translation.
- 50p - Polish translation.
- Zamaroht - Spanish translation.
- Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes
- for me to strive to better.
- Pixels^ - Running XScripters where the idea was born.
- Matite - Pestering me to release it and using it.
-
- Very special thanks to:
- Thiadmer - PAWN, whose limits continue to amaze me!
- Kye/Kalcor - SA:MP.
- SA:MP Team past, present and future - SA:MP.
-
- Version:
- 0.1
- Changelog:
- 25/02/12:
- First version.
- Functions:
- Stock:
- -
- Inline:
- -
- Variables:
- Global:
- -
- \*----------------------------------------------------------------------------*/
- #include <a_http>
- #include "y_utils"
- #include "internal\y_funcinc"
- #include "y_debug"
- #include "y_timers"
- #include "y_master"
- #include "y_hooks"
- #if !defined PHP_RECEIVE || !defined PHP_SEND
- #error You must define PHP_RECEIVE and PHP_SEND before including y_php.
- #endif
- #define PHP_HEADER_LENGTH (3)
- static stock
- YSI_g_sID = 0,
- //YSI_g_sLen,
- YSI_g_sIndex = PHP_HEADER_LENGTH,
- YSI_g_sBuffer[2048] = "DR=";
- /*
- native PHP_SendString(string:name[], string:value[], bool:priority = false);
- native PHP_SendFloat(string:name[], Float:value, bool:priority = false);
- native PHP_SendBool(string:name[], bool:value, bool:priority = false);
- native PHP_SendInt(string:name[], value, bool:priority = false);
- */
- enum
- {
- e_PHP_SEND_TYPE_STRING,
- e_PHP_SEND_TYPE_FLOAT,
- e_PHP_SEND_TYPE_BOOL,
- e_PHP_SEND_TYPE_INT
- }
- //foreign _PHP_Send(string:name[], string:value[], bool:priority, type);
- forward _PHP_Result(index, response, data[]);
- forward _PHP_Ignore(index, response, data[]);
- stock PHP_SendString(string:name[], string:value[], bool:priority = false)
- {
- if (isnull(value))
- {
- return _PHP_Send(name, NULL, priority, e_PHP_SEND_TYPE_STRING);
- }
- else
- {
- return _PHP_Send(name, value, priority, e_PHP_SEND_TYPE_STRING);
- }
- }
- stock PHP_SendFloat(string:name[], Float:value, bool:priority = false)
- {
- static
- sStr[6];
- PHP_EncodeFloat(_:value, sStr);
- return _PHP_Send(name, sStr, priority, e_PHP_SEND_TYPE_FLOAT);
- }
- stock PHP_SendBool(string:name[], bool:value, bool:priority = false)
- {
- if (value)
- {
- return _PHP_Send(name, "1", priority, e_PHP_SEND_TYPE_BOOL);
- }
- else
- {
- return _PHP_Send(name, "0", priority, e_PHP_SEND_TYPE_BOOL);
- }
- }
- stock PHP_SendInt(string:name[], value, bool:priority = false)
- {
- static
- sStr[6];
- PHP_EncodeInt(value, sStr);
- return _PHP_Send(name, sStr, priority, e_PHP_SEND_TYPE_INT);
- }
- static stock _PHP_Send(string:name[], string:value[], bool:priority, type)
- {
- new
- nlen = strlen(name);
- // Only loops twice max in reality.
- for ( ; ; )
- {
- switch (type)
- {
- case e_PHP_SEND_TYPE_STRING:
- {
- new
- vlen = strlen(value);
- if (vlen + nlen + 7 + YSI_g_sIndex < sizeof (YSI_g_sBuffer))
- {
- static
- sStr[6];
- PHP_EncodeInt(vlen, sStr);
- format(YSI_g_sBuffer[YSI_g_sIndex], sizeof (YSI_g_sBuffer), "%c%s%s%s%c", nlen | 0x80, name, sStr, value, 255);
- YSI_g_sIndex += vlen + nlen + 7;
- if (priority)
- {
- _PHP_ForceSend();
- }
- return 1;
- }
- }
- case e_PHP_SEND_TYPE_FLOAT, e_PHP_SEND_TYPE_INT:
- {
- if (nlen + 7 + YSI_g_sIndex < sizeof (YSI_g_sBuffer))
- {
- format(YSI_g_sBuffer[YSI_g_sIndex], sizeof (YSI_g_sBuffer), "%c%s%s%c", nlen | 0x80, name, value, 255);
- YSI_g_sIndex += nlen + 7;
- if (priority)
- {
- _PHP_ForceSend();
- }
- return 1;
- }
- }
- case e_PHP_SEND_TYPE_BOOL:
- {
- if (nlen + 2 + YSI_g_sIndex < sizeof (YSI_g_sBuffer))
- {
- format(YSI_g_sBuffer[YSI_g_sIndex], sizeof (YSI_g_sBuffer), "%c%s%c", nlen | 0x80, name, value[0]);
- YSI_g_sIndex += nlen + 2;
- if (priority)
- {
- _PHP_ForceSend();
- }
- return 1;
- }
- }
- }
- // Not enough space in the buffer. Send the existing data, reset
- // "YSI_g_sIndex", and try again (just once).
- if (YSI_g_sIndex > PHP_HEADER_LENGTH)
- {
- _PHP_ForceSend();
- }
- else
- {
- break;
- }
- }
- return 0;
- }
- task _PHP_ForceSend[5000]()
- {
- // This is run in all scripts, not just the master one, because there is no
- // "mtask". In retrospect, that seems like an oversight.
- if (YSI_g_sIndex > PHP_HEADER_LENGTH)
- {
- // Send the data.
- HTTP(0, HTTP_POST, PHP_SEND, YSI_g_sBuffer, "_PHP_Ignore");
- YSI_g_sIndex = PHP_HEADER_LENGTH;
- // I don't think this is actually REQUIRED, but does no harm.
- YSI_g_sBuffer[PHP_HEADER_LENGTH] = '\0';
- }
- }
- static stock PHP_EncodeInt(value, dest[])
- {
- dest[0] = (value >> 25 & 0x7F | 0x80);
- dest[1] = (value >> 18 & 0x7F | 0x80);
- dest[2] = (value >> 11 & 0x7F | 0x80);
- dest[3] = (value >> 4 & 0x7F | 0x80);
- dest[4] = (value & 0x0F | 0x80);
- }
- static stock PHP_EncodeFloat(value, dest[])
- {
- dest[0] = (value >> 25 & 0x7F | 0x80);
- dest[1] = (value >> 18 & 0x7F | 0x80);
- dest[2] = (value >> 11 & 0x7F | 0x80);
- dest[3] = (value >> 4 & 0x7F | 0x80);
- // This is the only difference from "PHP_EncodeInt" (0x80 vs 0xC0).
- dest[4] = (value & 0x0F | 0xC0);
- }
- mhook OnScriptInit()
- {
- if (!strcmp(PHP_RECEIVE, "http://", true, 7))
- {
- P:E("PHP_RECEIVE should exclude \"http://\".");
- }
- P:I("Starting PHP Connection...");
- P:I("Note that messages may take a few seconds to get going.");
- //YSI_g_sLen = strlen(PHP_RECEIVE) + 4;
- //SetTimer("_PHP_FireOne", 50, 0);
- // Send '0' only once at server start to reset PHP.
- HTTP(0, HTTP_HEAD, PHP_RECEIVE "?ID=0", "", "_PHP_Result");
- //new TODO;
- defer _PHP_FireOne[500](0, 0);
- defer _PHP_FireOne[5500](0, 0);
- //SetTimer("_PHP_FireOne", 500, 0);
- //SetTimer("_PHP_FireOne", 5500, 0);
- //PHP_FireOne();
- //PHP_FireOne();
- //PHP_FireOne();
- return 1;
- }
- timer _PHP_FireOne[10](res, to)
- {
- static
- sAddr[64]; // = PHP_RECEIVE "?ID=?????&RE=???????????";
- YSI_g_sID = (YSI_g_sID + 1) & 0xFFFF;
- if (YSI_g_sID == 0) YSI_g_sID = 1;
- //valstr(sAddr[YSI_g_sLen], YSI_g_sID);
- format(sAddr, sizeof (sAddr), PHP_RECEIVE "?ID=%d&RE=%d&TO=%d", YSI_g_sID, res, to);
- P:1("_PHP_FireOne request: %s: ", sAddr);
- HTTP(YSI_g_sID, HTTP_GET, sAddr, "", "_PHP_Result");
- }
- static stock PHP_GetNum32(str[])
- {
- return ((str[0] & ~0x80) << 25) | ((str[1] & ~0x80) << 18) | ((str[2] & ~0x80) << 11) | ((str[3] & ~0x80) << 4) | (str[4] & ~0xF0);
- }
- static stock PHP_GetNum8(str[])
- {
- return str[0] & ~0x80;
- }
- static stock PHP_GetNum6(str[])
- {
- return str[0] & ~0x40;
- }
- static stock bool:PHP_GetBool(str[])
- {
- return str[0] == '1';
- }
- public _PHP_Ignore(index, response, data[])
- {
- P:1("_PHP_Ignore: %i, %i, %s", index, response, data);
- return 0;
- }
- public _PHP_Result(index, response, data[])
- {
- P:1("_PHP_Result called: %d %d %s", index, response, data);
- if (response == 200)
- {
- // Fire a replacement.
- //PHP_FireOne();
- if (index)
- {
- new
- res = 0;
- switch (data[0])
- {
- case '1':
- {
- //P:I("PHP: Got response.");
- // Now parse the data.
- //printf(data);
- static
- sFunc[32],
- bool:sTrue = true,
- bool:sFalse = false;
- for (new i = 1, len = strlen(data); i < len; )
- {
- //new
- // flen = PHP_GetNum8(data[i]) + i + 1;
- //data[flen] = '\0';
- //format(sFunc, sizeof (sFunc), "%s@yP_", data[i + 1]);
- //i = flen;
- //printf("%d %d", i, data[i]);
- new
- flen = PHP_GetNum8(data[i++]);
- //printf("%d", flen);
- //data[flen] = '\0';
- format(sFunc, sizeof (sFunc), "%.*s@yP_", flen, data[i]);
- //printf("%s", sFunc);
- i += flen;
- //printf("%d", data[i]);
- if (data[i] & 0x80)
- {
- flen = PHP_GetNum32(data[i]);
- i += 5;
- if (data[i] == 255)
- {
- P:5("_PHP_Result: Got number.");
- // Number.
- /*if (data[i - 1] & 0x40)
- {
- CallRemoteFunction(sFunc, "f", flen);
- }
- else
- {
- CallRemoteFunction(sFunc, "i", flen);
- }*/
- CallRemoteFunction(sFunc, "i", flen);
- ++i;
- }
- else
- {
- P:5("_PHP_Result: Got string.");
- // String.
- flen += i;
- data[flen] = '\0';
- CallRemoteFunction(sFunc, "s", data[i]);
- i = flen + 1;
- }
- }
- else if (data[i] & 0x40)
- {
- sFunc[flen] = '_';
- sFunc[flen + 3] = '@';
- // Function call.
- new
- params = PHP_GetNum6(data[i]),
- n = params * 4 + 8,
- heap = 0;
- static
- sFormat[64];
- ++i;
- sFormat[params] = '\0';
- P:5("_PHP_Result: Got function %s.", sFunc);
- while (params--)
- {
- if (data[i] & 0x80)
- {
- flen = PHP_GetNum32(data[i]);
- i += 5;
- if (data[i] == 255)
- {
- P:5("_PHP_Result: Got number parameter (%d).", flen);
- sFormat[params] = 'i';
- // Number.
- #emit LOAD.S.pri flen
- #emit HEAP 4
- #emit STOR.I
- #emit PUSH.alt
- heap += 4;
- ++i;
- }
- else
- {
- sFormat[params] = 's';
- // String
- flen += i;
- data[flen] = '\0';
- P:5("_PHP_Result: Got string parameter (%d: %s).", flen, data[i]);
- #emit LOAD.S.pri i
- #emit LOAD.S.alt data // Not ADDR.alt.
- #emit IDXADDR
- #emit PUSH.pri
- //CallRemoteFunction(sFunc, "s", data[i]);
- i = flen + 1;
- }
- }
- else if (data[i] == '1')
- {
- P:5("_PHP_Result: Got true parameter.");
- sFormat[params] = 'i';
- #emit PUSH.C sTrue
- ++i;
- }
- else
- {
- P:5("_PHP_Result: Got false parameter.");
- sFormat[params] = 'i';
- #emit PUSH.C sFalse
- ++i;
- }
- }
- P:5("_PHP_Result: Do function call.");
- // Push the static parameters and call the function.
- #emit PUSH.C sFormat
- #emit PUSH.C sFunc
- #emit PUSH.S n
- #emit SYSREQ.C CallRemoteFunction
-
- //n += 4;
- //#emit POP.pri
- // Save the return.
- #emit STOR.S.pri res
- // Clear the stack, including the return.
- #emit LCTRL 4
- #emit LOAD.S.alt n
- #emit ADD
- #emit ADD.C 4
- #emit SCTRL 4
-
- // Clear the heap.
- #emit LCTRL 2
- #emit LOAD.S.alt heap
- #emit SUB
- #emit SCTRL 2
-
- // Have a return.
- }
- else if (data[i] == '1')
- {
- P:5("_PHP_Result: Got true.");
- CallRemoteFunction(sFunc, "i", sTrue);
- ++i;
- }
- else
- {
- P:5("_PHP_Result: Got false.");
- CallRemoteFunction(sFunc, "i", sFalse);
- ++i;
- }
- }
- }
- case '\0':
- {
- P:E("PHP: Empty response.");
- }
- default:
- {
- // Error or unknown.
- switch (data[1])
- {
- case '0':
- {
- P:E("PHP: ID out of bounds.");
- }
- case '1':
- {
- P:E("PHP: Could not open shared memory.");
- }
- case '2':
- {
- //P:E("PHP: ID out of bounds.");
- // Not an error!
- }
- case '3':
- {
- P:F("PHP: Server does not support Shared Memory Extensions (shmop).");
- // Fatal error (one of only two ever)!
- return;
- }
- default:
- {
- P:E("PHP: Unknown error: %s.", data[1]);
- }
- }
- }
- }
- //new TODO;
- defer _PHP_FireOne(res, index);
- }
- }
- else
- {
- defer _PHP_FireOne[5000](0, 0);
- }
- }
- #define phpdata%0(%1) %0@yP_(%1);public%0@yP_(%1)
- #define phpfunc%0(%1) %0_yP@(%1);public%0_yP@(%1)
- #include "internal\y_grouprevert"
|