im having a segmentation fault error testing a client-server file transfer. I have this code on the downloader side (this is where i think the problem is):
else if (info_socket[fds[i].fd] == RECIBIENDO) {
close_conn = FALSE;
buffer = (char*) malloc(1500);
rc = recv(fds[i].fd, buffer, 1500, 0);
if (rc < 0) {
if (errno != EWOULDBLOCK) {
perror(" recv() failed");
close_conn = TRUE;
map<int, info_trans*>::iterator it = descargas.find(fds[i].fd);
descargas.erase(it);
}
} else if (rc == 0) {
close_conn = TRUE;
map<int, info_trans*>::iterator it = descargas.find(fds[i].fd);
descargas.erase(it);
} else {
arch = fopen((directorio + descargas[fds[i].fd]->nombre_archivo).c_str(), "ab");
printf("%s -- %d",(directorio + descargas[fds[i].fd]->nombre_archivo).c_str(),fds[i].fd);
totalEscrito = fwrite(buffer, 1, rc, arch);
descargas[fds[i].fd]->bytes_descargados = descargas[fds[i].fd]->bytes_descargados + totalEscrito;
fclose(arch);
file_descript = open((directorio + descargas[fds[i].fd]->nombre_archivo).c_str(), O_RDONLY);
file_size = get_size_by_fd(file_descript);
file_buffer = (char*) mmap(0, file_size, PROT_READ, MAP_SHARED, file_descript, 0);
MD5((unsigned char*) file_buffer, file_size, result);
mdString = (char*) malloc(33);
for (int r = 0; r < 16; r++)
sprintf(&mdString[r * 2], "%02x", (unsigned int) result[r]);
if (strcmp(mdString, (descargas[fds[i].fd]->md5).c_str()) == 0) {
close_conn = TRUE;
map<int, info_trans*>::iterator it = descargas.find(fds[i].fd);
descargas.erase(it);
}
free(mdString);
free(file_buffer);
close(file_descript);
}
The Server is on a similar loop sending the data. The strange part is that if i run this on my laptop it works, but at the school pc's virtual machine throws the Segmentation fault.
If there is a good way to debug the memory using VMware Player, please tell me too.
Thanks you, and sorry for my english level.
free(file_buffer); is wrong. I guess you meant munmap(file_buffer, file_size);.
Related
Right now I am currently trying to learn winsock, and to do so I'm trying to just send a file over a socket. I have written all of the code, and I got it to partially work, sending only the top part of an image, but now it has just completely stopped working. I have no idea what is causing send and recv to return SOCKET_ERROR.
To be honest, I have no idea what to do. The socket just closes poops itself and I do not know why.
Here is the code I use for recieving the file size, and also the file itself.
cout << "Fetching file from server" << endl;
int nBytes = 4096, nLeft, idx; // I have no idea what this does, ctrl c + ctrl v always works though, maybe this is the problem?
nLeft = nBytes;
idx = 0;
while (nLeft > 0)
{
ret = recv(listening, sizef[idx], nLeft, 0);
if (ret == SOCKET_ERROR)
{
WSACleanup();
return 912;
}
nLeft -= ret;
idx += ret;
}
Here is the code I use for sending the file size and file.
int nBytes = 4096, nLeft, idx;
nLeft = nBytes;
idx = 0;
while (nLeft > 0)
{
ret = send(clientSocket, &cstr[idx], nLeft, 0);
if (ret == SOCKET_ERROR)
{
cerr << "Oops, failed to send, the programmer shit his pants, or the client did";
return 912;
}
nLeft -= ret;
idx += ret;
}
Now, the intended result of this function is to just receive the file, but it always returns SOCKET_ERROR, on every file I try.
The short version:
I have written a small program to print a report. This program is exec'ed from our proprietary server, that is running as a windows service. It works in our development environment, but not on our customer's network.
When I attempt to access the printing system in the failing case, I get a "No default printer" error. We had the customer create a new login account that has a default printer defined, and restarted the server using that login account. Same error.
Note that this error is generated when trying to find a specified printer, not when we try to print to it.
Is there any way to convince a server-spawned process that printers do, in fact, exist?
The long version:
In our "current" production environment, we have the following:
1. a proprietary server that runs as a service under windows.
2. a desktop client
--> accesses data via that service
--> uses fastreport4 to generate reports
--> developed using C++Builder6 (and VCL)
3. a PocketPC-based application that runs on scanning devices
--> uses Apache to communicate with the service
--> also uses Apache to poke a cgi-bin application that will bring up
the desktop app in stealth mode, run a report, and print it.
I have been tasked with re-implementing the Pocket-PC functionality on an Android-based scanning device, and removing the Apache layer from the architecture. In the Android app, I've written a communication layer to access the server (service) directly (the same way the desktop does). The server has the ability to exec applications, so I've written a small one to just gather data, and call fastreport to format and print it.
Works great. No problem. ... in our development environment. It works in our office network with the server running on a Windows 7 system. It works when run from the command line on our customer's Windows 2008 server. It does not work when run from the service on the customer's server.
So here's the code. In my current revision, I have try/catch and debug print statements around (nearly) every line of code. I removed them for readability.
bool __fastcall TFormReportRunner::mySetPrinter(const char* name)
{
char pDevice[MAX_PATH];
char pDriver[MAX_PATH];
char APort[100];
UINT ADeviceMode;
bool printerFound = false;
bool errorFound = false;
String PrinterPort = String(name).UpperCase();
TPrinter* Prntr;
// I added this bit to see if it helps. Seems to make no difference
bool rc = SetDefaultPrinter("");
Prntr = Printer();
if (Prntr == NULL)
{
LogErrorMsg("Printer() returned null.");
return false;
}
int i = Prntr->Printers->Count - 1;
for (; i >= 0; i--)
{
// In the failing case, this next statement is the one that causes an exception.
Prntr->PrinterIndex = i;
Prntr->GetPrinter(pDevice, pDriver, APort, ADeviceMode);
DWORD SizeNeeded = 0;
HANDLE PrinterHandle;
if (OpenPrinter(pDevice, &PrinterHandle, NULL) == 0)
{
LogErrorMsg("Could not open printer");
return false;
}
GetPrinter(PrinterHandle, 2, NULL, 0, &SizeNeeded);
if (SizeNeeded == 0)
{
ClosePrinter(PrinterHandle);
LogErrorMsg("Could not retrieve printer info size");
return false;
}
PRINTER_INFO_2 PrinterInfo2;
char* buffer = new char[SizeNeeded];
if (GetPrinter(PrinterHandle, 2, buffer, SizeNeeded, &SizeNeeded) == 0)
{
ClosePrinter(PrinterHandle);
delete [] buffer;
LogErrorMsg("Could not retrieve printer info");
return false;
}
String PortName = ((PRINTER_INFO_2*)buffer)->pPortName;
delete [] buffer;
ClosePrinter(PrinterHandle);
if (PrinterPort == PortName)
{
frxReport1->PrintOptions->Printer = pDevice;
break;
}
}
Prntr->PrinterIndex = i;
return true;
}
One of the customer's IT guys says that in order to have the Apache version work they have to run Apache as administrator with a defined default printer AND have that admin account logged in for printing to work. He suspects that if we run our service in the same configuration it will start to work. I have not been able to replicate that on our network. My admin account always works, whether anyone is currently logged into the system, or not. But this is Windows 7/Professional, and not a server version.
This has got to be possible... Apache's doing it. If it can find a printer and print to it, I should be able to, right?
Any hints or help will be greatly appreciated. Anything. Really. :)
Thanks,
-Karen
Edit: Adding server-side code.
A couple of notes, first. One, this was written 20-ish years ago (by someone else). Two, it is NOT a VCL app (and was compiled with the Microsoft compiler). Three, we will not change it. Recompiling with current compilers is WAY too risky for something that is otherwise working.
int myServer::RunProcess2(ClientCall *call, vector<string> &args, vector<string> &env, const char* input, unsigned int insize,
string *output, string *error)
{
CancelProcess2(); // only one process allowed per connection
string cmdline;
for (unsigned int i = 0; i < args.size(); i++)
{
if (i != 0)
cmdline += ' ';
cmdline += args[i];
}
env.push_back(EnvPATH);
int size = 1;
for (unsigned int i = 0; i < env.size(); i++)
{
size += env[i].size() + 1;
}
char *environment = (char*)malloc(size);
if (environment == NULL)
{
call->error = "Could not allocate memory for process environment variables";
return 0;
}
char *ptr = environment;
for (unsigned int i = 0; i < env.size(); i++)
{
size = env[i].size() + 1;
memcpy(ptr, env[i].c_str(), size);
ptr += size;
}
ptr[0] = '\0';
HANDLE hInputReadPipe = NULL, hInputWritePipe = NULL;
HANDLE hReadPipe, hWritePipe;
HANDLE hErrorReadPipe, hErrorWritePipe;
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = true;
// create output pipe
if (CreatePipe(&hReadPipe, &hWritePipe, &sa, 4096) == 0)
{
free(environment);
call->error = "Error creation Pipe";
return 0;
}
// create error pipe
if (CreatePipe(&hErrorReadPipe, &hErrorWritePipe, &sa, 4096) == 0)
{
CloseHandle(hReadPipe);
CloseHandle(hWritePipe);
free(environment);
call->error = "Error creating Pipe";
return 0;
}
if (insize > 0)
{
// create input pipe
if (CreatePipe(&hInputReadPipe, &hInputWritePipe, &sa, 4096) == 0)
{
CloseHandle(hReadPipe);
CloseHandle(hWritePipe);
CloseHandle(hErrorReadPipe);
CloseHandle(hErrorWritePipe);
free(environment);
call->error = "Error creating Pipe";
return 0;
}
}
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.wShowWindow = SW_HIDE;
si.hStdOutput = hWritePipe;
si.hStdError = hErrorWritePipe;
si.hStdInput = hInputReadPipe;
PROCESS_INFORMATION pi;
if (CreateProcess(NULL, (char*)cmdline.c_str(), NULL, NULL, true, 0, environment, NULL, &si, &pi) == 0)
{
CloseHandle(hErrorReadPipe);
CloseHandle(hErrorWritePipe);
CloseHandle(hReadPipe);
CloseHandle(hWritePipe);
if (hInputReadPipe != NULL)
{
CloseHandle(hInputReadPipe);
CloseHandle(hInputWritePipe);
}
free(environment);
call->error = string("Error executing command: ") + cmdline + "\n" + GetErrorText();
return 0;
}
report_handle = pi.hProcess;
CloseHandle(hErrorWritePipe);
CloseHandle(hWritePipe);
if (hErrorReadPipe != NULL)
CloseHandle(hInputReadPipe);
char buffer[4097];
DWORD BytesAvail;
DWORD BytesRead = 0;
DWORD BytesWritten = 0;
DWORD BytesToRead = sizeof(buffer) - 1;
DWORD BytesToWrite = insize;
bool finished_readpipe = false, finished_errorpipe = false;
bool finished_inputpipe = (insize == 0);
int wait_time = 1;
bool error_occurred = false;
while (finished_readpipe == false || finished_errorpipe == false || finished_inputpipe == false)
{
if (finished_inputpipe == false)
{
if (BytesToWrite <= 0)
{
CloseHandle(hInputWritePipe);
hInputWritePipe = NULL;
finished_inputpipe = true;
continue;
}
BytesAvail = 1000;
/*if (PeekNamedPipe(hInputWritePipe, NULL, NULL, NULL, &BytesAvail, NULL) == 0)
{
DWORD temp = GetLastError();
// pipe has been closed
finished_inputpipe = true;
continue;
}*/
if (BytesAvail > 0)
{
if (BytesAvail > BytesToWrite)
BytesAvail = BytesToWrite;
if (WriteFile(hInputWritePipe, input, BytesAvail, &BytesWritten, NULL) == 0)
{
if (GetLastError() == ERROR_NO_DATA)
{
int a = 2; // Pipe was closed (normal exit path).
}
finished_inputpipe = true;
continue;
}
input += BytesWritten;
BytesToWrite -= BytesWritten;
if (BytesToWrite == 0)
{
finished_inputpipe = true;
}
continue;
}
}
if (finished_readpipe == false)
{
while (true)
{
if (PeekNamedPipe(hReadPipe, NULL, NULL, NULL, &BytesAvail, NULL) == 0)
{
// pipe has been closed
finished_readpipe = true;
break;
}
if (BytesAvail <= 0)
break;
if (BytesAvail > sizeof(buffer) - 1)
BytesAvail = sizeof(buffer) - 1;
if (ReadFile(hReadPipe, buffer, BytesAvail, &BytesRead, NULL) == 0)
{
finished_readpipe = true;
break;
}
if (BytesRead == 0)
{
finished_readpipe = true;
break;
}
buffer[BytesRead] = '\0';
*output += buffer;
if (output->length() >= MAX_PROCESS_OUTPUT)
{
finished_inputpipe = true;
finished_readpipe = true;
finished_errorpipe = true;
error_occurred = true;
call->error = "Output limit reached";
}
}
if (finished_readpipe == true)
continue;
}
if (finished_errorpipe == false)
{
while (true)
{
if (PeekNamedPipe(hErrorReadPipe, NULL, NULL, NULL, &BytesAvail, NULL) == 0)
{
// pipe has been closed
finished_errorpipe = true;
break;
}
if (BytesAvail <= 0)
break;
if (BytesAvail > sizeof(buffer) - 1)
BytesAvail = sizeof(buffer) - 1;
if (ReadFile(hErrorReadPipe, buffer, BytesAvail, &BytesRead, NULL) == 0)
{
finished_errorpipe = true;
break;
}
if (BytesRead == 0)
{
finished_errorpipe = true;
break;
}
buffer[BytesRead] = '\0';
*error += buffer;
if (error->length() >= MAX_PROCESS_OUTPUT)
{
finished_inputpipe = true;
finished_readpipe = true;
finished_errorpipe = true;
error_occurred = true;
call->error = "Error output limit reached";
}
}
if (finished_errorpipe == true)
continue;
}
// don't tie up the server
if (wait_time < 100)
wait_time++;
Sleep(wait_time);
}
if (error_occurred == false)
WaitForSingleObject(pi.hProcess, INFINITE);
process_mutex.lock();
report_handle = NULL;
process_mutex.unlock();
DWORD exit_code = 0;
GetExitCodeProcess(pi.hProcess, &exit_code);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
CloseHandle(hReadPipe);
CloseHandle(hErrorReadPipe);
if (hInputWritePipe != NULL)
CloseHandle(hInputWritePipe);
free(environment);
return exit_code;
}
I am using fread function to read file, which I am sending via TCP. I found out, that fread doesn't read the whole file, if the file is binary. I tried everything what i found on the internet, but nothing helped. My code is:
#define BUFSIZE 1024
char buf[BUFSIZE];
FILE *file = fopen(soubor,"rb"); //I do a check which i won't write here
size_t bytes_loaded = 0;
while (!feof(file))
{
bytes_loaded = fread(buf,1,BUFSIZE,file);
if(bytes_loaded != BUFSIZE)
{
if(!feof(file))
{
for(int i = 0; i < 100;i++)
{
fseek(file,-strlen(buf),SEEK_CUR);
bytes_loaded = fread(buf,1,BUFSIZE,file);
if(bytes_loaded == BUFSIZE)
{
break;
}
else if(i == 99)
{
fprintf(stderr,"C could't read the file\n");
fclose(file);
close(client_socket);
return 1;
}
}
}
}
bytestx = send(client_socket, buf, BUFSIZE, 0);
if (bytestx < 0)
perror("ERROR in sendto");
bzero(buf, BUFSIZE);
bytes_loaded = 0;
}
Am I doing something wrong? For example that fread check...
Your whole fread() error handling is wrong, get rid of it (using strlen() on a binary buffer is wrong anyway).
In fact, you shouldn't be using feof() to control your loop. Simply call fread() in a loop until it returns < 1 on EOF or error (use feof() and ferror() to differentiate). And when it returns > 0, you need to pass that value to send instead of passing BUFSIZE.
Try something more like this:
#define BUFSIZE 1024
char buf[BUFSIZE], *pbuf;
FILE *file = fopen(soubor, "rb");
...
size_t bytes_loaded;
do
{
bytes_loaded = fread(buf, 1, BUFSIZE, file);
if (bytes_loaded < 1)
{
if ((!feof(file)) && ferror(file))
fprintf(stderr, "Couldn't read the file\n");
break;
}
pbuf = buf;
do
{
bytestx = send(client_socket, pbuf, bytes_loaded, 0);
if (bytestx < 0)
{
perror("ERROR in send");
break;
}
pbuf += bytestx;
bytes_loaded -= bytestx;
}
while (bytes_loaded > 0);
}
while (bytes_loaded == 0);
fclose(file);
...
If you are just shifting bytes from the file to the socket then you can just keep looping on the return value from std::fread which tells you how many bytes you read and then send exactly that many bytes to your send() command.
Something like this (untested) code:
if(FILE* fp = std::fopen(soubor, "rb"))
{
char buf[1024];
std::size_t bytesrx;
while((bytesrx = std::fread(0, 1, sizeof(buf), fp)) > 0)
{
int bytestx;
if((bytestx = send(client_socket, buf, bytesrx, 0) < 0))
{
// socket error
std::cout << "socket error: " << std::strerror(errno) << '\n';
return EXIT_FAILURE;
}
}
if(bytesrx < 0)
{
// file error
std::cout << "file error: " << std::strerror(errno) << '\n';
return EXIT_FAILURE;
}
}
else
{
// error opening file
}
I have an interruptions problem. I am working in an application which has to handle many buttons by interruptions. I am using this program to handle one:
int main(){
gpio_export(gpio);
gpio_set_dir(gpio, 0);
gpio_set_edge(gpio, "falling");
gpio_fd = gpio_fd_open(gpio);
timeout = POLL_TIMEOUT;
while (1) {
memset((void*)fdset, 0, sizeof(fdset));
fdset[0].fd = STDIN_FILENO;
fdset[0].events = POLLIN;
fdset[1].fd = gpio_fd;
fdset[1].events = POLLPRI;
rc = poll(fdset, nfds, timeout);
if (rc < 0) {
printf("\npoll() failed!\n");
return -1;
}
if (rc == 0) {
printf(".");
}
if (fdset[1].revents & POLLPRI) {
len = read(fdset[1].fd, buf, MAX_BUF);
printf("\npoll() GPIO %d interrupt occurred\n", gpio);
}
if (fdset[0].revents & POLLIN) {
(void)read(fdset[0].fd, buf, 1);
printf("POLLIN");
//printf("\npoll() stdin read 0x%2.2X\n", (unsigned int) buf[0]);
}
fflush(stdout);
}
gpio_fd_close(gpio_fd);
gpio_fd_close(gpio_fd2);
return 0;
}
It is working perfectly, my problem is that what I want to do is handle more interruptions so what I tried is this:
while (1) {
memset((void*)fdset, 0, sizeof(fdset));
fdset[0].fd = STDIN_FILENO;
fdset[0].events = POLLIN;
fdset[1].fd = gpio_fd;
fdset[1].events = POLLPRI;
rc = poll(fdset, nfds, timeout);
memset((void*)fdset2, 0, sizeof(fdset2));
fdset2[0].fd = STDIN_FILENO;
fdset2[0].events = POLLIN;
fdset2[1].fd = gpio_fd2;
fdset2[1].events = POLLPRI;
rc2 = poll(fdset2, nfds, timeout);
if (rc < 0 || rc2 < 0) {
printf("\npoll() failed!\n");
return -1;
}
if (rc == 0 || rc2==0) {
printf(".");
}
if (fdset[1].revents & POLLPRI) {
len = read(fdset[1].fd, buf, MAX_BUF);
printf("\npoll() GPIO %d interrupt occurred\n", gpio);
}
if (fdset2[1].revents & POLLPRI) {
len = read(fdset2[1].fd, buf, MAX_BUF);
printf("\npoll() GPIO %d interrupt occurred\n", gpio2);
}
if (fdset[0].revents & POLLIN) {
(void)read(fdset[0].fd, buf, 1);
printf("POLLIN");
//printf("\npoll() stdin read 0x%2.2X\n", (unsigned int) buf[0]);
}
if (fdset2[0].revents & POLLIN) {
(void)read(fdset2[0].fd, buf, 1);
printf("POLLIN");
//printf("\npoll() stdin read 0x%2.2X\n", (unsigned int) buf[0]);
}
fflush(stdout);
}
gpio_fd_close(gpio_fd);
gpio_fd_close(gpio_fd2);
return 0;
}
Basically I tried to handle two interruptions in the same program, but when I push any button nothing happend. What can I do that? shall I use threads?
Thank you guys
You have to merge fdset-s before you call poll. Basically the program waits at first poll call instead of waiting on first and second in parralel. So you can use threads or call one poll for all fdset-s and once.
I want to send a file from a Linux server to a Windows client through sockets, the problem is that I receive more bytes than I send.
Server code----------------------------------------------
if (resultEnviarLongitud = send(ClientSocket,GotFileSize.c_str(),1024,0)<0){
cout<<endl<<"Error mandando la longitud! "<<endl;
}
rewind(fs);
while ((len = fread(Buffer,1,1024, fs)) > 0)
{
if((resultEnviar = send(ClientSocket,Buffer,1024,0)) < 0){
printf("ERROR: Failed to send file %s.\n", nombreArchivoADescargar.c_str());
break;
}
sumEnviada+=len;
}
send(ClientSocket,"Hi",sizeof(Buffer),0);
cout<<"Bytes enviados: "<<sumEnviada<<endl;
strcpy(data, "");
cout<<endl<<"ARCHIVO MANDADO EXITOSAMENTE!"<<endl;
rutaArchivoADescargar.clear();
Client code-----------------------------------------
if (resultRecibirLongitud = recv(sock, Buffer, sizeof(Buffer), 0) > 0)
{
LongitudArchivo = atoi(Buffer);
cout<<endl<<"Longitud Archivo a Recibir: " <<LongitudArchivo<<endl;
}
FILE *fp=fopen("imagen.jpg","wb");
if (fp==NULL){
cout<<"Error al crear archivo."<<endl;
}else{
bzero(Buffer2, 1024);
int fr_block_sz = 0;
int contador=0;
//shutdown(sock, SD_SEND); I HAVE TO USE IT?
while((fr_block_sz = recv(sock, Buffer2, 1024, 0)) >= 0)
{
if (fr_block_sz == 0) break;
if ( strcmp (Buffer,"Hi") == 0) break;
int write_sz = fwrite(Buffer2, 1, 1024, fp);
if(write_sz < fr_block_sz)
{
printf("File write failed on server.\n");
}
bzero(Buffer2, 1024);
contador+=fr_block_sz;
if (contador >= LongitudArchivo)break;
bzero(Buffer2, 1024);
}
cout<<endl<<"Numero de bytes recibidos: "<<contador<<endl<<endl;
if(fr_block_sz < 0)
{
printf("Error receiving file from client to server.\n");
}
printf("Ok received from client!\n");
fclose(fp);
}
Thanks,
while ((len = fread(Buffer,1,1024, fs)) > 0)
{
if((resultEnviar = send(ClientSocket,Buffer,1024,0)) < 0)
One of your issues is that you always send 1024 bytes of the buffer even if you fread fewer bytes. (Note that 1348656 rounded up to the nearest multiple of 1024 is 1349632.)
So, on the write side you want something like:
while ((len = fread(Buffer,1,1024, fs)) > 0)
{
if((resultEnviar = send(ClientSocket,Buffer,len,0)) < 0)
and on the read side you want something like:
while((fr_block_sz = recv(sock, Buffer2, 1024, 0)) >= 0)
{
// ...
int write_sz = fwrite(Buffer2, 1, fr_block_sz, fp);
Your initial send is also problematic as you always send 1024 bytes with no check that this is the actual length of what is returned by c_str.