I have a socket wraper and it has the RecvData that returns an int:
int RecvData(void* buff, int bufferSize){
return recv(hSocket, reinterpret_cast<char*>(buff), bufferSize, 0);
}
also I have this WebServer function ReceiveLine to get an HTTP request:
static string ReceiveLine()
{
Socket* sock;
std::string ret;
while (1) {
char r;
switch(sock->SendData(&r,sizeof(r))) {
case 0: // not connected anymore;
return "";
case -1:
if (errno == EAGAIN) {
return ret;
} else {
// not connected anymore
return "";
}
}
ret += r;
if (r == '\n') return ret;
}
return ret;
}
The problem is that in the switch statement I have this error:
Socket* sock; pointer to incomplete class type is not allowed
An incomplete class means you have declared the Socket class but not defined it. Maybe it's been forward declared but you never included the .h file containing the definition.
Related
The image linked above is the HTML that browser shows. Every time when I press a link, the server cannot accept the correct HTTP information from the browser. Below is my code related to communicating through HTTP.
char buf[2048];
http_handle hh(connfd, buf, 2048);
read(connfd, buf, 2048);
hh.handle_http_request(&hh);
hh.response_http_request(&hh); //the first two function works
read(connfd, buf, 2048); //this returns 0
hh.handle_http_request(&hh);
hh.response_http_request(&hh);
Below is the implementation of handle_http_requestandresponse_http_request:
void* http_handle::handle_http_request(void* arg) {
http_handle* hp = (http_handle*)arg;
hp->_handle_http_request();
return hp;
}
void http_handle::_handle_http_request() {
int i, j;
for (i = 0; this->buf[i] != ' '; i++)
method[i] = this->buf[i];
method[i] = 0;
for (j = 0, ++i; this->buf[i] != ' '; i++, j++)
url[j] = this->buf[i];
url[j] = 0;
//method stores http operations like GET and POST
//url stores the url resource in the http start line
if (!strcasecmp(method, "GET")) {
//...
}
if (!strcasecmp(method, "POST")) {
//...
}
}
void* http_handle::response_http_request(void* arg) {
http_handle* hp = (http_handle*)arg;
hp->_response_http_request();
return hp;
}
void http_handle::_response_http_request() {
if (strcasecmp(method, "GET") && strcasecmp(method, "POST")) {
unimpelented();
return;
}
if (!strcasecmp(method, "GET")) {
if (strcmp(url, "/") == 0) {
char tmp_path[256];
http_handle::path = getcwd(tmp_path, 256);
trans_dir("src");
return;
}
std::string filepath = http_handle::path + "/" + url;
struct stat filestat;
if ((stat(filepath.c_str(), &filestat)) != 0) {
perror("_response_http_request stat error");
exit(1);
}
switch (filestat.st_mode & S_IFMT) {
case S_IFREG:
trans_file(filepath);
break;
case S_IFDIR:
trans_dir(filepath);
break;
default:
break;
}
return;
}
if (!strcasecmp(method, "POST")) { //to be implemented
return;
}
}
read() returns 0 when EOF is reached, ie when the peer has closed the TCP connection on its end.
The data you have shown is not larger than your buffer, so the first read() receives all of the data, and there is nothing left for the second read() because the server closed the connection after sending the data.
Currently, I am using a very simple code example which help me working with cross-platform sockets.
Github: Socket c++ cross platform
The problem comes when I was trying to make the http GET request
When I try simple requests, it returns me a correct value, but when I this complex request:
"GET /1.0/stock/aapl/batch?types=quote,news,chart&range=1m&last=10 HTTP/1.0\r\nHost: api.iextrading.com\r\nConnection: close\r\n\r\n"
It returns nothing!
//Main.cpp
#include <string>
#include <ActiveSocket.h>
#define SEND(a,b,c,d) send(a, (const char *)b, (int)c, d)
typedef unsigned char uint8;
int main(int argc, char **argv)
{
CActiveSocket socket; // Instantiate active socket object (defaults to TCP).
char time[50];
memset(&time, 0, 50);
char host[] = "api.iextrading.com";
char message[] = "GET /1.0/stock/aapl/batch?types=quote,news,chart&range=1m&last=10 HTTP/1.0\r\nHost: api.iextrading.com\r\nConnection: close\r\n\r\n";
socket.Initialize();
if (socket.Open(host, 80))
{
if (socket.Send((const uint8 *)message, strlen(message)))
{
socket.Receive(4096);//size of the buffer
socket.Close();
}
}
getchar();
return 1;
}
//CActiveSocket.h
int32 CSimpleSocket::Send(const uint8 *pBuf, size_t bytesToSend)
{
SetSocketError(SocketSuccess);
m_nBytesSent = 0;
switch(m_nSocketType)
{
case CSimpleSocket::SocketTypeTcp:
{
if (IsSocketValid())
{
if ((bytesToSend > 0) && (pBuf != NULL))
{
m_timer.Initialize();
m_timer.SetStartTime();
//---------------------------------------------------------
// Check error condition and attempt to resend if call
// was interrupted by a signal.
//---------------------------------------------------------
do
{
m_nBytesSent = SEND(m_socket, pBuf, bytesToSend, 0);
TranslateSocketError();
} while (GetSocketError() == CSimpleSocket::SocketInterrupted);
m_timer.SetEndTime();
}
}
break;
}
...
}
int32 CSimpleSocket::Receive(int32 nMaxBytes, uint8 * pBuffer )
{
m_nBytesReceived = 0;
if (IsSocketValid() == false)
{
return m_nBytesReceived;
}
uint8 * pWorkBuffer = pBuffer;
if ( pBuffer == NULL )
{
if ((m_pBuffer != NULL) && (nMaxBytes != m_nBufferSize))
{
delete [] m_pBuffer;
m_pBuffer = NULL;
}
if (m_pBuffer == NULL)
{
m_nBufferSize = nMaxBytes;
m_pBuffer = new uint8[nMaxBytes];
}
pWorkBuffer = m_pBuffer;
}
SetSocketError(SocketSuccess);
m_timer.Initialize();
m_timer.SetStartTime();
switch (m_nSocketType)
{
case CSimpleSocket::SocketTypeTcp:
{
do
{
m_nBytesReceived = RECV(m_socket, (pWorkBuffer +m_nBytesReceived), nMaxBytes, m_nFlags);
TranslateSocketError();
} while ((GetSocketError() == CSimpleSocket::SocketInterrupted));
break;
}
...
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I am converting our code to use IOCP and I got the communication relatively stable, but the memory usage of the application is increasing. Looks like I am getting back (on completion function calls) much fewer objects of OverlappedEx than I create. My code is below. What am I doing wrong?
#ifndef NETWORK_DATA
#define NETWORK_DATA
#include <afxwin.h>
#include <vector>
#include <string>
#include "CriticalSectionLocker.h"
using namespace std;
DWORD NetworkManager::NetworkThread(void* param)
{
bool bRun = true;
while (bRun)
{
DWORD wait = ::WaitForSingleObject(CCommunicationManager::s_hShutdownEvent, 0);
if (WAIT_OBJECT_0 == wait)
{
bRun = false;
DEBUG_LOG0("Shutdown event was signalled thread");
}
else
{
DWORD dwBytesTransfered = 0;
void* lpContext = nullptr;
OVERLAPPED* pOverlapped = nullptr;
BOOL bReturn = GetQueuedCompletionStatus(s_IOCompletionPort,
&dwBytesTransfered,
(LPDWORD)&lpContext,
&pOverlapped,
INFINITE);
if (nullptr == lpContext)
{
DEBUG_LOG0("invalid context");
/*continue;*/
}
else
{
if (bReturn && dwBytesTransfered > 0)
{
OverlappedEx* data = reinterpret_cast<OverlappedEx*>(pOverlapped);
ServerData* networkData = reinterpret_cast<ServerData*>(lpContext);
if (networkData && data)
{
switch(data->m_opType)
{
case OverlappedEx::OP_READ:
/*DEBUG_LOG4("device name: %s bytes received: %d socket: %d handle: %d",
networkData->Name().c_str(), dwBytesTransfered, networkData->Socket(), networkData->Handle());*/
networkData->CompleteReceive(dwBytesTransfered, data);
break;
case OverlappedEx::OP_WRITE:
/*DEBUG_LOG4("device name: %s bytes sent: %d socket: %d handle: %d",
networkData->Name().c_str(), dwBytesTransfered, networkData->Socket(), networkData->Handle());*/
networkData->CompleteSend(dwBytesTransfered, data);
break;
}
}
}
else
{
/*DEBUG_LOG2("GetQueuedCompletionStatus failed: bReturn: %d dwBytesTransferred: %u", bReturn, dwBytesTransfered);*/
}
}
}
}
return 0;
}
enum NetworkType
{
UDP,
TCP
};
struct OverlappedEx : public OVERLAPPED
{
enum OperationType
{
OP_READ,
OP_WRITE
};
const static int MAX_PACKET_SIZE = 2048;
WSABUF m_wBuf;
char m_buffer[MAX_PACKET_SIZE];
OperationType m_opType;
OverlappedEx()
{
Clear();
m_refCount = 1;
}
void AddRef()
{
::InterlockedIncrement(&m_refCount);
}
void Release()
{
::InterlockedDecrement(&m_refCount);
}
int Refcount() const
{
return InterlockedExchangeAdd((unsigned long*)&m_refCount, 0UL);
}
~OverlappedEx()
{
Clear();
}
void Clear()
{
memset(m_buffer, 0, MAX_PACKET_SIZE);
m_wBuf.buf = m_buffer;
m_wBuf.len = MAX_PACKET_SIZE;
Internal = 0;
InternalHigh = 0;
Offset = 0;
OffsetHigh = 0;
hEvent = nullptr;
m_opType = OP_READ;
}
private:
volatile LONG m_refCount;
};
class ServerData
{
public:
const static int MAX_REVEIVE_QUEUE_SIZE = 100;
const static int MAX_PACKET_SIZE = 2048;
const static int MAX_SEND_QUEUE_SIZE = 10;
const static int MAX_RECEIVE_QUEUE_SIZE = 100;
const static int MAX_OVERLAPPED_STRUCTS = 20;
ServerData(NetworkType netType, const string& sName, CCommunicationManager::CommHandle handle,
SOCKET sock, HANDLE IOPort) :
m_sName(sName)
{
InitializeCriticalSection(&m_receiveQueLock);
InitializeCriticalSection(&m_objectLock);
m_Handle = handle;
m_Socket = sock;
m_nIPAddress = 0;
m_netType = netType;
m_bEnabled = true;
m_ovlpIndex = 0;
for (int i = 0; i < MAX_OVERLAPPED_STRUCTS; ++i)
{
m_olps.push_back(new OverlappedEx);
}
/* Associate socket with completion handle */
if (m_Socket != 0)
{
CreateIoCompletionPort( reinterpret_cast<HANDLE>(m_Socket), IOPort, reinterpret_cast<ULONG_PTR>(this), 0 );
}
}
~ServerData()
{
CriticalSectionLocker lock(&m_receiveQueLock);
DeleteCriticalSection(&m_receiveQueLock);
DeleteCriticalSection(&m_objectLock);
closesocket(m_Socket);
}
const string& Name() const { return m_sName; }
bool Enabled() const { return m_bEnabled; }
void SetEnabled(bool bEnabled)
{
m_bEnabled = bEnabled;
}
int Handle() const { return m_Handle; }
void SetHandle(int handle)
{
m_Handle = handle;
}
unsigned long IPAddress() const { return m_nIPAddress; }
SOCKET Socket() const
{
return m_Socket;
}
void SetSocket(SOCKET sock)
{
m_Socket = sock;
}
void SetIPAddress(unsigned long nIP)
{
m_nIPAddress = nIP;
}
bool ValidTelegram(const vector<char>& telegram) const
{
return false;
}
OverlappedEx* GetBuffer()
{
OverlappedEx* ret = nullptr;
if (!m_olps.empty())
{
ret = m_olps.front();
m_olps.pop_front();
}
return ret;
}
void CompleteReceive(size_t numBytes, OverlappedEx* data)
{
//DEBUG_LOG1("%d buffers are available", AvailableBufferCount());
if (numBytes > 0)
{
vector<char> v(data->m_buffer, data->m_buffer + numBytes);
ReceivedData rd;
rd.SetData(v);
EnqueReceiveMessage(rd);
}
data->Release();
{
CriticalSectionLocker lock(&m_objectLock);
m_olps.push_back(data);
// DEBUG_LOG1("Queue size: %d", m_olps.size());
}
StartReceiving();
}
void CompleteSend(size_t numBytes, OverlappedEx* data)
{
data->Release();
{
CriticalSectionLocker lock(&m_objectLock);
m_olps.push_back(data);
//DEBUG_LOG1("Queue size: %d", m_olps.size());
}
//DEBUG_LOG2("Object: %s num sent: %d", Name().c_str(), numBytes);
}
void StartReceiving()
{
DWORD bytesRecv = 0;
sockaddr_in senderAddr;
DWORD flags = 0;
int senderAddrSize = sizeof(senderAddr);
int rc = 0;
CriticalSectionLocker lock(&m_objectLock);
auto olp = GetBuffer();
if (!olp)
{
if (...)
{
m_olps.push_back(new OverlappedEx);
olp = GetBuffer();
}
else
{
if (...)
{
DEBUG_LOG1("Name: %s ************* NO AVAILABLE BUFFERS - bailing ***************", Name().c_str());
}
return;
}
}
olp->Clear();
olp->m_opType = OverlappedEx::OP_READ;
olp->AddRef();
switch(GetNetworkType())
{
case UDP:
{
rc = WSARecvFrom(Socket(),
&olp->m_wBuf,
1,
&bytesRecv,
&flags,
(SOCKADDR *)&senderAddr,
&senderAddrSize, (OVERLAPPED*)olp, NULL);
}
break;
case TCP:
{
rc = WSARecv(Socket(),
&olp->m_wBuf,
1,
&bytesRecv,
&flags,
(OVERLAPPED*)olp, NULL);
}
break;
}
if (SOCKET_ERROR == rc)
{
DWORD err = WSAGetLastError();
if (err != WSA_IO_PENDING)
{
olp->Release();
m_olps.push_back(olp);
}
}
}
void SetWriteBuf(const SendData& msg, OverlappedEx* data)
{
int len = min(msg.Data().size(), MAX_PACKET_SIZE);
memcpy(data->m_buffer, &msg.Data()[0], len);
data->m_wBuf.buf = data->m_buffer;
data->m_wBuf.len = len;
}
void StartSending(const SendData& msg)
{
DEBUG_LOG1("device name: %s", Name().c_str());
int rc = 0;
DWORD bytesSent = 0;
DWORD flags = 0;
SOCKET sock = Socket();
int addrSize = sizeof(sockaddr_in);
CriticalSectionLocker lock(&m_objectLock);
//UpdateOverlapped(OverlappedEx::OP_WRITE);
auto olp = GetBuffer();
if (!olp)
{
if (...)
{
m_olps.push_back(new OverlappedEx);
olp = GetBuffer();
DEBUG_LOG2("name: %s ************* NO AVAILABLE BUFFERS new size: %d ***************", Name().c_str(), m_olps.size());
}
else
{
if (...)
{
DEBUG_LOG1("Name: %s ************* NO AVAILABLE BUFFERS - bailing ***************", Name().c_str());
}
return;
}
}
olp->Clear();
olp->m_opType = OverlappedEx::OP_WRITE;
olp->AddRef();
SetWriteBuf(msg, olp);
switch(GetNetworkType())
{
case UDP:
rc = WSASendTo(Socket(), &olp->m_wBuf, 1,
&bytesSent, flags, (sockaddr*)&msg.SendAddress(),
addrSize, (OVERLAPPED*)olp, NULL);
break;
case TCP:
rc = WSASend(Socket(), &olp->m_wBuf, 1,
&bytesSent, flags, (OVERLAPPED*)olp, NULL);
break;
}
if (SOCKET_ERROR == rc)
{
DWORD err = WSAGetLastError();
if (err != WSA_IO_PENDING)
{
olp->Release();
m_olps.push_back(olp);
}
}
}
size_t ReceiveQueueSize()
{
CriticalSectionLocker lock(&m_receiveQueLock);
return m_receiveDataQueue.size();
}
void GetAllData(vector <ReceivedData> & data)
{
CriticalSectionLocker lock(&m_receiveQueLock);
while (m_receiveDataQueue.size() > 0)
{
data.push_back(m_receiveDataQueue.front());
m_receiveDataQueue.pop_front();
}
}
void DequeReceiveMessage(ReceivedData& msg)
{
CriticalSectionLocker lock(&m_receiveQueLock);
if (m_receiveDataQueue.size() > 0)
{
msg = m_receiveDataQueue.front();
m_receiveDataQueue.pop_front();
}
}
template <class T>
void EnqueReceiveMessage(T&& data)
{
CriticalSectionLocker lock(&m_receiveQueLock);
if (m_receiveDataQueue.size() <= MAX_RECEIVE_QUEUE_SIZE)
{
m_receiveDataQueue.push_back(data);
}
else
{
static int s_nLogCount = 0;
if (s_nLogCount % 100 == 0)
{
DEBUG_LOG2("Max queue size was reached handle id: %d in %s", Handle(), Name().c_str());
}
s_nLogCount++;
}
}
NetworkType GetNetworkType() const
{
return m_netType;
}
private:
ServerData(const ServerData&);
ServerData& operator=(const ServerData&);
private:
bool m_bEnabled; //!< This member flags if this reciever is enabled for receiving incoming connections.
int m_Handle; //!< This member holds the handle for this receiver.
SOCKET m_Socket; //!< This member holds the socket information for this receiver.
unsigned long m_nIPAddress; //!< This member holds an IP address the socket is bound to.
deque < ReceivedData > m_receiveDataQueue;
CRITICAL_SECTION m_receiveQueLock;
CRITICAL_SECTION m_objectLock;
string m_sName;
NetworkType m_netType;
deque<OverlappedEx*> m_olps;
size_t m_ovlpIndex;
};
#endif
your implementation of void Release() have no sense - you decrement m_refCount and so what ? must be
void Release()
{
if (!InterlockedDecrement(&m_refCount)) delete this;
}
as result you never free OverlappedEx* data - this what i just view and this give memory leak.
also can advice - use WaitForSingleObject(CCommunicationManager::s_hShutdownEvent, 0); this is bad idea for detect shutdown. call only GetQueuedCompletionStatus and for shutdown call PostQueuedCompletionStatus(s_IOCompletionPort, 0, 0, 0) several times(number or threads listen on s_IOCompletionPort) and if thread view pOverlapped==0 - just exit.
use
OverlappedEx* data = static_cast<OverlappedEx*>(pOverlapped);
instead of reinterpret_cast
make ~OverlappedEx() private - it must not be direct called, only via Release
olp->Release();
m_olps.push_back(olp);
after you call Release() on object you must not it more access here, so or olp->Release() or m_olps.push_back(olp); but not both. this kill all logic of Release may be you need overwrite operator delete of OverlappedEx and inside it call m_olps.push_back(olp); and of course overwrite operator new too
again (OVERLAPPED*)olp - for what reinterpret_cast here ? because you inherit own struct from OVERLAPPED compiler auto do type cast here
I have a class that handles the serial comms for my program called "serial.h and serial.cpp". It has the following constructor:
#include "serial.h"
serialib LS;
serial::serial(void)
{
int Ret;
Ret = LS.Open(DEVICE_PORT, BAUD_RATE);
if (Ret != 1)
{
printf("Serial port open FAILED!\n");
}
else
{
printf("Serial port successfully opened...");
}
}
I want to call this class in another and use its methods, so I do the following in a class called dataHandler.cpp:
#include "dataHandler.h"
#include "serial.h"
using namespace opendnp3;
serial ser;
dataHandler::dataHandler(void)
{
}
dataHandler::~dataHandler(void)
{
}
int dataHandler::sendRestartCommand()
{
int Ret;
char buffer[128];
RestartInfo ri;
std::string strW = "GetRestartInfo\r\n";
std::string strR;
Ret = ser.Write(strW);
int bytes;
Ret = ser.Read(strR);
if ((strR.compare("201-OK [GetRestartInfo]\r\n")) != 0)
{
printf ("Wrong response from device to restart message.\n");
return 0;
}
Ret = ser.Read(strR);
std::string s_bytes = strR.substr(4,3);
std::stringstream ss(s_bytes);
if (!(ss >> bytes))
bytes = 0;
Ret = ser.Read(buffer);
writeSettings(ri);
return 1;
}
However, when I do this, I get the following error:
dataHandler.o: In function `dataHandler::sendRestartCommand()':
dataHandler.cpp:(.text+0x31c): undefined reference to `dataHandler::ser'
collect2: error: ld returned 1 exit status
My original plan was to create a serial object in my .h file like:
public:
serial ser;
But that did not work either...
I'm a bit stumped as to how to do this, I know I'm probably missing something small.
Any advice?
What I ended up doing is creating an constructor with arguments:
serial::serial(std::string devPort, int baud)
{
int Ret;
const char * devP = devPort.c_str();
Ret = LS.Open(devP, baud);
if (Ret != 1)
{
printf("Serial port open FAILED!\n");
}
else
{
printf("Serial port successfully opened...");
}
}
Then I called it like so:
static serial ser(DEVICE_PORT, BAUD_RATE);
Works fine now. Thus, I am calling the serial object as a global variable!
I'm made a File class that is a sort of wrapper of the FILE type and added some methods.
This is the code of my file class :
#include <Fs/File.h>
File::File(Path& p):
m_path(p),
m_openned(false)
{
}
int File::open(const string& mode)
{
m_f = new FILE;
fopen(m_path, mode.c_str());
if (m_f == NULL)
{
m_openned = false;
return -1;
}
m_openned = true;
return 0;
}
bool File::exists()
{
FILE* file;
if (file = fopen(m_path, "r"))
{
fclose(file);
return true;
}
fclose(file);
return false;
}
int File::flush(){
return fflush(m_f);
}
int File::remove()
{
return ::remove(m_path);
}
int File::close()
{
if (isOpenned())
{
m_openned = false;
return fclose(m_f);
}
return 0;
}
long File::getSize()
{
struct stat file_status;
if(!this->exists())
return -1;
if (stat(m_path, &file_status) < 0)
{
return -1;
}
return file_status.st_size;
}
FileMode File::getMode()
{
struct stat file_status;
if (stat(m_path, &file_status) < 0)
{
return FileMode(-1);
}
return FileMode(file_status.st_mode);
}
Path File::getPath()
{
return m_path;
}
bool File::isOpenned()
{
return m_openned;
}
int File::setMode(FileMode& mode)
{
return chmod(m_path, mode);
}
int File::renameTo(File& f)
{
if (f.exists() || !this->exists())
return -1;
return rename( m_path , f.getPath());
}
int File::copyTo(File& to)
{
char ch;
this->close();
this->open(FileTypes::READ);
to.close();
to.open(FileTypes::WRITE);
while (!this->eof())
{
ch = this->readc();
if (ch == -1)
return 0;
if (!to.eof())
to.writec(ch);
}
if (this->close() < 0)
{
return -1;
}
if (to.close() < 0)
{
return -1;
}
return 0;
}
int File::readc()
{
if (!isOpenned())
return FileTypes::ENDOFFILE;
char c = fgetc(m_f);
if (ferror(m_f))
{
return FileTypes::ENDOFFILE;
}
return c;
}
int File::writec(char c)
{
if (!isOpenned())
return -1;
fputc(c, m_f);
if (ferror(m_f))
{
return FileTypes::ENDOFFILE;
}
return 0;
}
bool File::eof()
{
if (!isOpenned())
return true;
return feof(m_f);
}
I made some tests and I have a kind of problem
Path p1("test.txt");
Path p2("temp.txt");
File f1(p1);
File f2(p2);
assert(f1.open(FileTypes::READ) == 0);
assert(f1.exists() == true);
assert(f1.close() == 0);
cout<<"Mode of f1 "<<f1.getMode().getStringMode()<<endl;
cout<<"Path of f1 "<<f1.getPath().getAbsolutePath()<<endl;
cout<<"Size of f1 "<<f1.getSize()<<endl;
assert(f2.exists() == false);
assert(f1.copyTo(f2) == 0);
//#####################################
// If I comment f2.close() the
// assert(f1.getSize() == f2.getSize()) test fails and
// f2.getSize() == 0
##########################################
f2.close();
assert(f2.exists() == true);
assert(f1.getSize() == f2.getSize());
I couldn't figure why this f2.close is needed because I did a close in the copyTo method.
Can someone help me ?
Thank you in advance.
Ben
In File::copyTo:
if (ch == -1)
return 0;
you are jumping out of the function without properly closing the files. When the target file is not closed, it's contents is probably not sent to the OS, which later reports bogus filesize.
fclose flushes the stream. My guess is, is that without closing the file, the stream has not been fully written, so the sizes are different. Consider adding fflush(to); at the end of your copyTo method to ensure everything has been written.
You have multiple exits from the copyTo function which doesn't ensure that you actually close the file. It looks to me that you may be exiting early from the copyTo function and that the intended close isn't executing
while (!this->eof())
{
ch = this->readc();
if (ch == -1)
return 0;
if (!to.eof())
to.writec(ch);
}
when you hit the end of the file you will get EOF which in my os (windows) it is -1, which would cause you to return 0 here, and skip the close call.