mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
DirtySDK (EA's Dirty Sockets library) will be used for the LiveAPI implementation, and depends on: EABase, EAThread.
990 lines
32 KiB
C
990 lines
32 KiB
C
/*H********************************************************************************/
|
|
/*!
|
|
\File http2.c
|
|
|
|
\Description
|
|
Test the ProtoHttp2 client
|
|
|
|
\Copyright
|
|
Copyright (c) 2016 Electronic Arts Inc.
|
|
|
|
\Version 12/01/2016 (eesponda)
|
|
*/
|
|
/********************************************************************************H*/
|
|
|
|
/*** Include files ****************************************************************/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "DirtySDK/dirtysock/dirtynet.h"
|
|
#include "DirtySDK/dirtysock/netconn.h"
|
|
#include "DirtySDK/proto/protohttp2.h"
|
|
#include "DirtySDK/proto/protossl.h"
|
|
#include "DirtySDK/util/protobufcommon.h"
|
|
#include "DirtySDK/util/protobufwrite.h"
|
|
#include "DirtySDK/util/protobufread.h"
|
|
#include "libsample/zmem.h"
|
|
|
|
#include "testermodules.h"
|
|
|
|
/*** Defines **********************************************************************/
|
|
|
|
//! default address for the grpc server we are testing
|
|
#define DEFAULT_GRPC_SERVER ("http://10.14.141.208:50051")
|
|
|
|
/*** Type Definitions *************************************************************/
|
|
|
|
//! wrapper for the data payloads used for our tests
|
|
typedef struct FixedBufferT
|
|
{
|
|
int32_t iSize;
|
|
uint8_t aData[256];
|
|
} FixedBufferT;
|
|
|
|
//! generator function for data
|
|
typedef FixedBufferT (GenerateFn)(void);
|
|
|
|
//! handle response function
|
|
typedef const uint8_t *(ResponseFn)(const uint8_t *pBuf, int32_t iBufLen);
|
|
|
|
//! location used for grpc tests
|
|
typedef struct LocationT
|
|
{
|
|
uint64_t iLatitude;
|
|
uint64_t iLongitude;
|
|
} LocationT;
|
|
|
|
typedef struct Http2RefT
|
|
{
|
|
ProtoHttp2RefT *pHttp; //!< http2 module ref
|
|
int32_t iStreamId; //!< main stream identifier
|
|
|
|
char strGrpcHost[32]; //!< the default host to run grpc tests
|
|
|
|
uint8_t *pBuf; //!< buffer for reading data
|
|
int32_t iBufSize; //!< size of the buffer
|
|
|
|
FixedBufferT Buffer; //!< buffer for sending data
|
|
int32_t iDataSent; //!< how much data we have sent
|
|
|
|
GenerateFn *pGen; //!< streaming generator fn
|
|
ResponseFn *pResp; //!< response handling fn
|
|
int32_t iIndex; //!< index of the data for client/bi-directional sends
|
|
int32_t iMaxIndex; //!< max index of data
|
|
|
|
uint32_t uTimer; //!< timer to gauge operations
|
|
int32_t iCount; //!< number of bytes downloaded
|
|
int32_t iShow; //!< current bytes show in logging
|
|
} Http2RefT;
|
|
|
|
/*** Variables ********************************************************************/
|
|
|
|
// instance for used in testing
|
|
static Http2RefT _Http2 = { NULL, 0, DEFAULT_GRPC_SERVER, NULL, 0, { 0, { 0 } }, 0, NULL, NULL, 0, 0, 0, 0, 0 };
|
|
|
|
//! list of locations use for RecordRoute RPC
|
|
static const LocationT _aFeatureLocations[] =
|
|
{
|
|
{ 407838351, (uint64_t)-746143763 },
|
|
{ 408122808, (uint64_t)-743999179 },
|
|
{ 413628156, (uint64_t)-749015468 },
|
|
{ 419999544, (uint64_t)-740371136 },
|
|
{ 414008389, (uint64_t)-743951297 },
|
|
{ 419611318, (uint64_t)-746524769 },
|
|
{ 406109563, (uint64_t)-742186778 },
|
|
{ 416802456, (uint64_t)-742370183 },
|
|
{ 412950425, (uint64_t)-741077389 },
|
|
{ 412144655, (uint64_t)-743949739 },
|
|
{ 415736605, (uint64_t)-742847522 },
|
|
{ 413843930, (uint64_t)-740501726 },
|
|
{ 410873075, (uint64_t)-744459023 },
|
|
{ 412346009, (uint64_t)-744026814 },
|
|
{ 402948455, (uint64_t)-747903913 },
|
|
{ 406337092, (uint64_t)-740122226 },
|
|
{ 406421967, (uint64_t)-747727624 },
|
|
{ 416318082, (uint64_t)-749677716 },
|
|
{ 415301720, (uint64_t)-748416257 },
|
|
{ 402647019, (uint64_t)-747071791 },
|
|
{ 412567807, (uint64_t)-741058078 },
|
|
{ 416855156, (uint64_t)-744420597 },
|
|
{ 404663628, (uint64_t)-744820157 },
|
|
{ 407113723, (uint64_t)-749746483 },
|
|
{ 402133926, (uint64_t)-743613249 },
|
|
{ 400273442, (uint64_t)-741220915 },
|
|
{ 411236786, (uint64_t)-744070769 },
|
|
{ 411633782, (uint64_t)-746784970 },
|
|
{ 415830701, (uint64_t)-742952812 },
|
|
{ 413447164, (uint64_t)-748712898 },
|
|
{ 405047245, (uint64_t)-749800722 },
|
|
{ 418858923, (uint64_t)-746156790 },
|
|
{ 417951888, (uint64_t)-748484944 },
|
|
{ 407033786, (uint64_t)-743977337 },
|
|
{ 417548014, (uint64_t)-740075041 },
|
|
{ 410395868, (uint64_t)-744972325 },
|
|
{ 404615353, (uint64_t)-745129803 },
|
|
{ 406589790, (uint64_t)-743560121 },
|
|
{ 414653148, (uint64_t)-740477477 },
|
|
{ 405957808, (uint64_t)-743255336 },
|
|
{ 411733589, (uint64_t)-741648093 },
|
|
{ 412676291, (uint64_t)-742606606 },
|
|
{ 409224445, (uint64_t)-748286738 },
|
|
{ 406523420, (uint64_t)-742135517 },
|
|
{ 401827388, (uint64_t)-740294537 },
|
|
{ 410564152, (uint64_t)-743685054 },
|
|
{ 408472324, (uint64_t)-740726046 },
|
|
{ 412452168, (uint64_t)-740214052 },
|
|
{ 409146138, (uint64_t)-746188906 },
|
|
{ 404701380, (uint64_t)-744781745 },
|
|
{ 409642566, (uint64_t)-746017679 },
|
|
{ 408031728, (uint64_t)-748645385 },
|
|
{ 413700272, (uint64_t)-742135189 },
|
|
{ 404310607, (uint64_t)-740282632 },
|
|
{ 409319800, (uint64_t)-746201391 },
|
|
{ 406685311, (uint64_t)-742108603 },
|
|
{ 419018117, (uint64_t)-749142781 },
|
|
{ 412856162, (uint64_t)-745148837 },
|
|
{ 416560744, (uint64_t)-746721964 },
|
|
{ 405314270, (uint64_t)-749836354 },
|
|
{ 414219548, (uint64_t)-743327440 },
|
|
{ 415534177, (uint64_t)-742900616 },
|
|
{ 406898530, (uint64_t)-749127080 },
|
|
{ 407586880, (uint64_t)-741670168 },
|
|
{ 400106455, (uint64_t)-742870190 },
|
|
{ 400066188, (uint64_t)-746793294 },
|
|
{ 418803880, (uint64_t)-744102673 },
|
|
{ 414204288, (uint64_t)-747895140 },
|
|
{ 414777405, (uint64_t)-740615601 },
|
|
{ 415464475, (uint64_t)-747175374 },
|
|
{ 404062378, (uint64_t)-746376177 },
|
|
{ 405688272, (uint64_t)-749285130 },
|
|
{ 400342070, (uint64_t)-748788996 },
|
|
{ 401809022, (uint64_t)-744157964 },
|
|
{ 404226644, (uint64_t)-740517141 },
|
|
{ 410322033, (uint64_t)-747871659 },
|
|
{ 407100674, (uint64_t)-747742727 },
|
|
{ 418811433, (uint64_t)-741718005 },
|
|
{ 415034302, (uint64_t)-743850945 },
|
|
{ 411349992, (uint64_t)-743694161 },
|
|
{ 404839914, (uint64_t)-744759616 },
|
|
{ 414638017, (uint64_t)-745957854 },
|
|
{ 412127800, (uint64_t)-740173578 },
|
|
{ 401263460, (uint64_t)-747964303 },
|
|
{ 412843391, (uint64_t)-749086026 },
|
|
{ 418512773, (uint64_t)-743067823 },
|
|
{ 404318328, (uint64_t)-740835638 },
|
|
{ 419020746, (uint64_t)-741172328 },
|
|
{ 404080723, (uint64_t)-746119569 },
|
|
{ 401012643, (uint64_t)-744035134 },
|
|
{ 404306372, (uint64_t)-741079661 },
|
|
{ 403966326, (uint64_t)-748519297 },
|
|
{ 405002031, (uint64_t)-748407866 },
|
|
{ 409532885, (uint64_t)-742200683 },
|
|
{ 416851321, (uint64_t)-742674555 },
|
|
{ 406411633, (uint64_t)-741722051 },
|
|
{ 413069058, (uint64_t)-744597778 },
|
|
{ 418465462, (uint64_t)-746859398 },
|
|
{ 411733222, (uint64_t)-744228360 },
|
|
{ 410248224, (uint64_t)-747127767 }
|
|
};
|
|
|
|
/*** Private functions ************************************************************/
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CmdHttp2WriteGrpcHeader
|
|
|
|
\Description
|
|
Encodes the required size of the message into the buffer
|
|
|
|
\Input *pEncoder - the message encoder
|
|
\Input *pPayload - the payload the message was encoded to
|
|
|
|
\Version 07/05/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _CmdHttp2WriteGrpcHeader(ProtobufWriteRefT *pEncoder, FixedBufferT *pPayload)
|
|
{
|
|
pPayload->iSize = ProtobufWriteDestroy(pEncoder);
|
|
// add extra for compression byte
|
|
pPayload->iSize += 1;
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CmdHttp2GetFeature
|
|
|
|
\Description
|
|
Encodes the payload for the GetFeature RPC
|
|
|
|
\Output
|
|
FixedBufferT - the buffer we have encoded
|
|
|
|
\Version 07/05/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static FixedBufferT _CmdHttp2GetFeature(void)
|
|
{
|
|
FixedBufferT Payload;
|
|
ProtobufWriteRefT *pEncoder;
|
|
|
|
/*
|
|
rpc GetFeature(Point) returns (Feature) {}
|
|
|
|
message Point {
|
|
int32 latitude = 1;
|
|
int32 longitude = 2;
|
|
}
|
|
*/
|
|
|
|
ds_memclr(&Payload, sizeof(Payload));
|
|
pEncoder = ProtobufWriteCreate(Payload.aData+1, sizeof(Payload.aData)-1, TRUE);
|
|
|
|
ProtobufWriteVarint(pEncoder, 409146138, 1);
|
|
ProtobufWriteVarint(pEncoder, (uint64_t)-746188906, 2);
|
|
|
|
// write the header
|
|
_CmdHttp2WriteGrpcHeader(pEncoder, &Payload);
|
|
|
|
return(Payload);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CmdHttp2GetFeatureResponse
|
|
|
|
\Description
|
|
Handles the response for the GetFeature RPC
|
|
|
|
\Input *pBuffer - payload
|
|
\Input iBufLen - size of payload
|
|
|
|
\Output
|
|
const uint8_t * - new buffer location past the response
|
|
|
|
\Version 07/05/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static const uint8_t *_CmdHttp2GetFeatureResponse(const uint8_t *pBuffer, int32_t iBufLen)
|
|
{
|
|
int32_t iMsgSize;
|
|
ProtobufReadT Reader, Msg;
|
|
struct {
|
|
char strName[256];
|
|
LocationT Point;
|
|
} Response;
|
|
|
|
ds_memset(&Response, -1, sizeof(Response));
|
|
|
|
/*
|
|
rpc GetFeature(Point) returns (Feature) {}
|
|
|
|
message Point {
|
|
int32 latitude = 1;
|
|
int32 longitude = 2;
|
|
}
|
|
|
|
message Feature {
|
|
string name = 1;
|
|
Point location = 2;
|
|
}
|
|
*/
|
|
|
|
// get message size (skipping compression)
|
|
pBuffer = ProtobufCommonReadSize(pBuffer+1, iBufLen-1, &iMsgSize);
|
|
ProtobufReadInit(&Reader, pBuffer, iMsgSize);
|
|
|
|
ProtobufReadString(&Reader, ProtobufReadFind(&Reader, 1), Response.strName, sizeof(Response.strName));
|
|
if (ProtobufReadMessage(&Reader, ProtobufReadFind(&Reader, 2), &Msg) != NULL)
|
|
{
|
|
Response.Point.iLatitude = ProtobufReadVarint(&Msg, ProtobufReadFind(&Msg, 1));
|
|
Response.Point.iLongitude = ProtobufReadVarint(&Msg, ProtobufReadFind(&Msg, 2));
|
|
}
|
|
|
|
ZPrintf("http2: name (%s), location (%d/%d)\n", Response.strName, Response.Point.iLatitude, Response.Point.iLongitude);
|
|
return(pBuffer+iMsgSize);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CmdHttp2ListFeatures
|
|
|
|
\Description
|
|
Encodes the payload for the ListFeatures RPC
|
|
|
|
\Output
|
|
FixedBufferT - the buffer we have encoded
|
|
|
|
\Version 07/05/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static FixedBufferT _CmdHttp2ListFeatures(void)
|
|
{
|
|
/*
|
|
rpc ListFeatures(Rectangle) returns (stream Feature) {}
|
|
|
|
message Rectangle {
|
|
Point lo = 1;
|
|
Point hi = 2;
|
|
}
|
|
*/
|
|
|
|
FixedBufferT Payload;
|
|
ProtobufWriteRefT *pEncoder;
|
|
|
|
ds_memclr(&Payload, sizeof(Payload));
|
|
pEncoder = ProtobufWriteCreate(Payload.aData+1, sizeof(Payload.aData)-1, TRUE);
|
|
|
|
ProtobufWriteMessageBegin(pEncoder, 1);
|
|
ProtobufWriteVarint(pEncoder, 400000000, 1);
|
|
ProtobufWriteVarint(pEncoder, (uint64_t)-750000000, 2);
|
|
ProtobufWriteMessageEnd(pEncoder);
|
|
|
|
ProtobufWriteMessageBegin(pEncoder, 2);
|
|
ProtobufWriteVarint(pEncoder, 420000000, 1);
|
|
ProtobufWriteVarint(pEncoder, (uint64_t)-730000000, 2);
|
|
ProtobufWriteMessageEnd(pEncoder);
|
|
|
|
// write the header
|
|
_CmdHttp2WriteGrpcHeader(pEncoder, &Payload);
|
|
|
|
return(Payload);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CmdHttp2ListFeaturesResponse
|
|
|
|
\Description
|
|
Handles the response for the ListFeatures RPC
|
|
|
|
\Input *pBuffer - payload
|
|
\Input iBufLen - size of payload
|
|
|
|
\Output
|
|
const uint8_t * - new buffer location past the response
|
|
|
|
\Version 07/05/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static const uint8_t *_CmdHttp2ListFeaturesResponse(const uint8_t *pBuffer, int32_t iBufLen)
|
|
{
|
|
int32_t iMsgSize;
|
|
ProtobufReadT Reader, Msg;
|
|
|
|
struct {
|
|
char strName[256];
|
|
LocationT Point;
|
|
} Response;
|
|
|
|
/*
|
|
rpc ListFeatures(Rectangle) returns (stream Feature) {}
|
|
|
|
message Point {
|
|
int32 latitude = 1;
|
|
int32 longitude = 2;
|
|
}
|
|
|
|
message Feature {
|
|
string name = 1;
|
|
Point location = 2;
|
|
}
|
|
*/
|
|
|
|
// get message size (skipping compression)
|
|
pBuffer = ProtobufCommonReadSize(pBuffer+1, iBufLen-1, &iMsgSize);
|
|
ProtobufReadInit(&Reader, pBuffer, iMsgSize);
|
|
|
|
ProtobufReadString(&Reader, ProtobufReadFind(&Reader, 1), Response.strName, sizeof(Response.strName));
|
|
if (ProtobufReadMessage(&Reader, ProtobufReadFind(&Reader, 2), &Msg) != NULL)
|
|
{
|
|
Response.Point.iLatitude = ProtobufReadVarint(&Msg, ProtobufReadFind(&Msg, 1));
|
|
Response.Point.iLongitude = ProtobufReadVarint(&Msg, ProtobufReadFind(&Msg, 2));
|
|
}
|
|
|
|
ZPrintf("http2: name (%s), location (%d/%d)\n", Response.strName, Response.Point.iLatitude, Response.Point.iLongitude);
|
|
return(pBuffer+iMsgSize);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CmdHttp2RecordRoute
|
|
|
|
\Description
|
|
Encodes the payload for the RecordRoute RPC
|
|
|
|
\Output
|
|
FixedBufferT - the buffer we have encoded
|
|
|
|
\Version 07/05/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static FixedBufferT _CmdHttp2RecordRoute(void)
|
|
{
|
|
/*
|
|
rpc RecordRoute(stream Point) returns (RouteSummary) {}
|
|
|
|
message Point {
|
|
int32 latitude = 1;
|
|
int32 longitude = 2;
|
|
}
|
|
*/
|
|
|
|
FixedBufferT Payload;
|
|
ProtobufWriteRefT *pEncoder;
|
|
const int32_t iIndex = rand() % (sizeof(_aFeatureLocations)/sizeof(_aFeatureLocations[0]));
|
|
|
|
ds_memclr(&Payload, sizeof(Payload));
|
|
pEncoder = ProtobufWriteCreate(Payload.aData+1, sizeof(Payload.aData)-1, TRUE);
|
|
ProtobufWriteVarint(pEncoder, _aFeatureLocations[iIndex].iLatitude, 1);
|
|
ProtobufWriteVarint(pEncoder, _aFeatureLocations[iIndex].iLongitude, 2);
|
|
|
|
// write the header
|
|
_CmdHttp2WriteGrpcHeader(pEncoder, &Payload);
|
|
|
|
return(Payload);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CmdHttp2RecordRouteResponse
|
|
|
|
\Description
|
|
Handles the response for the RecordRoute RPC
|
|
|
|
\Input *pBuffer - payload
|
|
\Input iBufLen - size of payload
|
|
|
|
\Output
|
|
const uint8_t * - new buffer location past the response
|
|
|
|
\Version 07/05/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static const uint8_t *_CmdHttp2RecordRouteResponse(const uint8_t *pBuffer, int32_t iBufLen)
|
|
{
|
|
int32_t iMsgSize;
|
|
ProtobufReadT Reader;
|
|
|
|
struct {
|
|
int32_t iPointCount;
|
|
int32_t iFeatureCount;
|
|
int32_t iDistance;
|
|
int32_t iElapsedTime;
|
|
} Response;
|
|
|
|
/*
|
|
rpc RecordRoute(stream Point) returns (RouteSummary) {}
|
|
|
|
message RouteSummary {
|
|
int32 point_count = 1;
|
|
int32 feature_count = 2;
|
|
int32 distance = 3;
|
|
int32 elapsed_time = 4;
|
|
}
|
|
*/
|
|
|
|
// get message size (skipping compression)
|
|
pBuffer = ProtobufCommonReadSize(pBuffer+1, iBufLen-1, &iMsgSize);
|
|
ProtobufReadInit(&Reader, pBuffer, iMsgSize);
|
|
|
|
Response.iPointCount = (int32_t)ProtobufReadVarint(&Reader, ProtobufReadFind(&Reader, 1));
|
|
Response.iFeatureCount = (int32_t)ProtobufReadVarint(&Reader, ProtobufReadFind(&Reader, 2));
|
|
Response.iDistance = (int32_t)ProtobufReadVarint(&Reader, ProtobufReadFind(&Reader, 3));
|
|
Response.iElapsedTime = (int32_t)ProtobufReadVarint(&Reader, ProtobufReadFind(&Reader, 4));
|
|
|
|
ZPrintf("http2: pointcount %d, featurecount %d, distance %d, elapsedtime %d\n", Response.iPointCount, Response.iFeatureCount, Response.iDistance, Response.iElapsedTime);
|
|
return(pBuffer+iMsgSize);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CmdHttp2RouteChat
|
|
|
|
\Description
|
|
Encodes the payload for the RouteChat RPC
|
|
|
|
\Output
|
|
FixedBufferT - the buffer we have encoded
|
|
|
|
\Version 07/05/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static FixedBufferT _CmdHttp2RouteChat(void)
|
|
{
|
|
/*
|
|
rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
|
|
|
|
message RouteNote {
|
|
Point location = 1;
|
|
string message = 2;
|
|
}
|
|
*/
|
|
|
|
FixedBufferT Payload = { 0, { 0 } };
|
|
int32_t iIndex;
|
|
const char *aMessages[] = { "First message", "Second message", "Third message", "Fourth message" };
|
|
LocationT aLocations[] = { { 0, 0 }, { 0, 1 }, { 1, 0 }, { 0, 0 } };
|
|
|
|
for (iIndex = 0; iIndex < 4; iIndex += 1)
|
|
{
|
|
FixedBufferT Message = { 0, { 0 } };
|
|
ProtobufWriteRefT *pEncoder;
|
|
|
|
pEncoder = ProtobufWriteCreate(Message.aData+1, sizeof(Message.aData)-1, TRUE);
|
|
ProtobufWriteMessageBegin(pEncoder, 1);
|
|
ProtobufWriteVarint(pEncoder, aLocations[iIndex].iLatitude, 1);
|
|
ProtobufWriteVarint(pEncoder, aLocations[iIndex].iLongitude, 2);
|
|
ProtobufWriteMessageEnd(pEncoder);
|
|
ProtobufWriteString(pEncoder, aMessages[iIndex], (signed)strlen(aMessages[iIndex]), 2);
|
|
|
|
_CmdHttp2WriteGrpcHeader(pEncoder, &Message);
|
|
|
|
ds_memcpy(Payload.aData+Payload.iSize, Message.aData, Message.iSize);
|
|
Payload.iSize += Message.iSize;
|
|
}
|
|
|
|
return(Payload);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CmdHttp2RouteChatResponse
|
|
|
|
\Description
|
|
Handles the response for the RouteChat RPC
|
|
|
|
\Input *pBuffer - payload
|
|
\Input iBufLen - size of payload
|
|
|
|
\Output
|
|
const uint8_t * - new buffer location past the response
|
|
|
|
\Version 07/05/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static const uint8_t *_CmdHttp2RouteChatResponse(const uint8_t *pBuffer, int32_t iBufLen)
|
|
{
|
|
int32_t iMsgSize;
|
|
ProtobufReadT Reader, Msg;
|
|
|
|
struct {
|
|
LocationT Point;
|
|
char strMessage[256];
|
|
} Response;
|
|
|
|
/*
|
|
rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
|
|
|
|
message RouteNote {
|
|
Point location = 1;
|
|
string message = 2;
|
|
}
|
|
*/
|
|
|
|
// get message size (skipping compression)
|
|
pBuffer = ProtobufCommonReadSize(pBuffer+1, iBufLen-1, &iMsgSize);
|
|
ProtobufReadInit(&Reader, pBuffer, iMsgSize);
|
|
|
|
if (ProtobufReadMessage(&Reader, ProtobufReadFind(&Reader, 1), &Msg) != NULL)
|
|
{
|
|
Response.Point.iLatitude = ProtobufReadVarint(&Msg, ProtobufReadFind(&Msg, 1));
|
|
Response.Point.iLongitude = ProtobufReadVarint(&Msg, ProtobufReadFind(&Msg, 2));
|
|
}
|
|
ProtobufReadString(&Reader, ProtobufReadFind(&Reader, 2), Response.strMessage, sizeof(Response.strMessage));
|
|
|
|
ZPrintf("http2: location (%d/%d), message (%s)\n", Response.Point.iLatitude, Response.Point.iLongitude, Response.strMessage);
|
|
return(pBuffer+iMsgSize);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CmdHttp2CleaupSend
|
|
|
|
Cleans up the module ref for a request send
|
|
|
|
\Input *pHttp2 - module ref for this test to cleanup
|
|
|
|
\Version 12/01/2016 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _CmdHttp2CleaupSend(Http2RefT *pHttp2)
|
|
{
|
|
ds_memclr(&pHttp2->Buffer, sizeof(pHttp2->Buffer));
|
|
pHttp2->iDataSent = 0;
|
|
pHttp2->pGen = NULL;
|
|
pHttp2->iMaxIndex = 0;
|
|
pHttp2->iIndex = 0;
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CmdHttp2IdleCb
|
|
|
|
\Description
|
|
Update for the http2 testing module
|
|
|
|
\Input *pArgz - environment
|
|
\Input iArgc - standard number of arguments
|
|
\Input *pArgv[] - standard arg list
|
|
|
|
\Version 12/01/2016 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static int32_t _CmdHttp2IdleCb(ZContext *pArgz, int32_t iArgc, char *pArgv[])
|
|
{
|
|
int32_t iResult;
|
|
Http2RefT *pHttp2 = &_Http2;
|
|
|
|
// clean up the ref if needed
|
|
if (iArgc == 0)
|
|
{
|
|
if (pHttp2->pHttp != NULL)
|
|
{
|
|
ProtoHttp2Destroy(pHttp2->pHttp);
|
|
ProtoSSLClrCACerts();
|
|
pHttp2->pHttp = NULL;
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
// try to send data
|
|
if (pHttp2->Buffer.iSize > 0)
|
|
{
|
|
if (pHttp2->iDataSent < pHttp2->Buffer.iSize)
|
|
{
|
|
int32_t iDataSent;
|
|
if ((iDataSent = ProtoHttp2Send(pHttp2->pHttp, pHttp2->iStreamId, pHttp2->Buffer.aData+pHttp2->iDataSent, pHttp2->Buffer.iSize-pHttp2->iDataSent)) < 0)
|
|
{
|
|
return(1);
|
|
}
|
|
pHttp2->iDataSent += iDataSent;
|
|
}
|
|
else if (pHttp2->iIndex < pHttp2->iMaxIndex)
|
|
{
|
|
pHttp2->Buffer = pHttp2->pGen();
|
|
pHttp2->iDataSent = 0;
|
|
pHttp2->iIndex += 1;
|
|
}
|
|
else
|
|
{
|
|
_CmdHttp2CleaupSend(pHttp2);
|
|
ProtoHttp2Send(pHttp2->pHttp, pHttp2->iStreamId, NULL, PROTOHTTP2_STREAM_END);
|
|
}
|
|
}
|
|
|
|
// try to read data
|
|
if (pHttp2->iStreamId != 0)
|
|
{
|
|
ProtoHttpRequestTypeE eRequestType = ProtoHttp2Status(pHttp2->pHttp, pHttp2->iStreamId, 'rtyp', NULL, 0);
|
|
|
|
/* for straight gets we want to use this to measure how fast our downloads are
|
|
other types can be handled as before */
|
|
if (eRequestType == PROTOHTTP_REQUESTTYPE_GET)
|
|
{
|
|
uint8_t strBuf[16*1024];
|
|
while ((iResult = ProtoHttp2Recv(pHttp2->pHttp, pHttp2->iStreamId, strBuf, 1, sizeof(strBuf))) > 0)
|
|
{
|
|
ProtoHttp2Update(pHttp2->pHttp);
|
|
pHttp2->iCount += iResult;
|
|
}
|
|
|
|
if (pHttp2->iCount != pHttp2->iShow)
|
|
{
|
|
ZPrintf("http2: downloaded %d bytes\n", pHttp2->iCount);
|
|
pHttp2->iShow = pHttp2->iCount;
|
|
}
|
|
if (iResult == PROTOHTTP2_RECVDONE || iResult == PROTOHTTP2_RECVHEAD)
|
|
{
|
|
int32_t iTickDiff = NetTickDiff(NetTick(), pHttp2->uTimer);
|
|
|
|
iResult = ProtoHttp2Status(pHttp2->pHttp, pHttp2->iStreamId, 'head', NULL, 0);
|
|
ZPrintf("http2: 'head' %d\n", iResult);
|
|
|
|
iResult = ProtoHttp2Status(pHttp2->pHttp, pHttp2->iStreamId, 'body', NULL, 0);
|
|
ZPrintf("http2: 'body' %d in %.2f seconds (%.3f k/sec)\n", iResult, (float)iTickDiff/1000.0f,
|
|
((float)iResult * 1000.0f) / ((float)iTickDiff * 1024.0f));
|
|
|
|
iResult = ProtoHttp2Status(pHttp2->pHttp, pHttp2->iStreamId, 'done', NULL, 0);
|
|
ZPrintf("http2: 'done' %s\n", iResult ? "TRUE" : "FALSE");
|
|
|
|
ProtoHttp2StreamFree(pHttp2->pHttp, pHttp2->iStreamId);
|
|
pHttp2->iStreamId = 0;
|
|
pHttp2->iCount = pHttp2->iShow = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uint8_t bDone;
|
|
iResult = ProtoHttp2RecvAll(pHttp2->pHttp, pHttp2->iStreamId, pHttp2->pBuf, pHttp2->iBufSize);
|
|
bDone = iResult != PROTOHTTP2_RECVWAIT && iResult != PROTOHTTP2_RECVBUFF;
|
|
|
|
// handle finished
|
|
if (iResult > 0)
|
|
{
|
|
int32_t iBody;
|
|
int32_t iTickDiff = NetTickDiff(NetTick(), pHttp2->uTimer);
|
|
|
|
iResult = ProtoHttp2Status(pHttp2->pHttp, pHttp2->iStreamId, 'head', NULL, 0);
|
|
ZPrintf("http2: 'head' %d\n", iResult);
|
|
|
|
iBody = ProtoHttp2Status(pHttp2->pHttp, pHttp2->iStreamId, 'body', NULL, 0);
|
|
ZPrintf("http2: 'body' %d in %.2f seconds (%.3f k/sec)\n", iBody, (float)iTickDiff/1000.0f,
|
|
((float)iBody * 1000.0f) / ((float)iTickDiff * 1024.0f));
|
|
|
|
iResult = ProtoHttp2Status(pHttp2->pHttp, pHttp2->iStreamId, 'done', NULL, 0);
|
|
ZPrintf("http2: 'done' %s\n", iResult ? "TRUE" : "FALSE");
|
|
|
|
iResult = ProtoHttp2Status(pHttp2->pHttp, pHttp2->iStreamId, 'hres', NULL, 0);
|
|
ZPrintf("http2: 'hres' 0x%08x\n", iResult);
|
|
|
|
// we have received the full response, now we can handle it
|
|
if (pHttp2->pResp != NULL)
|
|
{
|
|
const uint8_t *pCur = pHttp2->pBuf;
|
|
const uint8_t *pEnd = pHttp2->pBuf+iBody;
|
|
while (pCur < pEnd)
|
|
{
|
|
pCur = pHttp2->pResp(pCur, (int32_t)(pEnd-pCur));
|
|
}
|
|
}
|
|
}
|
|
// increase size if needed
|
|
else if (iResult == PROTOHTTP2_RECVBUFF)
|
|
{
|
|
if (pHttp2->iBufSize == 0)
|
|
{
|
|
pHttp2->pBuf = ZMemAlloc(4096);
|
|
pHttp2->iBufSize = 4096;
|
|
}
|
|
else
|
|
{
|
|
uint8_t *pNewBuf = ZMemAlloc(pHttp2->iBufSize * 2);
|
|
ds_memcpy(pNewBuf, pHttp2->pBuf, pHttp2->iBufSize);
|
|
|
|
ZMemFree(pHttp2->pBuf);
|
|
pHttp2->pBuf = pNewBuf;
|
|
pHttp2->iBufSize *= 2;
|
|
}
|
|
|
|
ZPrintf("http2: allocated larger buffer: new size %d\n", pHttp2->iBufSize);
|
|
}
|
|
else if ((iResult == PROTOHTTP2_RECVFAIL) || (iResult == PROTOHTTP2_TIMEOUT))
|
|
{
|
|
iResult = ProtoHttp2Status(pHttp2->pHttp, pHttp2->iStreamId, 'hres', NULL, 0);
|
|
ZPrintf("http2: receive failed (0x%08x)\n", iResult);
|
|
}
|
|
|
|
// cleanup now that we are done
|
|
if (bDone == TRUE)
|
|
{
|
|
ProtoHttp2StreamFree(pHttp2->pHttp, pHttp2->iStreamId);
|
|
pHttp2->iStreamId = 0;
|
|
|
|
ZMemFree(pHttp2->pBuf);
|
|
pHttp2->pBuf = NULL;
|
|
pHttp2->iBufSize = 0;
|
|
pHttp2->pResp = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
// update the ref
|
|
ProtoHttp2Update(pHttp2->pHttp);
|
|
|
|
return(ZCallback(_CmdHttp2IdleCb, 1)); // slow enough to allow us to test abort
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CmdHttp2WriteCb
|
|
|
|
\Description
|
|
Callback when we receive data (if registered)
|
|
|
|
\Input *pState - module state
|
|
\Input *pCbInfo - information about the request
|
|
\Input *pData - data we are receiving
|
|
\Input iDataSize - size of the data
|
|
\Input *pUserData - user specific data
|
|
|
|
\Output
|
|
int32_t - result of the operation
|
|
|
|
\Version 12/01/2016 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static int32_t _CmdHttp2WriteCb(ProtoHttp2RefT *pState, const ProtoHttp2WriteCbInfoT *pCbInfo, const uint8_t *pData, int32_t iDataSize, void *pUserData)
|
|
{
|
|
Http2RefT *pHttp2 = (Http2RefT *)pUserData;
|
|
ZPrintf("received %d\n", iDataSize);
|
|
|
|
// if the request is complete then cleanup the stream
|
|
if ((iDataSize == PROTOHTTP2_RECVDONE) || (iDataSize == PROTOHTTP2_RECVFAIL) || (iDataSize == PROTOHTTP2_TIMEOUT))
|
|
{
|
|
ProtoHttp2StreamFree(pState, pCbInfo->iStreamId);
|
|
pHttp2->iStreamId = 0;
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CmdHttp2CreateGrpcRequest
|
|
|
|
\Description
|
|
Wrapper to create grpc request
|
|
|
|
\Input *pHttp2 - module state
|
|
\Input *pUri - the path of the request
|
|
\Input *pPayloadFn - pointer to function to generate payload data
|
|
\Input iNumPayload - number of entries in array
|
|
\Input *pResponseFn - pointer to function to handle response data
|
|
|
|
\Version 12/01/2016 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _CmdHttp2CreateGrpcRequest(Http2RefT *pHttp2, const char *pUri, GenerateFn *pPayloadFn, int32_t iNumPayloads, ResponseFn *pResponseFn)
|
|
{
|
|
char strUrl[128];
|
|
|
|
// setup url
|
|
ds_snzprintf(strUrl, sizeof(strUrl), "%s/%s", pHttp2->strGrpcHost, pUri);
|
|
|
|
// update headers, we set null first to clear the previous headers
|
|
ProtoHttp2Control(pHttp2->pHttp, 0, 'apnd', 0, 0, NULL);
|
|
ProtoHttp2Control(pHttp2->pHttp, 0, 'apnd', 0, 0, (void *)"te: trailers\r\ncontent-type: application/grpc\r\n");
|
|
|
|
pHttp2->uTimer = NetTick();
|
|
|
|
// create the request
|
|
if (ProtoHttp2Request(pHttp2->pHttp, strUrl, NULL, PROTOHTTP2_STREAM_BEGIN, PROTOHTTP_REQUESTTYPE_POST, &pHttp2->iStreamId) < 0)
|
|
{
|
|
ZPrintf("http2: failed to create request %s\n", pUri);
|
|
return;
|
|
}
|
|
// set the array and num indexies
|
|
pHttp2->pGen = pPayloadFn;
|
|
pHttp2->pResp = pResponseFn;
|
|
pHttp2->iMaxIndex = iNumPayloads;
|
|
// set index to 1 as we always read first entry
|
|
pHttp2->iIndex = 1;
|
|
// read the first entry
|
|
pHttp2->Buffer = pPayloadFn();
|
|
}
|
|
|
|
/*** Public Functions *************************************************************/
|
|
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function CmdHttp2
|
|
|
|
\Description
|
|
Entrypoint for the http2 testing module
|
|
|
|
\Input *pArgz - environment
|
|
\Input iArgc - standard number of arguments
|
|
\Input *pArgv[] - standard arg list
|
|
|
|
\Output
|
|
int32_t - standard return value
|
|
|
|
\Version 12/01/2016 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t CmdHttp2(ZContext *pArgz, int32_t iArgc, char *pArgv[])
|
|
{
|
|
Http2RefT *pHttp2 = &_Http2;
|
|
|
|
// allocate the module if needed
|
|
if (pHttp2->pHttp == NULL)
|
|
{
|
|
if ((pHttp2->pHttp = ProtoHttp2Create(0)) == NULL)
|
|
{
|
|
ZPrintf("http2: could not allocate module state\n");
|
|
return(1);
|
|
}
|
|
}
|
|
|
|
// make sure there are enough parameters
|
|
if (iArgc < 2)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
// close the connection
|
|
if (ds_stricmp(pArgv[1], "close") == 0)
|
|
{
|
|
ProtoHttp2Close(pHttp2->pHttp);
|
|
}
|
|
// update the logging
|
|
else if (ds_stricmp(pArgv[1], "spam") == 0)
|
|
{
|
|
ProtoHttp2Control(pHttp2->pHttp, PROTOHTTP2_INVALID_STREAMID, 'spam', atoi(pArgv[2]), 0, NULL);
|
|
}
|
|
else if (ds_stricmp(pArgv[1], "time") == 0)
|
|
{
|
|
ProtoHttp2Control(pHttp2->pHttp, PROTOHTTP2_INVALID_STREAMID, 'time', atoi(pArgv[2]), 0, NULL);
|
|
}
|
|
else if (ds_stricmp(pArgv[1], "grpc") == 0)
|
|
{
|
|
ds_strnzcpy(pHttp2->strGrpcHost, pArgv[2], sizeof(pHttp2->strGrpcHost));
|
|
}
|
|
|
|
if (pHttp2->iStreamId == 0)
|
|
{
|
|
// handle the normal get/head/options
|
|
if ((ds_stricmp(pArgv[1], "get") == 0) || (ds_stricmp(pArgv[1], "head") == 0) || (ds_stricmp(pArgv[1], "options") == 0))
|
|
{
|
|
// a bit nasty but gets the job done
|
|
ProtoHttpRequestTypeE eRequestType = *pArgv[1] == 'g' ? PROTOHTTP_REQUESTTYPE_GET : *pArgv[1] == 'h' ? PROTOHTTP_REQUESTTYPE_HEAD : PROTOHTTP_REQUESTTYPE_OPTIONS;
|
|
|
|
pHttp2->uTimer = NetTick();
|
|
|
|
if ((iArgc == 4) && (ds_stricmp(pArgv[3], "-cb") == 0))
|
|
{
|
|
ProtoHttp2RequestCb(pHttp2->pHttp, pArgv[2], NULL, 0, eRequestType, &pHttp2->iStreamId, _CmdHttp2WriteCb, &_Http2);
|
|
}
|
|
else
|
|
{
|
|
ProtoHttp2Request(pHttp2->pHttp, pArgv[2], NULL, 0, eRequestType, &pHttp2->iStreamId);
|
|
}
|
|
}
|
|
else if (ds_stricmp(pArgv[1], "test1") == 0)
|
|
{
|
|
_CmdHttp2CreateGrpcRequest(pHttp2, "routeguide.RouteGuide/GetFeature", &_CmdHttp2GetFeature, 0, &_CmdHttp2GetFeatureResponse);
|
|
}
|
|
else if (ds_stricmp(pArgv[1], "test2") == 0)
|
|
{
|
|
_CmdHttp2CreateGrpcRequest(pHttp2, "routeguide.RouteGuide/ListFeatures", &_CmdHttp2ListFeatures, 0, &_CmdHttp2ListFeaturesResponse);
|
|
}
|
|
else if (ds_stricmp(pArgv[1], "test3") == 0)
|
|
{
|
|
_CmdHttp2CreateGrpcRequest(pHttp2, "routeguide.RouteGuide/RecordRoute", &_CmdHttp2RecordRoute, 10, _CmdHttp2RecordRouteResponse);
|
|
}
|
|
else if (ds_stricmp(pArgv[1], "test4") == 0)
|
|
{
|
|
_CmdHttp2CreateGrpcRequest(pHttp2, "routeguide.RouteGuide/RouteChat", &_CmdHttp2RouteChat, 5, _CmdHttp2RouteChatResponse);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ds_stricmp(pArgv[1], "abort") == 0)
|
|
{
|
|
// abort the request
|
|
ProtoHttp2Abort(pHttp2->pHttp, pHttp2->iStreamId);
|
|
|
|
// cleanup send data
|
|
_CmdHttp2CleaupSend(pHttp2);
|
|
|
|
// cleanup stream
|
|
ProtoHttp2StreamFree(pHttp2->pHttp, pHttp2->iStreamId);
|
|
pHttp2->iStreamId = 0;
|
|
}
|
|
}
|
|
|
|
return(ZCallback(_CmdHttp2IdleCb, 1));
|
|
}
|