Various optimalisations to improve performance. More coming soon.
This commit is contained in:
parent
24a3bcd8db
commit
4140b04608
7 changed files with 243 additions and 50 deletions
55
lib/dtsc.cpp
55
lib/dtsc.cpp
|
@ -86,6 +86,59 @@ bool DTSC::Stream::parsePacket(std::string & buffer){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attempts to parse a packet from the given Socket::Buffer.
|
||||||
|
/// Returns true if successful, removing the parsed part from the buffer.
|
||||||
|
/// Returns false if invalid or not enough data is in the buffer.
|
||||||
|
/// \arg buffer The Socket::Buffer to attempt to parse.
|
||||||
|
bool DTSC::Stream::parsePacket(Socket::Buffer & buffer){
|
||||||
|
uint32_t len;
|
||||||
|
static bool syncing = false;
|
||||||
|
if (buffer.available(8)){
|
||||||
|
std::string header_bytes = buffer.copy(8);
|
||||||
|
if (memcmp(header_bytes.c_str(), DTSC::Magic_Header, 4) == 0){
|
||||||
|
len = ntohl(((uint32_t *)header_bytes.c_str())[1]);
|
||||||
|
if (!buffer.available(len+8)){return false;}
|
||||||
|
unsigned int i = 0;
|
||||||
|
std::string wholepacket = buffer.remove(len+8);
|
||||||
|
metadata = JSON::fromDTMI((unsigned char*)wholepacket.c_str() + 8, len, i);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (memcmp(header_bytes.c_str(), DTSC::Magic_Packet, 4) == 0){
|
||||||
|
len = ntohl(((uint32_t *)header_bytes.c_str())[1]);
|
||||||
|
if (!buffer.available(len+8)){return false;}
|
||||||
|
buffers.push_front(JSON::Value());
|
||||||
|
unsigned int i = 0;
|
||||||
|
std::string wholepacket = buffer.remove(len+8);
|
||||||
|
buffers.front() = JSON::fromDTMI((unsigned char*)wholepacket.c_str() + 8, len, i);
|
||||||
|
datapointertype = INVALID;
|
||||||
|
if (buffers.front().isMember("data")){
|
||||||
|
datapointer = &(buffers.front()["data"].strVal);
|
||||||
|
}else{
|
||||||
|
datapointer = 0;
|
||||||
|
}
|
||||||
|
if (buffers.front().isMember("datatype")){
|
||||||
|
std::string tmp = buffers.front()["datatype"].asString();
|
||||||
|
if (tmp == "video"){datapointertype = VIDEO;}
|
||||||
|
if (tmp == "audio"){datapointertype = AUDIO;}
|
||||||
|
if (tmp == "meta"){datapointertype = META;}
|
||||||
|
if (tmp == "pause_marker"){datapointertype = PAUSEMARK;}
|
||||||
|
}
|
||||||
|
while (buffers.size() > buffercount){buffers.pop_back();}
|
||||||
|
advanceRings();
|
||||||
|
syncing = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#if DEBUG >= 2
|
||||||
|
if (!syncing){
|
||||||
|
std::cerr << "Error: Invalid DTMI data detected - syncing" << std::endl;
|
||||||
|
syncing = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
buffer.get().clear();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a direct pointer to the data attribute of the last received packet, if available.
|
/// Returns a direct pointer to the data attribute of the last received packet, if available.
|
||||||
/// Returns NULL if no valid pointer or packet is available.
|
/// Returns NULL if no valid pointer or packet is available.
|
||||||
std::string & DTSC::Stream::lastData(){
|
std::string & DTSC::Stream::lastData(){
|
||||||
|
@ -295,7 +348,7 @@ void DTSC::File::seekNext(){
|
||||||
if (frames[currframe] != pos){
|
if (frames[currframe] != pos){
|
||||||
currframe++;
|
currframe++;
|
||||||
currtime = jsonbuffer["time"].asInt();
|
currtime = jsonbuffer["time"].asInt();
|
||||||
#if DEBUG >= 4
|
#if DEBUG >= 6
|
||||||
if (frames[currframe] != pos){
|
if (frames[currframe] != pos){
|
||||||
std::cerr << "Found a new frame " << currframe << " @ " << pos << "b/" << currtime << "ms" << std::endl;
|
std::cerr << "Found a new frame " << currframe << " @ " << pos << "b/" << currtime << "ms" << std::endl;
|
||||||
}else{
|
}else{
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <stdio.h> //for FILE
|
#include <stdio.h> //for FILE
|
||||||
#include "json.h"
|
#include "json.h"
|
||||||
|
#include "socket.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -113,6 +114,7 @@ namespace DTSC{
|
||||||
bool hasVideo();
|
bool hasVideo();
|
||||||
bool hasAudio();
|
bool hasAudio();
|
||||||
bool parsePacket(std::string & buffer);
|
bool parsePacket(std::string & buffer);
|
||||||
|
bool parsePacket(Socket::Buffer & buffer);
|
||||||
std::string & outPacket(unsigned int num);
|
std::string & outPacket(unsigned int num);
|
||||||
std::string & outHeader();
|
std::string & outHeader();
|
||||||
Ring * getRing();
|
Ring * getRing();
|
||||||
|
|
|
@ -169,7 +169,8 @@ int FTP::User::ParseCommand( std::string Command ) {
|
||||||
fprintf( stderr, "Reading STOR information\n" );
|
fprintf( stderr, "Reading STOR information\n" );
|
||||||
std::string Buffer;
|
std::string Buffer;
|
||||||
while( Connected.spool() ) { }
|
while( Connected.spool() ) { }
|
||||||
Buffer = Connected.Received();
|
/// \todo Comment me back in. ^_^
|
||||||
|
//Buffer = Connected.Received();
|
||||||
MyDir.STOR( Command, Buffer );
|
MyDir.STOR( Command, Buffer );
|
||||||
return 250;
|
return 250;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -133,6 +133,7 @@ bool HTTP::Parser::Read(std::string & strbuf){
|
||||||
return parse(strbuf);
|
return parse(strbuf);
|
||||||
}//HTTPReader::Read
|
}//HTTPReader::Read
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
/// Attempt to read a whole HTTP response or request from a data buffer.
|
/// Attempt to read a whole HTTP response or request from a data buffer.
|
||||||
/// If succesful, fills its own fields with the proper data and removes the response/request
|
/// If succesful, fills its own fields with the proper data and removes the response/request
|
||||||
/// from the data buffer.
|
/// from the data buffer.
|
||||||
|
@ -141,13 +142,17 @@ bool HTTP::Parser::Read(std::string & strbuf){
|
||||||
bool HTTP::Parser::parse(std::string & HTTPbuffer){
|
bool HTTP::Parser::parse(std::string & HTTPbuffer){
|
||||||
size_t f;
|
size_t f;
|
||||||
std::string tmpA, tmpB, tmpC;
|
std::string tmpA, tmpB, tmpC;
|
||||||
/// \todo Make this not resize HTTPbuffer in parts, but read all at once and then remove the entire request, like doxygen claims it does.
|
/// \todo Make this not resize HTTPbuffer in parts, but read all at once and then remove the entire request, like doxygen claims it does?
|
||||||
while (!HTTPbuffer.empty()){
|
while (!HTTPbuffer.empty()){
|
||||||
if (!seenHeaders){
|
if (!seenHeaders){
|
||||||
f = HTTPbuffer.find('\n');
|
f = HTTPbuffer.find('\n');
|
||||||
if (f == std::string::npos) return false;
|
if (f == std::string::npos) return false;
|
||||||
tmpA = HTTPbuffer.substr(0, f);
|
tmpA = HTTPbuffer.substr(0, f);
|
||||||
HTTPbuffer.erase(0, f+1);
|
if (f+1 == HTTPbuffer.size()){
|
||||||
|
HTTPbuffer.clear();
|
||||||
|
}else{
|
||||||
|
HTTPbuffer.erase(0, f+1);
|
||||||
|
}
|
||||||
while (tmpA.find('\r') != std::string::npos){tmpA.erase(tmpA.find('\r'));}
|
while (tmpA.find('\r') != std::string::npos){tmpA.erase(tmpA.find('\r'));}
|
||||||
if (!seenReq){
|
if (!seenReq){
|
||||||
seenReq = true;
|
seenReq = true;
|
||||||
|
@ -166,7 +171,11 @@ bool HTTP::Parser::parse(std::string & HTTPbuffer){
|
||||||
}else{
|
}else{
|
||||||
if (tmpA.size() == 0){
|
if (tmpA.size() == 0){
|
||||||
seenHeaders = true;
|
seenHeaders = true;
|
||||||
if (GetHeader("Content-Length") != ""){length = atoi(GetHeader("Content-Length").c_str());}
|
body.clear();
|
||||||
|
if (GetHeader("Content-Length") != ""){
|
||||||
|
length = atoi(GetHeader("Content-Length").c_str());
|
||||||
|
if (body.capacity() < length){body.reserve(length);}
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
f = tmpA.find(':');
|
f = tmpA.find(':');
|
||||||
if (f == std::string::npos) continue;
|
if (f == std::string::npos) continue;
|
||||||
|
@ -178,10 +187,13 @@ bool HTTP::Parser::parse(std::string & HTTPbuffer){
|
||||||
}
|
}
|
||||||
if (seenHeaders){
|
if (seenHeaders){
|
||||||
if (length > 0){
|
if (length > 0){
|
||||||
if (HTTPbuffer.length() >= length){
|
unsigned int toappend = length - body.length();
|
||||||
body = HTTPbuffer.substr(0, length);
|
if (toappend > 0){
|
||||||
|
body.append(HTTPbuffer, 0, toappend);
|
||||||
|
HTTPbuffer.erase(0, toappend);
|
||||||
|
}
|
||||||
|
if (length == body.length()){
|
||||||
parseVars(body); //parse POST variables
|
parseVars(body); //parse POST variables
|
||||||
HTTPbuffer.erase(0, length);
|
|
||||||
return true;
|
return true;
|
||||||
}else{
|
}else{
|
||||||
return false;
|
return false;
|
||||||
|
@ -194,7 +206,6 @@ bool HTTP::Parser::parse(std::string & HTTPbuffer){
|
||||||
return false; //empty input
|
return false; //empty input
|
||||||
}//HTTPReader::parse
|
}//HTTPReader::parse
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
/// Parses GET or POST-style variable data.
|
/// Parses GET or POST-style variable data.
|
||||||
/// Saves to internal variable structure using HTTP::Parser::SetVar.
|
/// Saves to internal variable structure using HTTP::Parser::SetVar.
|
||||||
void HTTP::Parser::parseVars(std::string data){
|
void HTTP::Parser::parseVars(std::string data){
|
||||||
|
|
|
@ -258,15 +258,17 @@ std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data, unsigne
|
||||||
|
|
||||||
|
|
||||||
/// Parses the argument string into the current chunk.
|
/// Parses the argument string into the current chunk.
|
||||||
/// Tries to read a whole chunk, if successful it will remove
|
/// Tries to read a whole chunk, removing data from the input string as it reads.
|
||||||
/// the corresponding data from the input string.
|
|
||||||
/// If only part of a chunk is read, it will remove the part and call itself again.
|
/// If only part of a chunk is read, it will remove the part and call itself again.
|
||||||
/// This has the effect of only causing a "true" reponse in the case a *whole* chunk
|
/// This has the effect of only causing a "true" reponse in the case a *whole* chunk
|
||||||
/// is read, not just part of a chunk.
|
/// is read, not just part of a chunk.
|
||||||
/// \param indata The input string to parse and update.
|
/// \param indata The input string to parse and update.
|
||||||
/// \warning This function will destroy the current data in this chunk!
|
/// \warning This function will destroy the current data in this chunk!
|
||||||
/// \returns True if a whole chunk could be read, false otherwise.
|
/// \returns True if a whole chunk could be read, false otherwise.
|
||||||
bool RTMPStream::Chunk::Parse(std::string & indata){
|
bool RTMPStream::Chunk::Parse(std::string & source){
|
||||||
|
static std::string indata;
|
||||||
|
indata.append(source);
|
||||||
|
source.clear();
|
||||||
gettimeofday(&RTMPStream::lastrec, 0);
|
gettimeofday(&RTMPStream::lastrec, 0);
|
||||||
unsigned int i = 0;
|
unsigned int i = 0;
|
||||||
if (indata.size() < 1) return false;//need at least a byte
|
if (indata.size() < 1) return false;//need at least a byte
|
||||||
|
@ -378,7 +380,7 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
|
||||||
if (len_left == 0){
|
if (len_left == 0){
|
||||||
return true;
|
return true;
|
||||||
}else{
|
}else{
|
||||||
return Parse(indata);
|
return Parse(source);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
data = "";
|
data = "";
|
||||||
|
|
170
lib/socket.cpp
170
lib/socket.cpp
|
@ -12,12 +12,110 @@
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define BUFFER_BLOCKSIZE 4096 //set buffer blocksize to 4KiB
|
||||||
|
#include <iostream>//temporary for debugging
|
||||||
|
|
||||||
std::string uint2string(unsigned int i){
|
std::string uint2string(unsigned int i){
|
||||||
std::stringstream st;
|
std::stringstream st;
|
||||||
st << i;
|
st << i;
|
||||||
return st.str();
|
return st.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the amount of elements in the internal std::deque of std::string objects.
|
||||||
|
/// The back is popped as long as it is empty, first - this way this function is
|
||||||
|
/// guaranteed to return 0 if the buffer is empty.
|
||||||
|
unsigned int Socket::Buffer::size(){
|
||||||
|
while (data.size() > 0 && data.back().empty()){data.pop_back();}
|
||||||
|
return data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Appends this string to the internal std::deque of std::string objects.
|
||||||
|
/// It is automatically split every BUFFER_BLOCKSIZE bytes.
|
||||||
|
void Socket::Buffer::append(const std::string & newdata){
|
||||||
|
append(newdata.c_str(), newdata.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Appends this data block to the internal std::deque of std::string objects.
|
||||||
|
/// It is automatically split every BUFFER_BLOCKSIZE bytes.
|
||||||
|
void Socket::Buffer::append(const char * newdata, const unsigned int newdatasize){
|
||||||
|
unsigned int i = 0, j = 0;
|
||||||
|
while (i < newdatasize){
|
||||||
|
j = i;
|
||||||
|
while (j < newdatasize && j - i <= BUFFER_BLOCKSIZE){
|
||||||
|
j++;
|
||||||
|
if (newdata[j-1] == '\n'){break;}
|
||||||
|
}
|
||||||
|
if (i != j){
|
||||||
|
data.push_front(std::string(newdata+i, (size_t)(j - i)));
|
||||||
|
i = j;
|
||||||
|
}else{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (data.size() > 1000){
|
||||||
|
std::cerr << "Warning: After " << newdatasize << " new bytes, buffer has " << data.size() << " parts!" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if at least count bytes are available in this buffer.
|
||||||
|
bool Socket::Buffer::available(unsigned int count){
|
||||||
|
unsigned int i = 0;
|
||||||
|
for (std::deque<std::string>::iterator it = data.begin(); it != data.end(); ++it){
|
||||||
|
i += (*it).size();
|
||||||
|
if (i >= count){return true;}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes count bytes from the buffer, returning them by value.
|
||||||
|
/// Returns an empty string if not all count bytes are available.
|
||||||
|
std::string Socket::Buffer::remove(unsigned int count){
|
||||||
|
if (!available(count)){return "";}
|
||||||
|
unsigned int i = 0;
|
||||||
|
std::string ret;
|
||||||
|
for (std::deque<std::string>::reverse_iterator it = data.rbegin(); it != data.rend(); ++it){
|
||||||
|
if (i + (*it).size() < count){
|
||||||
|
ret.append(*it);
|
||||||
|
i += (*it).size();
|
||||||
|
(*it).clear();
|
||||||
|
}else{
|
||||||
|
ret.append(*it, 0, count - i);
|
||||||
|
(*it).erase(0, count - i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Copies count bytes from the buffer, returning them by value.
|
||||||
|
/// Returns an empty string if not all count bytes are available.
|
||||||
|
std::string Socket::Buffer::copy(unsigned int count){
|
||||||
|
if (!available(count)){return "";}
|
||||||
|
unsigned int i = 0;
|
||||||
|
std::string ret;
|
||||||
|
for (std::deque<std::string>::reverse_iterator it = data.rbegin(); it != data.rend(); ++it){
|
||||||
|
if (i + (*it).size() < count){
|
||||||
|
ret.append(*it);
|
||||||
|
i += (*it).size();
|
||||||
|
}else{
|
||||||
|
ret.append(*it, 0, count - i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets a reference to the back of the internal std::deque of std::string objects.
|
||||||
|
std::string & Socket::Buffer::get(){
|
||||||
|
static std::string empty;
|
||||||
|
if (data.size() > 0){
|
||||||
|
return data.back();
|
||||||
|
}else{
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Create a new base socket. This is a basic constructor for converting any valid socket to a Socket::Connection.
|
/// Create a new base socket. This is a basic constructor for converting any valid socket to a Socket::Connection.
|
||||||
/// \param sockNo Integer representing the socket to convert.
|
/// \param sockNo Integer representing the socket to convert.
|
||||||
Socket::Connection::Connection(int sockNo){
|
Socket::Connection::Connection(int sockNo){
|
||||||
|
@ -225,23 +323,36 @@ std::string Socket::Connection::getStats(std::string C){
|
||||||
/// Updates the downbuffer and upbuffer internal variables.
|
/// Updates the downbuffer and upbuffer internal variables.
|
||||||
/// Returns true if new data was received, false otherwise.
|
/// Returns true if new data was received, false otherwise.
|
||||||
bool Socket::Connection::spool(){
|
bool Socket::Connection::spool(){
|
||||||
iwrite(upbuffer);
|
if (upbuffer.size() > 0){
|
||||||
return iread(downbuffer);
|
iwrite(upbuffer.get());
|
||||||
|
}
|
||||||
|
/// \todo Provide better mechanism to prevent overbuffering.
|
||||||
|
if (downbuffer.size() > 1000){
|
||||||
|
return true;
|
||||||
|
}else{
|
||||||
|
return iread(downbuffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates the downbuffer and upbuffer internal variables until upbuffer is empty.
|
/// Updates the downbuffer and upbuffer internal variables until upbuffer is empty.
|
||||||
/// Returns true if new data was received, false otherwise.
|
/// Returns true if new data was received, false otherwise.
|
||||||
bool Socket::Connection::flush(){
|
bool Socket::Connection::flush(){
|
||||||
while (upbuffer.size() > 0 && connected()){
|
while (upbuffer.size() > 0 && connected()){
|
||||||
iwrite(upbuffer);
|
if (!iwrite(upbuffer.get())){
|
||||||
usleep(5000);//sleep 5 ms
|
usleep(10000);//sleep 10ms
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// \todo Provide better mechanism to prevent overbuffering.
|
||||||
|
if (downbuffer.size() > 1000){
|
||||||
|
return true;
|
||||||
|
}else{
|
||||||
|
return iread(downbuffer);
|
||||||
}
|
}
|
||||||
return iread(downbuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Returns a reference to the download buffer.
|
/// Returns a reference to the download buffer.
|
||||||
std::string & Socket::Connection::Received(){
|
Socket::Buffer & Socket::Connection::Received(){
|
||||||
return downbuffer;
|
return downbuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,16 +362,15 @@ std::string & Socket::Connection::Received(){
|
||||||
/// the data right away. Any data that could not be send will be put into the upbuffer.
|
/// the data right away. Any data that could not be send will be put into the upbuffer.
|
||||||
/// This means this function is blocking if the socket is, but nonblocking otherwise.
|
/// This means this function is blocking if the socket is, but nonblocking otherwise.
|
||||||
void Socket::Connection::Send(std::string & data){
|
void Socket::Connection::Send(std::string & data){
|
||||||
if (upbuffer.size() > 0){
|
while (upbuffer.size() > 0){
|
||||||
iwrite(upbuffer);
|
if (!iwrite(upbuffer.get())){break;}
|
||||||
if (upbuffer.size() > 0){
|
|
||||||
upbuffer.append(data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (upbuffer.size() == 0){
|
if (upbuffer.size() > 0){
|
||||||
|
upbuffer.append(data);
|
||||||
|
}else{
|
||||||
int i = iwrite(data.c_str(), data.size());
|
int i = iwrite(data.c_str(), data.size());
|
||||||
if (i < data.size()){
|
if (i < data.size()){
|
||||||
upbuffer.append(data, i, data.size() - i);
|
upbuffer.append(data.c_str()+i, data.size() - i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -272,16 +382,15 @@ void Socket::Connection::Send(std::string & data){
|
||||||
/// This means this function is blocking if the socket is, but nonblocking otherwise.
|
/// This means this function is blocking if the socket is, but nonblocking otherwise.
|
||||||
void Socket::Connection::Send(const char * data){
|
void Socket::Connection::Send(const char * data){
|
||||||
int len = strlen(data);
|
int len = strlen(data);
|
||||||
if (upbuffer.size() > 0){
|
while (upbuffer.size() > 0){
|
||||||
iwrite(upbuffer);
|
if (!iwrite(upbuffer.get())){break;}
|
||||||
if (upbuffer.size() > 0){
|
|
||||||
upbuffer.append(data, (size_t)len);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (upbuffer.size() == 0){
|
if (upbuffer.size() > 0){
|
||||||
|
upbuffer.append(data, len);
|
||||||
|
}else{
|
||||||
int i = iwrite(data, len);
|
int i = iwrite(data, len);
|
||||||
if (i < len){
|
if (i < len){
|
||||||
upbuffer.append(data + i, (size_t)(len - i));
|
upbuffer.append(data + i, len - i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -292,13 +401,12 @@ void Socket::Connection::Send(const char * data){
|
||||||
/// the data right away. Any data that could not be send will be put into the upbuffer.
|
/// the data right away. Any data that could not be send will be put into the upbuffer.
|
||||||
/// This means this function is blocking if the socket is, but nonblocking otherwise.
|
/// This means this function is blocking if the socket is, but nonblocking otherwise.
|
||||||
void Socket::Connection::Send(const char * data, size_t len){
|
void Socket::Connection::Send(const char * data, size_t len){
|
||||||
if (upbuffer.size() > 0){
|
while (upbuffer.size() > 0){
|
||||||
iwrite(upbuffer);
|
if (!iwrite(upbuffer.get())){break;}
|
||||||
if (upbuffer.size() > 0){
|
|
||||||
upbuffer.append(data, len);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (upbuffer.size() == 0){
|
if (upbuffer.size() > 0){
|
||||||
|
upbuffer.append(data, len);
|
||||||
|
}else{
|
||||||
int i = iwrite(data, len);
|
int i = iwrite(data, len);
|
||||||
if (i < len){
|
if (i < len){
|
||||||
upbuffer.append(data + i, len - i);
|
upbuffer.append(data + i, len - i);
|
||||||
|
@ -380,14 +488,14 @@ int Socket::Connection::iread(void * buffer, int len){
|
||||||
return r;
|
return r;
|
||||||
}//Socket::Connection::iread
|
}//Socket::Connection::iread
|
||||||
|
|
||||||
/// Read call that is compatible with std::string.
|
/// Read call that is compatible with Socket::Buffer.
|
||||||
/// Data is read using iread (which is nonblocking if the Socket::Connection itself is),
|
/// Data is read using iread (which is nonblocking if the Socket::Connection itself is),
|
||||||
/// then appended to end of buffer.
|
/// then appended to end of buffer.
|
||||||
/// \param buffer std::string to append data to.
|
/// \param buffer Socket::Buffer to append data to.
|
||||||
/// \return True if new data arrived, false otherwise.
|
/// \return True if new data arrived, false otherwise.
|
||||||
bool Socket::Connection::iread(std::string & buffer){
|
bool Socket::Connection::iread(Buffer & buffer){
|
||||||
char cbuffer[5000];
|
char cbuffer[BUFFER_BLOCKSIZE];
|
||||||
int num = iread(cbuffer, 5000);
|
int num = iread(cbuffer, BUFFER_BLOCKSIZE);
|
||||||
if (num < 1){return false;}
|
if (num < 1){return false;}
|
||||||
buffer.append(cbuffer, num);
|
buffer.append(cbuffer, num);
|
||||||
return true;
|
return true;
|
||||||
|
|
28
lib/socket.h
28
lib/socket.h
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
@ -13,6 +14,7 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
//for being friendly with Socket::Connection down below
|
//for being friendly with Socket::Connection down below
|
||||||
namespace Buffer{class user;};
|
namespace Buffer{class user;};
|
||||||
|
@ -20,6 +22,20 @@ namespace Buffer{class user;};
|
||||||
///Holds Socket tools.
|
///Holds Socket tools.
|
||||||
namespace Socket{
|
namespace Socket{
|
||||||
|
|
||||||
|
/// A buffer made out of std::string objects that can be efficiently read from and written to.
|
||||||
|
class Buffer{
|
||||||
|
private:
|
||||||
|
std::deque<std::string> data;
|
||||||
|
public:
|
||||||
|
unsigned int size();
|
||||||
|
void append(const std::string & newdata);
|
||||||
|
void append(const char * newdata, const unsigned int newdatasize);
|
||||||
|
std::string & get();
|
||||||
|
bool available(unsigned int count);
|
||||||
|
std::string remove(unsigned int count);
|
||||||
|
std::string copy(unsigned int count);
|
||||||
|
};//Buffer
|
||||||
|
|
||||||
/// This class is for easy communicating through sockets, either TCP or Unix.
|
/// This class is for easy communicating through sockets, either TCP or Unix.
|
||||||
class Connection{
|
class Connection{
|
||||||
private:
|
private:
|
||||||
|
@ -29,15 +45,15 @@ namespace Socket{
|
||||||
unsigned int up;
|
unsigned int up;
|
||||||
unsigned int down;
|
unsigned int down;
|
||||||
unsigned int conntime;
|
unsigned int conntime;
|
||||||
std::string downbuffer; ///< Stores temporary data coming in.
|
Buffer downbuffer; ///< Stores temporary data coming in.
|
||||||
std::string upbuffer; ///< Stores temporary data going out.
|
Buffer upbuffer; ///< Stores temporary data going out.
|
||||||
int iread(void * buffer, int len); ///< Incremental read call.
|
int iread(void * buffer, int len); ///< Incremental read call.
|
||||||
int iwrite(const void * buffer, int len); ///< Incremental write call.
|
int iwrite(const void * buffer, int len); ///< Incremental write call.
|
||||||
bool iread(std::string & buffer); ///< Incremental write call that is compatible with std::string.
|
bool iread(Buffer & buffer); ///< Incremental write call that is compatible with Socket::Buffer.
|
||||||
bool iwrite(std::string & buffer); ///< Write call that is compatible with std::string.
|
bool iwrite(std::string & buffer); ///< Write call that is compatible with std::string.
|
||||||
public:
|
public:
|
||||||
//friends
|
//friends
|
||||||
friend class Buffer::user;
|
friend class ::Buffer::user;
|
||||||
//constructors
|
//constructors
|
||||||
Connection(); ///< Create a new disconnected base socket.
|
Connection(); ///< Create a new disconnected base socket.
|
||||||
Connection(int sockNo); ///< Create a new base socket.
|
Connection(int sockNo); ///< Create a new base socket.
|
||||||
|
@ -55,7 +71,7 @@ namespace Socket{
|
||||||
//buffered i/o methods
|
//buffered i/o methods
|
||||||
bool spool(); ///< Updates the downbuffer and upbuffer internal variables.
|
bool spool(); ///< Updates the downbuffer and upbuffer internal variables.
|
||||||
bool flush(); ///< Updates the downbuffer and upbuffer internal variables until upbuffer is empty.
|
bool flush(); ///< Updates the downbuffer and upbuffer internal variables until upbuffer is empty.
|
||||||
std::string & Received(); ///< Returns a reference to the download buffer.
|
Buffer & Received(); ///< Returns a reference to the download buffer.
|
||||||
void Send(std::string & data); ///< Appends data to the upbuffer.
|
void Send(std::string & data); ///< Appends data to the upbuffer.
|
||||||
void Send(const char * data); ///< Appends data to the upbuffer.
|
void Send(const char * data); ///< Appends data to the upbuffer.
|
||||||
void Send(const char * data, size_t len); ///< Appends data to the upbuffer.
|
void Send(const char * data, size_t len); ///< Appends data to the upbuffer.
|
||||||
|
|
Loading…
Add table
Reference in a new issue