What would be the best way to do an scp or sftp copy in a Unix environment using C?
I'm interested in knowing the best library to use and an example if at all possible. I'm working on a Solaris server with the Sun tools installed.
Try Libcurl
libcurl is a free and easy-to-use client-side URL transfer library, supporting DICT, FILE, > FTP, FTPS, Gopher, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, Telnet and TFTP. libcurl supports SSL certificates, HTTP POST, HTTP PUT, FTP uploading, HTTP form based upload, proxies, cookies, user+password authentication (Basic, Digest, NTLM, Negotiate, Kerberos), file transfer resume, http proxy tunneling and more!
libcurl is highly portable, it builds and works identically on numerous platforms, including Solaris, NetBSD, FreeBSD, OpenBSD, Darwin, HPUX, IRIX, AIX, Tru64, Linux, UnixWare, HURD, Windows, Amiga, OS/2, BeOs, Mac OS X, Ultrix, QNX, OpenVMS, RISC OS, Novell NetWare, DOS and more...
I'm not really a C expert, but I think you can use system() to run OS commands. This would assume that you don't actually want to re-implement scp, just use it.
I've always just used the system() command. Of course doing this requires that you have SSH keys properly installed between the client and target machine so that it doesn't prompt for the password.
You can use libssh for sftp. I put some code here for you which has Pause/Resume and works on Windows. For Linux, you need to replace local file handling functions. I cannot copy the entire class because it will exceed this website limit. Change username and password and hostname to proper equivalents of your SFTP server:
int main(array<System::String ^> ^args)
{
//Console::WriteLine(L"Hello World");
pSFTPConnector sshc = new SFTPConnector(L".\\", L"127.0.0.1", 22, L"iman", L"iman"); // Change the hostname, port, username, password to your SFTP server, your credentials
//FILE *nullfile = fopen("null", "w");
//sshc->setLogFile(nullfile);
sshc->setVerbosity(SSH_LOG_RARE); // You can change the verbosity as appropriate for you
int i = sshc->InitSession();
i = sshc->ConnectSession();
i = sshc->InitSFTP();
//i = sshc->SFTPrename("renamed_myfile.txt", "myfile.txt"); // Change these file names
//i = sshc->Makedir("sftpdir");
//i = sshc->testUploadFile("myfile2.txt", "1234567890testfile");
// Change these file names to whatever appropriate
//i = sshc->SFTPget("c:\\testdir\\Got_CAR_HIRE_FINAL_test.jpg", "CAR_HIRE_FINAL_test.jpg", 64*1024);
i = sshc->SFTPget("c:\\testdir\\get_downloaded_CAR_HIRE_FINAL.jpg", "CAR_HIRE_FINAL.jpg", 64 *1024);
i = sshc->SFTPreget("c:\\testdir\\reget_downloaded_CAR_HIRE_FINAL.jpg", "CAR_HIRE_FINAL.jpg", 64 * 1024);
i = sshc->SFTPput("c:\\testdir\\CAR_HIRE_FINAL.jpg", "put_CAR_HIRE_FINAL.jpg", 64 * 1024);
i = sshc->SFTPreput("c:\\testdir\\CAR_HIRE_FINAL.jpg", "reput_CAR_HIRE_FINAL.jpg", 64 * 1024);
delete sshc;
return 0;
}
typedef enum sshconerr {
E_OK = 1, E_SESSION_ALOC = -1, E_SSH_CONNECT_ERR = -2, E_SFTP_ALLOC = -3, E_INIT_SFTP = -4, E_CREATE_DIR = -5, E_FILEOPEN_WRITE = -6, E_WRITE_ERR = -7,
E_FILE_CLOSE = -8, E_FILE_OPEN_READ = -9, E_INVALID_PARAMS = -10, E_SFTP_ERR = -11, E_SFTP_READ_ERR = -12, E_SFTP_READBYTES_ERR = -13, E_GET_FILEINF = -14,
E_LOCAL_FILE_NOTFOUND = -15, E_RENAME_ERR = -16, E_MEM_ALLOC = -17, E_LOCAL_FILE_READ = -18, E_LOCAL_FILE_RDWR = -19, E_REMOTEFILE_SEEK = -20,
E_REMOTE_FILE_OPEN = -21, E_DELETE_ERR = -22, E_RENAME_LOCAL_FILE = -23, E_LOCAL_DELETE_FILE = -24, E_FILEOPEN_RDONLY = -25, E_SFTP_READ_EOF = -26,
E_UNKNOWN = -999
} ESSHERR;
// Status of transfers;
typedef enum sftpstat{ES_DONE=0, ES_INPROGRESS, ES_FAILED, ES_STARTING, ES_PAUSED, ES_RESUMING, ES_CANCELLED, ES_NONE } ESFTPSTAT;
using namespace std;
// Statistics about the transfer;
typedef struct transferstatstruct {
string remote_file_name;
string local_file_name;
__int64 total_size;
__int64 transferred;
__int64 averagebps;
long long seconds_elapsed;
long long seconds_remained;
int percent;
ESFTPSTAT transferstate;
} TTransStat;
#define E_SESSION_NEW -1
// These libraries are required
#pragma comment(lib, "ssh.lib")
// This is the main class that does the majority of the work
typedef class CSFTPConnector {
private:
ssh_session session; // SSH session
sftp_session sftp; // SFTP session
sftp_file file; // Structure for a remote file
FILE *localfile; // Not used on Windows, but it could be local file pointer in Unix
FILE *logfile; // The file for writing logs, default is set to stderr
string filename; // File name of the transfer;
string localfilename; // File name of local file;
string tempfilename; // A temporary file name will be used during the transfer which is renamed when transfer is completed.
ESFTPSTAT transferstatus; // State of the transfer which has one of the above values (ESFTPSTAT)
time_t transferstarttime; // Time of start of the transfer
wchar_t username[SHORT_BUFF_LEN];
wchar_t password[SHORT_BUFF_LEN];
wchar_t hostname[SHORT_BUFF_LEN]; // Hostname of the SFTP server
wchar_t basedir[SHORT_BUFF_LEN]; // This base directory is the directory of the public and private key structure (NOT USED IN THIS VERSION)
int port; // Port of the server;
int verbosity; // Degree of verbosity of libssh
__int64 filesize; // Total number of bytes to be transferred;
DWORD local_file_size_hiDWORD; // Bill Gates cannot accept the file size
// without twisting the programmers, so
// he accepts them in two separate words
// like this
DWORD local_file_size_lowDWORD; // These two DWORDs when connected together comprise a 64 bit file size.
__int64 lfilesize; // Local file size
__int64 rfilesize; // Remote file size
__int64 transferred; // Number of bytes already transferred
bool pause; // Pause flag
TTransStat stats; // Statistics of the transfer
HANDLE localfilehandle; // Windows uses handles to manipulate files. this is the handle to local file.
ESSHERR CSFTPConnector::rwopen_existing_SFTPfile(char *fn); // Open a file on remote (server) read/write for upload
ESSHERR CSFTPConnector::rdopen_existing_SFTPfile(char *fn); // Open a file on remote (server) read only for download
ESSHERR createSFTPfile(char *fn); // Create a file on server;
ESSHERR writeSFTPfile(char *block, size_t blocksize); // Write a block of data to the open remote file
ESSHERR readSFTPfile(char *block, size_t len, size_t *bytesread); // Read a block of data from the open remote file
ESSHERR readSFTPfile(char *block, __int64 len, DWORD *bytesread);
ESSHERR closeSFTPfile(); // Closes the remote file;
ESSHERR openSFTPfile(char *fn); // Opens the remote file
ESSHERR getSFTPfileinfo(); // Gets information about the remote file
public:
wstring errstring; // The string describing last error
ESSHERR Err; // Error code of last error
CSFTPConnector(); // Default constructor;
CSFTPConnector(wchar_t *dir, wchar_t *hn, int hostport, wchar_t *un, wchar_t *pass); // Constructor
void setVerbosity(int v);
int getVerbosity();
ESSHERR InitSession(); // Must be called before doing any transfer
ESSHERR ConnectSession(); // Connects to the SSH server
ESSHERR InitSFTP(); // Must be called before doing any transfer
ESSHERR Makedir(char *newdir);
ESSHERR testUploadFile(char *fn, char *block); // Do not use this, only for test purposes for myself
ESSHERR SFTPput(char *lfn, char *rfn, size_t blocksize); // Upload a file from start
ESSHERR SFTPreput(char *lfn, char *rfn, size_t blocksize); // Checks for previouse interrupted transfer, then
// either continues the previous transfer (if
// there was any) or starts a new one (UPLOAD)
ESSHERR SFTPrename(char *newname, char *oldname); // Renames a remote file( must be closed)
ESSHERR CSFTPConnector::SFTPdelete(char *remfile); // Deletes a remote file
TTransStat getStatus(); // Gets statistics of the transfer
ESSHERR CSFTPConnector::SFTPget(char *lfn, char *rfn, size_t blocksize); // Downloads a file from the SFTP server
ESSHERR CSFTPConnector::SFTPreget(char *lfn, char *rfn, size_t blocksize); // Checks for a previous interrupted transfer,
// then either continues the previous transfer
// (if there was any) or starts a new one (DOWNLOAD).
void CancelTransfer();
void PauseTransfer();
void setLogFile(FILE *logf); // Sets the log file. If not set, standard
// error will be used. By default.
void CloseLocalFile();
void CloseRemoteFile();
~CSFTPConnector();
} SFTPConnector, *pSFTPConnector;
void CSFTPConnector::CloseLocalFile()
{
CloseHandle(localfilehandle);
}
void CSFTPConnector::CloseRemoteFile()
{
sftp_close(file);
}
void CSFTPConnector::setLogFile(FILE *logf)
{
logfile = logf;
}
void CSFTPConnector::CancelTransfer()
{
transferstatus = ES_CANCELLED;
}
void CSFTPConnector::PauseTransfer()
{
transferstatus = ES_PAUSED;
pause = true;
}
//----------------------------------------
ESSHERR CSFTPConnector::SFTPget(char *lfn, char *rfn, size_t blocksize)
{
DWORD result;
int rc;
BOOL bresult;
DWORD bytesread;
filesize = 0;
transferred = 0;
pause = false;
transferstatus = ES_NONE;
char *block;
struct stat st;
wchar_t temp[SHORT_BUFF_LEN];
size_t tempsize;
wstring wlfn;
int loopcounter = 0;
localfilename = lfn;
filename = rfn;
tempfilename = string(lfn) + ".sftp_temp";
mbstowcs_s(&tempsize, temp, tempfilename.c_str(), SHORT_BUFF_LEN);
localfilehandle = CreateFile(temp, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (localfilehandle == INVALID_HANDLE_VALUE)
{
transferstatus = ES_FAILED;
errstring = L"Could not open local file:" + wstring(temp) + L" for read and write";
Err = E_LOCAL_FILE_RDWR;
return E_LOCAL_FILE_RDWR;
}
lfilesize = 0;
transferred = 0;
block = (char*)malloc(blocksize + 1);
if (block == NULL) {
Err = E_MEM_ALLOC;
transferstatus = ES_FAILED;
errstring = L"Could not allocate memory for file block size";
CloseLocalFile();
return E_MEM_ALLOC;
}
result = rdopen_existing_SFTPfile((char *)rfn);
if (result == E_OK) {
getSFTPfileinfo();
filesize = rfilesize;
}
else
{
Err = E_REMOTE_FILE_OPEN;
transferstatus = ES_FAILED;
errstring = L"Could not open remote file";
CloseLocalFile();
delete block;
return E_REMOTEFILE_SEEK;
}
transferstatus = ES_STARTING;
sftp_file_set_blocking(file);
transferstarttime = time(NULL);
transferstatus = ES_INPROGRESS;
while (transferstatus != ES_FAILED &&
transferstatus != ES_PAUSED &&
transferstatus != ES_CANCELLED &&
transferstatus != ES_DONE)
{
loopcounter++;
result = readSFTPfile(block, blocksize, (size_t *)&bytesread);
if (result != E_OK && result!= E_SFTP_READ_EOF)
{
errstring = L"Error reading from remote SFTP server file.";
Err = (ESSHERR)result;
transferstatus = ES_FAILED;
CloseRemoteFile();
CloseLocalFile();
delete block;
return (ESSHERR)result;
}
if (result == E_SFTP_READ_EOF)
transferstatus = ES_DONE;
fprintf(logfile, "Read %d bytes from input file. Number of packets: %d, %llu from %llu bytes\n", bytesread, loopcounter, transferred, filesize);
bresult = WriteFile(localfilehandle, (LPVOID)block, bytesread, &bytesread, NULL);
if (bytesread < blocksize)
{
if (bresult == FALSE)
{
errstring = L"Error writing to local file.";
Err = E_LOCAL_FILE_RDWR;
transferstatus = ES_FAILED;
CloseRemoteFile();
CloseLocalFile();
delete block;
return E_LOCAL_FILE_RDWR;
}
else if (bytesread == 0)
{
errstring = L"Transfer done.";
Err = E_OK;
transferstatus = ES_DONE;
continue;
}
}
Err = E_OK;
if (pause == true)
transferstatus = ES_PAUSED;
if (bresult == TRUE && bytesread == 0)
{
// At the end of the file
transferstatus = ES_DONE;
}
Sleep(BLOCKTRANSDELAY);
if (loopcounter % 331 == 0)
Sleep(77 * BLOCKTRANSDELAY);
if (loopcounter % 3331 == 0)
Sleep(777 * BLOCKTRANSDELAY);
}
// Closing files
result = closeSFTPfile();
CloseHandle(localfilehandle);
Sleep(1000);
if (transferstatus == ES_DONE)
{
wchar_t temp2[SHORT_BUFF_LEN];
mbstowcs_s(&tempsize, temp2, lfn, SHORT_BUFF_LEN);
bresult = MoveFile(temp, temp2);
if (bresult != TRUE)
{
Err = E_RENAME_LOCAL_FILE;
errstring = L"Could not rename local file: " + wstring(temp);
transferstatus = ES_FAILED;
delete block;
return E_RENAME_LOCAL_FILE;
}
}
if (transferstatus == ES_CANCELLED)
{
wchar_t temp2[SHORT_BUFF_LEN];
mbstowcs_s(&tempsize, temp2, lfn, SHORT_BUFF_LEN);
bresult = DeleteFile(temp);
if (bresult != TRUE)
{
Err = E_LOCAL_DELETE_FILE;
errstring = L"Could not rename local file: " + wstring(temp);
transferstatus = ES_FAILED;
delete block;
return E_LOCAL_DELETE_FILE;
}
}
delete block;
return (ESSHERR) result;
}
TTransStat CSFTPConnector::getStatus()
{
stats.seconds_elapsed = time(NULL) - transferstarttime;
stats.averagebps = (transferred * 8) / stats.seconds_elapsed;
if (filesize > 0) {
stats.percent = (transferred *100)/ filesize;
stats.seconds_remained = ((filesize - transferred) * 8) / stats.averagebps;
}
else
{
stats.percent = -1;
stats.seconds_remained = -1;
}
stats.total_size = filesize;
stats.transferstate = transferstatus;
stats.remote_file_name = filename;
stats.local_file_name = localfilename;
return stats;
}
ESSHERR CSFTPConnector::SFTPrename(char *newname, char *oldname)
{
int rc = sftp_rename(sftp, oldname, newname);
if (rc != SSH_OK) {
return E_RENAME_ERR;
}
return E_OK;
}
ESSHERR CSFTPConnector::SFTPdelete(char *remfile)
{
int rc = sftp_unlink(sftp, remfile);
if (rc != SSH_OK) {
return E_DELETE_ERR;
}
return E_OK;
}
ESSHERR CSFTPConnector::SFTPreput(char *lfn, char *rfn, size_t blocksize)
{
ESSHERR result;
BOOL bresult;
DWORD bytesread;
filesize = 0;
transferred = 0;
pause = false;
transferstatus = ES_NONE;
char *block;
struct stat st;
wchar_t temp[SHORT_BUFF_LEN];
size_t tempsize;
wstring wlfn;
int loopcounter = 0;
localfilename = lfn;
//wlfn = wstring(lfn);
//localfile = fopen(lfn, L"r");
filename = rfn;
mbstowcs_s(&tempsize, temp, lfn, SHORT_BUFF_LEN);
//filesize = getFileSize(localfilename);
/*if (filesize < 0) {
transferstatus = ES_FAILED;
Err = E_LOCAL_FILE_NOTFOUND;
return E_LOCAL_FILE_NOTFOUND;
}*/
localfilehandle = CreateFile(temp, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (localfilehandle == INVALID_HANDLE_VALUE)
{
transferstatus = ES_FAILED;
Err = E_LOCAL_FILE_NOTFOUND;
return E_LOCAL_FILE_NOTFOUND;
}
local_file_size_lowDWORD = GetFileSize(localfilehandle, &local_file_size_hiDWORD);
filesize = (local_file_size_hiDWORD * 0x100000000) + local_file_size_lowDWORD;
if (filesize < 0) {
transferstatus = ES_FAILED;
Err = E_LOCAL_FILE_NOTFOUND;
CloseLocalFile();
return E_LOCAL_FILE_NOTFOUND;
}
block = (char*)malloc(blocksize + 1);
if (block == NULL) {
Err = E_MEM_ALLOC;
transferstatus = ES_FAILED;
errstring = L"Could not allocate memory for file block size";
CloseLocalFile();
return E_MEM_ALLOC;
}
tempfilename = string(rfn) + ".sftp_temp";
result = rwopen_existing_SFTPfile((char *)tempfilename.c_str());
if (result == E_OK) {
getSFTPfileinfo();
sftp_seek64(file, rfilesize);
__int64 tempi64 = rfilesize & 0x00000000FFFFFFFF;
DWORD dwlow = tempi64;
tempi64 = (rfilesize & 0x7FFFFFFF00000000);
tempi64 = tempi64 >> 32;
long dwhi = tempi64;
DWORD dwResult = SetFilePointer(localfilehandle, dwlow, &dwhi, FILE_BEGIN);
if (dwResult == INVALID_SET_FILE_POINTER)
{
transferstatus = ES_FAILED; Err = result; return result;
}
transferstatus = ES_RESUMING;
transferred = rfilesize;
}
else{
result = createSFTPfile((char *)tempfilename.c_str());
transferstatus = ES_STARTING;
if (result != E_OK) {
transferstatus = ES_FAILED;
Err = result;
CloseLocalFile();
return result;
}
}
sftp_file_set_blocking(file);
transferstarttime = time(NULL);
transferstatus = ES_INPROGRESS;
while (transferstatus != ES_FAILED &&
transferstatus != ES_PAUSED &&
transferstatus != ES_DONE)
{
loopcounter++;
bresult = ReadFile(localfilehandle, (LPVOID)block, blocksize, &bytesread, NULL);
fprintf(logfile, "Read %d bytes from input file. Number of packets: %d, %llu from %llu bytes\n", bytesread, loopcounter, transferred, filesize);
if (bytesread < blocksize)
{
if (bresult == FALSE)
{
errstring = L"Error reading from local file.";
Err = E_LOCAL_FILE_READ;
transferstatus = ES_FAILED;
CloseRemoteFile();
CloseLocalFile();
return E_LOCAL_FILE_READ;
}
else if (bytesread == 0)
{
errstring = L"Transfer done.";
Err = E_OK;
transferstatus = ES_DONE;
continue;
}
}
result = writeSFTPfile(block, bytesread);
if (result != E_OK && bytesread>0)
{
errstring = L"Error transmitting to remote SFTP server file.";
Err = result;
transferstatus = ES_FAILED;
CloseRemoteFile();
CloseLocalFile();
return result;
}
Err = E_OK;
//transferred = transferred + bytesread;
if (pause == true)
transferstatus = ES_PAUSED;
if (bresult == TRUE && bytesread == 0)
{
// At the end of the file
transferstatus = ES_DONE;
}
Sleep(BLOCKTRANSDELAY);
if (loopcounter % 331 == 0)
Sleep(77 * BLOCKTRANSDELAY);
if (loopcounter % 3331 == 0)
Sleep(777 * BLOCKTRANSDELAY);
}
CloseRemoteFile();
CloseLocalFile();
Sleep(1000);
if (transferstatus == ES_CANCELLED)
{
result = SFTPdelete((char *)tempfilename.c_str());
if (bresult != E_OK)
{
Err = E_DELETE_ERR;
errstring = L"Could not delete remote file.";
transferstatus = ES_FAILED;
return E_DELETE_ERR;
}
}
if (transferstatus == ES_DONE)
result = SFTPrename(rfn, (char *)tempfilename.c_str());
delete block;
return result;
}
ESSHERR CSFTPConnector::getSFTPfileinfo()
{
sftp_attributes fileinf = sftp_fstat(file);
if (fileinf == NULL) {
return E_GET_FILEINF;
}
rfilesize = fileinf->size;
sftp_attributes_free(fileinf);
return E_OK;
}
ESSHERR CSFTPConnector::closeSFTPfile()
{
int rc = sftp_close(file);
if (rc != SSH_OK)
{
fprintf(logfile, "Can't close the written file: %s\n",
ssh_get_error(session));
return E_FILE_CLOSE;
}
return E_OK;
}
ESSHERR CSFTPConnector::writeSFTPfile(char *block, size_t blocksize)
{
size_t nwritten = sftp_write(file, block, blocksize);
if (nwritten != blocksize)
{
fprintf(logfile, "Can't write data to file: %s\n",
ssh_get_error(session));
//sftp_close(file);
transferred = transferred + nwritten;
return E_WRITE_ERR;
}
transferred = transferred + nwritten;
return E_OK;
}
ESSHERR CSFTPConnector::readSFTPfile(char *block, size_t len, size_t *bytesread)
{
DWORD readbytes;
*bytesread = 0;
if (len <= 0)
return E_INVALID_PARAMS;
if (bytesread == NULL || block == NULL)
return E_INVALID_PARAMS;
readbytes = sftp_read(file, block, len);
if (readbytes < 0)
{
fprintf(logfile, "Can't read from remote file: %s %s\n", filename.c_str(), ssh_get_error(session));
*bytesread = 0;
return E_SFTP_READ_ERR;
}
if (readbytes < len)
{
*bytesread = readbytes;
transferred = transferred + readbytes;
return E_SFTP_READ_EOF;
}
*bytesread = readbytes;
transferred = transferred + readbytes;
return E_OK;
}
ESSHERR CSFTPConnector::readSFTPfile(char *block, __int64 len, DWORD *bytesread)
{
DWORD readbytes;
*bytesread = 0;
if (len <= 0)
return E_INVALID_PARAMS;
if (bytesread == NULL || block == NULL)
return E_INVALID_PARAMS;
readbytes = sftp_read(file, block, len);
if (readbytes < 0)
{
fprintf(logfile, "Can't read from remote file: %s %s\n", filename.c_str(), ssh_get_error(session));
*bytesread = 0;
return E_SFTP_READ_ERR;
}
if (readbytes < len)
{
*bytesread = readbytes;
return E_SFTP_READ_EOF;
}
*bytesread = readbytes;
transferred = transferred + readbytes;
return E_OK;
}
ESSHERR CSFTPConnector::createSFTPfile(char *fn)
{
int access_type = O_CREAT | O_RDWR;
int rc, nwritten;
filename = string(fn);
file = sftp_open(sftp, fn,
access_type, S_IWRITE);
if (file == NULL)
{
fprintf(logfile, "Can't open file for writing: %s\n",
ssh_get_error(session));
return E_FILEOPEN_WRITE;
}
return E_OK;
}
ESSHERR CSFTPConnector::rdopen_existing_SFTPfile(char *fn)
{
int access_type = O_RDONLY;
int rc, nwritten;
filename = string(fn);
file = sftp_open(sftp, fn,
access_type, S_IREAD);
if (file == NULL)
{
fprintf(logfile, "Can't open file for writing: %s\n",
ssh_get_error(session));
return E_FILEOPEN_RDONLY;
}
return E_OK;
}
ESSHERR CSFTPConnector::openSFTPfile(char *fn)
{
int access_type = O_RDONLY;
int rc, nwritten;
filename = string(fn);
file = sftp_open(sftp, fn,
access_type, S_IWRITE);
if (file == NULL)
{
fprintf(logfile, "Can't open file for writing: %s\n",
ssh_get_error(session));
return E_FILE_OPEN_READ;
}
return E_OK;
}
ESSHERR CSFTPConnector::Makedir(char *newdir)
{
int rc;
rc = sftp_mkdir(sftp, newdir, S_IFDIR);
if (rc != SSH_OK)
{
if (sftp_get_error(sftp) != SSH_FX_FILE_ALREADY_EXISTS)
{
fprintf(logfile, "Can't create directory: %s\n",
ssh_get_error(session));
return E_CREATE_DIR;
}
}
return E_OK;
}
SFTPConnector::CSFTPConnector()
{
//libssh2_init(0);
session = ssh_new();
if (session == NULL)
{
Err = E_SESSION_ALOC;
errstring = L"Could not allocate a session.";
}
wcscpy(hostname, L"localhost");
wcscpy(username, L"User");
wcscpy(password, L"Password");
wcscpy(basedir, L".\\");
port = 22;
verbosity = SSH_LOG_RARE;
filesize = 0;
transferred = 0;
pause = false;
transferstatus = ES_NONE;
logfile = stderr;
}
CSFTPConnector::CSFTPConnector(wchar_t *dir, wchar_t *hn, int hostport, wchar_t *un, wchar_t *pass)
{
session = ssh_new();
if (session == NULL)
{
Err = E_SESSION_ALOC;
errstring = L"Could not allocate a session.";
}
wcscpy(hostname, hn);
wcscpy(username, un);
wcscpy(password, pass);
wcscpy(basedir, dir);
port = hostport;
verbosity = SSH_LOG_RARE;
filesize = 0;
transferred = 0;
pause = false;
transferstatus = ES_NONE;
logfile = stderr;
}
ESSHERR CSFTPConnector::InitSFTP()
{
int rc;
sftp = sftp_new(session);
if (session == NULL)
{
Err = E_SFTP_ALLOC;
errstring = L"Could not allocate a sftp session.";
}
rc = sftp_init(sftp);
if (rc != SSH_OK)
{
fprintf(logfile, "Error initializing SFTP session: %s.\n",
sftp_get_error(sftp));
sftp_free(sftp);
return E_INIT_SFTP;
}
return E_OK;
}
ESSHERR CSFTPConnector::ConnectSession()
{
char temp[SHORT_BUFF_LEN];
size_t n_of_chars;
wcstombs_s(&n_of_chars, temp, SHORT_BUFF_LEN, (const wchar_t *)password, SHORT_BUFF_LEN);
int ir;
ir = ssh_connect(session);
if (ir != SSH_OK) {
errstring = L"Could not connect the ssh session.";
return E_SSH_CONNECT_ERR;
}
ir = ssh_userauth_password(session, NULL, temp);
if (ir != SSH_OK) {
errstring = L"Could not connect the ssh session.";
return E_SSH_CONNECT_ERR;
}
return E_OK;
}
ESSHERR CSFTPConnector::InitSession()
{
char temp[SHORT_BUFF_LEN];
size_t n_of_chars;
wcstombs_s(&n_of_chars, temp, SHORT_BUFF_LEN, (const wchar_t *) hostname, SHORT_BUFF_LEN);
ssh_options_set(session, SSH_OPTIONS_HOST, temp);
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
ssh_options_set(session, SSH_OPTIONS_PORT, &port);
wcstombs_s(&n_of_chars, temp, SHORT_BUFF_LEN, (const wchar_t *)username, SHORT_BUFF_LEN);
ssh_options_set(session, SSH_OPTIONS_USER, temp);
wcstombs_s(&n_of_chars, temp, SHORT_BUFF_LEN, (const wchar_t *)basedir, SHORT_BUFF_LEN);
ssh_options_set(session, SSH_OPTIONS_SSH_DIR, temp);
return E_OK;
}
CSFTPConnector::~CSFTPConnector()
{
sftp_free(sftp);
ssh_disconnect(session);
ssh_free(session);
return;
}
In the past, I've simply called a shell script that contained the file transfer code.
int transferFile()
{
// Declare the transfer command
char transferCommand[50] = "/home/tyler/transferFile.shl";
// Execute the command
return system(transferCommand);
}
This will return 1 if the transfer command returns successfully.
Related
I am trying to unzip data in ZLIB using the uncompress function. the data to be decompressed is in a Char vector. the library was downloaded from github for C language. code below:
//C
unsigned char out[20000], u_out[20000];
size_t size_out;
unsigned char* in = ""; //non inserisco i dati di partenza per privacy
int err, i;
long int ucompSize_out;
long int compSize_out;
size_out=sizeof(out);
//codifica in base45
err=base45_decode(out,&size_out,in,strlen(in));
printf("\nbase45(%s) ", (char*)out);
printf("\n%d",err);
//decompressione zlib
ucompSize_out= strlen(out)+1;
compSize_out= compressBound(ucompSize_out);
err=uncompress ((Byte *)u_out, &ucompSize_out, (const Byte *) out, compSize_out );
printf("\nzlib(\"%s\") ", (char*)u_out);
printf("\n%d",err);
when I run this code it returns me BUF_ERROR (-5). I read on the Zlib guide that it is a problem of space for output or input but I can not figure out how to fix it
for completeness load also the functions recalled
int ZEXPORT uncompress2 (dest, destLen, source, sourceLen)
Bytef *dest;
uLongf *destLen;
const Bytef *source;
uLong *sourceLen;
{
z_stream stream;
int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
z_streamp strm;
int windowBits;
const char *version;
int stream_size;
{
int ret;
struct inflate_state FAR *state;
if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
stream_size != (int)(sizeof(z_stream)))
return Z_VERSION_ERROR;
if (strm == Z_NULL) return Z_STREAM_ERROR;
strm->msg = Z_NULL; /* in case we return an error */
if (strm->zalloc == (alloc_func)0) {
}
if (strm->zfree == (free_func)0)
state = (struct inflate_state FAR *)
ZALLOC(strm, 1, sizeof(struct inflate_state));
if (state == Z_NULL) return Z_MEM_ERROR;
Tracev((stderr, "inflate: allocated\n"));
strm->state = (struct internal_state FAR *)state;
state->strm = strm;
state->window = Z_NULL;
state->mode = HEAD; /* to pass state test in inflateReset2() */
ret = inflateReset2(strm, windowBits);
if (ret != Z_OK) {
ZFREE(strm, state);
strm->state = Z_NULL;
}
return ret;
}
int ZEXPORT inflateInit_(strm, version, stream_size)
z_streamp strm;
const char *version;
int stream_size;
{
return inflateInit2_(strm, DEF_WBITS, version, stream_size);
}
int err;
const uInt max = (uInt)-1;
uLong len, left;
Byte buf[1]; /* for detection of incomplete stream when *destLen == 0 */
len = *sourceLen;
if (*destLen) {
left = *destLen;
*destLen = 0;
}
else {
left = 1;
dest = buf;
}
stream.next_in = (z_const Bytef *)source;
stream.avail_in = 0;
stream.zalloc = (alloc_func)0;
stream.zfree = (free_func)0;
stream.opaque = (voidpf)0;
err = inflateInit2(&stream);
if (err != Z_OK) return err;
stream.next_out = dest;
stream.avail_out = 0;
do {
if (stream.avail_out == 0) {
stream.avail_out = left > (uLong)max ? max : (uInt)left;
left -= stream.avail_out;
}
if (stream.avail_in == 0) {
stream.avail_in = len > (uLong)max ? max : (uInt)len;
len -= stream.avail_in;
}
err = inflate(&stream, Z_NO_FLUSH);
} while (err == Z_OK);
*sourceLen -= len + stream.avail_in;
if (dest != buf)
*destLen = stream.total_out;
else if (stream.total_out && err == Z_BUF_ERROR)
left = 1;
inflateEnd(&stream);
return err == Z_STREAM_END ? Z_OK :
err == Z_NEED_DICT ? Z_DATA_ERROR :
err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR :
err;
}
int ZEXPORT uncompress (dest, destLen, source, sourceLen)
Bytef *dest;
uLongf *destLen;
const Bytef *source;
uLong sourceLen;
{
return uncompress2(dest, destLen, source, &sourceLen);
}
I am developing plugin for Pidgin. I want to share one of my windows that are open on my computer with other user via VNC. When I select the window to be shared and press the button, Pidgin freezes and closes.
Here is working well: opening vnc connection and sends Port name to other users. (but this one for sharing all of screen.)
static void
send_button_cb(GtkButton *button, PidginConversation *gtkconv)
{
gchar *url_vnc;
gchar *url_http;
gchar *joinstr;
int std_out[2];
int autoport = purple_prefs_get_bool(PREF_AUTOPORT);
char x11vnc_port[10] = "0";
if (purple_prefs_get_bool(PREF_X11VNC) && ((x11vnc_pid == 0) || (kill(x11vnc_pid, 0) != 0)))
{
if (purple_prefs_get_bool(PREF_GENPASSWD))
{
readableRandomString(password, 4);
}
else
{
strcpy(password, purple_prefs_get_string(PREF_PASSWD));
}
sprintf(x11vnc_port, "%d", 5900 + purple_prefs_get_int(PREF_PORT));
pipe(std_out);
if ((x11vnc_pid = fork()) == 0)
{
close(1);
close(std_out[0]);
dup2(std_out[1], 1);
close(std_out[1]);
int ret = execlp("x11vnc", "x11vnc", "-shared", "-gui", "tray", "-http", "-viewonly", "-passwd", password, ((autoport) ? "-autoport" : "-rfbport"), x11vnc_port, NULL);
perror("pidgin_vnc:x11vnc");
exit(ret);
}
close(std_out[1]);
port_num = x11vnc_port;
if (fd = fdopen(std_out[0], "r"))
{
while (!feof(fd))
{
if (fscanf(fd, "PORT=%d", &port_num))
break;
}
port_num -= 5900;
//close (fd);
printf("FINI\n");
}
else
{
port_num = x11vnc_port;
}
}
const char *ip;
PurpleStunNatDiscovery *stun_res = purple_stun_discover(NULL);
if (stun_res && stun_res->status == PURPLE_STUN_STATUS_DISCOVERED)
{
printf("STUN mode %d %d\n", stun_res->status, stun_res->type);
ip = purple_network_get_my_ip(-1);
}
else
{
ip = purple_upnp_get_public_ip();
if (ip == NULL)
{
printf("LOCAL mode\n");
ip = purple_network_get_my_ip(-1);
}
else
{
printf("UPNP mode\n");
}
}
url_http = g_strdup_printf("http://%s:%d/", ip, 5800 + port_num);
url_vnc = g_strdup_printf("vnc://invitation:%s#%s:%d", password, ip, port_num);
g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, url_vnc);
joinstr = g_strdup_printf("%s.\ntry %s\nor %s. Password=%s", purple_prefs_get_string(PREF_TEXT), url_vnc, url_vnc, url_http, url_http, password);
gtk_imhtml_append_text(GTK_IMHTML(gtkconv->entry), joinstr, FALSE);
g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "imhtml display vnc\n");
g_signal_emit_by_name(gtkconv->entry, "message_send");
g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "message sent\n");
g_free(url_vnc);
g_free(url_http);
g_free(joinstr);
}
There is a problem in here. When I click to button which is calling this function program crashes when you click the button.(this function for sharing one of my windows that are open on my computer.)
static void
send_button_cb_win(GtkButton *button, PidginConversation *gtkconv)
{
gchar *url_vnc;
gchar *url_http;
gchar *joinstr;
int std_out[2];
int comboBoxSelectedRow = gtk_combo_box_get_active(combo_box);
char *selectedId[1] = {0};
selectedId[0] = ekranIds[0][comboBoxSelectedRow];
int autoport = purple_prefs_get_bool(PREF_AUTOPORT);
char x11vnc_port[10] = "0";
if (purple_prefs_get_bool(PREF_X11VNC) && ((x11vnc_pid == 0) || (kill(x11vnc_pid, 0) != 0)))
{
if (purple_prefs_get_bool(PREF_GENPASSWD))
{
readableRandomString(password, 4);
}
else
{
strcpy(password, purple_prefs_get_string(PREF_PASSWD));
}
sprintf(x11vnc_port, "%d", 5900 + purple_prefs_get_int(PREF_PORT));
pipe(std_out);
if((x11vnc_pid = fork()) == 0)
{
close(1);
close(std_out[0]);
dup2(std_out[1], 1);
close(std_out[1]);
int ret = execlp("x11vnc", "x11vnc", "-id", selectedId[0], "-gui", "-shared", "tray", "-http", "-viewonly", "-passwd", password, ((autoport) ? "-autoport" : "-rfbport"), x11vnc_port, NULL);
perror("pidgin_vnc:x11vnc");
exit(ret);
}
close(std_out[1]);
port_num = x11vnc_port;
if (fd = fdopen(std_out[0], "r"))
{
while (!feof(fd))
{
if (fscanf(fd, "PORT=%d", &port_num))
break;
}
port_num -= 5900;
//close (fd);
printf("FINI\n");
}
else
{
port_num = x11vnc_port;
}
}
const char *ip;
PurpleStunNatDiscovery *stun_res = purple_stun_discover(NULL);
if (stun_res && stun_res->status == PURPLE_STUN_STATUS_DISCOVERED)
{
printf("STUN mode %d %d\n", stun_res->status, stun_res->type);
ip = purple_network_get_my_ip(-1);
}
else
{
ip = purple_upnp_get_public_ip();
if (ip == NULL)
{
printf("LOCAL mode\n");
ip = purple_network_get_my_ip(-1);
}
else
{
printf("UPNP mode\n");
}
}
url_http = g_strdup_printf("http://%s:%d/", ip, 5800 + port_num);
url_vnc = g_strdup_printf("vnc://invitation:%s#%s:%d", password, ip, port_num);
g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, url_vnc);
joinstr = g_strdup_printf("%s.\ntry %s\nor %s. Password=%s", purple_prefs_get_string(PREF_TEXT), url_vnc, url_vnc, url_http, url_http, password);
gtk_imhtml_append_text(GTK_IMHTML(gtkconv->entry), joinstr, FALSE);
g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "imhtml display vnc\n");
g_signal_emit_by_name(gtkconv->entry, "message_send");
g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "message sent\n");
g_free(url_vnc);
g_free(url_http);
g_free(joinstr);
gtk_widget_show_all(button);
}
This function to fill combobox with opened windows names
static void
refresh_combo_box(GtkWidget *widget, PidginConversation *gtkconv)
{
FILE *fp1;
FILE *fp2;
char path[1035];
char path2[1035];
char sum[1035];
/* Open the command for reading. */
fp1 = popen("xprop -root | grep '_NET_CLIENT_LIST_STACKING(WINDOW)'", "r");
if (fp1 == NULL)
{
printf("Failed to run command\n" );
exit(1);
}
/* Read the output a line at a time - output it. */
while (fgets(path, sizeof(path) - 1, fp1) != NULL)
{
// printf("%s", path);
strcat(sum, path);
}
char *splitter = strtok(sum, "#");
splitter = strtok(NULL, "#");
char *virgulSplitter = strtok(splitter, ", ");
ekranIds[0][0] = strdup(virgulSplitter);
int a = 1;
while (virgulSplitter != NULL)
{
virgulSplitter = strtok(NULL, ",");
if (virgulSplitter != NULL)
{
ekranIds[0][a] = strdup(virgulSplitter);
a++;
}
}
for (int x = 0; x < a; x++)
{
ekranIds[0][a - 1][strcspn(ekranIds[0][a - 1], "\n")] = 0;
char tmp[500] = {0};
//here is get window names by id
sprintf(tmp, "xprop -id %s | grep '^WM_NAME'", ekranIds[0][x]);
fp2 = popen(tmp, "r");
if (fp1 == NULL)
{
printf("Failed to run command\n" );
exit(1);
}
// Read the output a line at a time - output it.
while (fgets(path2, sizeof(path2) - 1, fp2) != NULL)
{
char *windowSplitter = strtok(path2, "=");
windowSplitter = strtok(NULL, "=");
ekranIds[1][x] = strdup(windowSplitter);
}
}
pclose(fp2);
pclose(fp1);
char *combobox_source[30];
for (int yf = 0; yf < 30; yf++)
{
if (ekranIds[1][yf] != NULL)
{
combobox_source[yf] = strdup(ekranIds[1][yf]);
}
}
gtk_list_store_clear(GTK_LIST_STORE(gtk_combo_box_get_model(combo_box)));
for (int i = 0; i < G_N_ELEMENTS(combobox_source); i++)
{
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_box), combobox_source[i]);
}
gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), 0);
gtk_widget_show_all(combo_box);
}
First function is working well: opening vnc connection and sends Port name to other users. (but this one for sharing all of screen.)
Second function has problem. When I click to button which is calling this function program crashes when you click the button.(this function for sharing one of my windows that are open on my computer.)
Third function to fill combobox with opened windows' names.
I am trying to implement multiple clients and multiple servers using Sun-RPC. However, I am unable to run multiple servers at the same time to begin with.
Here's the IDL
const MAXLEN = 1024;
typedef string filename<MAXLEN>;
typedef int vtimestamp[5];
typedef int sender_id;
typedef int recv_id;
struct request {
filename name;
int start;
vtimestamp ts;
sender_id sid;
recv_id rid;
};
typedef struct request request;
typedef opaque filepart[MAXLEN];
struct partreceive {
filepart data;
int bytes;
vtimestamp ts;
sender_id sid;
recv_id rid;
};
typedef struct partreceive partreceive;
struct partsend {
filename name;
filepart data;
int bytes;
vtimestamp ts;
sender_id sid;
recv_id rid;
};
typedef struct partsend partsend;
union readfile_res switch (int errno) {
case 0:
partreceive part;
default:
void;
};
program FTPROG {
version FTVER {
readfile_res retrieve_file(request *) = 1;
int send_file(partsend *) = 2;
} = 1;
} = 0x31240000;
Here's the server 1's code:
#include <rpc/rpc.h>
#include <stdio.h>
#include "maekawa.h"
extern __thread int errno;
int Id = 1;
char fileLog[50] = "server_1_file_log.txt";
int cur_ts[5] = {0};
readfile_res* retrieve_file_1_svc(request *req, struct svc_req *rqstp)
{
printf("%d",req->rid);
if(req->rid == Id)
{
FILE *file;
char data[1024];
int bytes,i;
static readfile_res res;
//update the timestamp
for(i=0;i<5;i++)
cur_ts[i] = res.readfile_res_u.part.ts[i];
char fn[3*MAXLEN] = "storage/";
strcat(fn,req->name);
file = fopen(fn, "rb");
if (file == NULL)
{
res.errno = errno;
return (&res);
}
fseek (file, req->start, SEEK_SET);
bytes = fread(res.readfile_res_u.part.data, 1, 1024, file);
res.readfile_res_u.part.bytes = bytes;
res.readfile_res_u.part.sid = Id;
res.readfile_res_u.part.rid = req->sid;
res.errno = 0;
fclose(file);
//log the transaction
FILE *log = NULL;
log = fopen(fileLog, "a");
fprintf(log,"R,");
for(i=0;i<5;i++)
fprintf(log,"%d,",cur_ts[i]);
fprintf(log,"%d,",req->sid);
fprintf(log,"%s,",req->name);
fprintf(log,"%d\n",req->start);
fclose(log);
return (&res);
}
}
int* send_file_1_svc(partsend *rec, struct svc_req *rqstp)
{
int i;
printf("%d",rec->rid);
if(rec->rid == Id)
{
FILE *file;
int write_bytes;
static int result;
cur_ts[Id]++;
//update the timestamp
for(i=0;i<5;i++)
cur_ts[i] = rec->ts[i];
char fn[3*MAXLEN] = "storage/";
strcat(fn,rec->name);
file = fopen(fn, "a");
if (file == NULL) {
result = errno;
return &result;
}
write_bytes = fwrite(rec->data, 1, rec->bytes, file);
fclose(file);
result = 0;
//log the transaction
FILE *log = NULL;
log = fopen(fileLog, "a");
fprintf(log,"S,");
for(i=0;i<5;i++)
fprintf(log,"%d,",cur_ts[i]);
fprintf(log,"%d,",rec->sid);
fprintf(log,"%s\n",rec->name);
fclose(log);
return &result;
}
}
Here's Server 2 :
#include <rpc/rpc.h>
#include <stdio.h>
#include "maekawa.h"
extern __thread int errno;
int Id = 2;
char fileLog[50] = "server_2_file_log.txt";
int cur_ts[5] = {0};
readfile_res* retrieve_file_1_svc(request *req, struct svc_req *rqstp)
{
printf("%d",req->rid);
if(req->rid == Id)
{
FILE *file;
char data[1024];
int bytes,i;
static readfile_res res;
//update the timestamp
for(i=0;i<5;i++)
cur_ts[i] = res.readfile_res_u.part.ts[i];
char fn[3*MAXLEN] = "storage/";
strcat(fn,req->name);
file = fopen(fn, "rb");
if (file == NULL)
{
res.errno = errno;
return (&res);
}
fseek (file, req->start, SEEK_SET);
bytes = fread(res.readfile_res_u.part.data, 1, 1024, file);
res.readfile_res_u.part.bytes = bytes;
res.readfile_res_u.part.sid = Id;
res.readfile_res_u.part.rid = req->sid;
res.errno = 0;
fclose(file);
//log the transaction
FILE *log = NULL;
log = fopen(fileLog, "a");
fprintf(log,"R,");
for(i=0;i<5;i++)
fprintf(log,"%d,",cur_ts[i]);
fprintf(log,"%d,",req->sid);
fprintf(log,"%s,",req->name);
fprintf(log,"%d\n",req->start);
fclose(log);
return (&res);
}
}
int* send_file_1_svc(partsend *rec, struct svc_req *rqstp)
{
int i;
printf("%d",rec->rid);
if(rec->rid == Id)
{
FILE *file;
int write_bytes;
static int result;
cur_ts[Id]++;
//update the timestamp
for(i=0;i<5;i++)
cur_ts[i] = rec->ts[i];
char fn[3*MAXLEN] = "storage/";
strcat(fn,rec->name);
file = fopen(fn, "a");
if (file == NULL) {
result = errno;
return &result;
}
write_bytes = fwrite(rec->data, 1, rec->bytes, file);
fclose(file);
result = 0;
//log the transaction
FILE *log = NULL;
log = fopen(fileLog, "a");
fprintf(log,"S,");
for(i=0;i<5;i++)
fprintf(log,"%d,",cur_ts[i]);
fprintf(log,"%d,",rec->sid);
fprintf(log,"%s\n",rec->name);
fclose(log);
return &result;
}
}
Here's my client 1 code.
#include <rpc/rpc.h>
#include <stdio.h>
#include <string.h>
#include "maekawa.h"
extern __thread int errno;
int Id = 4;
char fileLog[50] = "client_1_file_log.txt";
int cur_ts[5] = {0};
//Explicit Replication due to lack of Active Directory Service in NFS.
int idMap[4] = {0,2,3,1};
char hostMap[4][MAXLEN] = {"","localhost","localhost","localhost"};
int get_file(char *host, char *name, int serverno) //just to ensure all servers are not operating on same domain, we use serverno.
{
CLIENT *clnt;
int total_bytes = 0, write_bytes;
readfile_res *result;
request req;
FILE *file;
req.name = name;
req.start = 0;
int i;
req.sid = Id;
req.rid = serverno;
clnt = clnt_create(host, FTPROG, FTVER, "tcp");
if (clnt == NULL)
{
clnt_pcreateerror(host);
exit(1);
}
file = fopen(name, "wb");
FILE *log = NULL;
log = fopen(fileLog, "a");
while (1)
{
cur_ts[Id]++;
for(i=0;i<5;i++)
req.ts[i] = cur_ts[i];
req.start = total_bytes;
result = retrieve_file_1(&req, clnt);
if (result == NULL)
{
clnt_perror(clnt, host);
exit(1);
}
if (result->errno != 0)
{
errno = result->errno;
perror(name);
exit(1);
}
write_bytes = fwrite(result->readfile_res_u.part.data, 1, result->readfile_res_u.part.bytes, file);
total_bytes += result->readfile_res_u.part.bytes;
//log the transaction
fprintf(log,"G,");
for(i=0;i<5;i++)
fprintf(log,"%d,",cur_ts[i]);
fprintf(log,"%d,",req.sid);
fprintf(log,"%s,",req.name);
fprintf(log,"%d\n",req.start);
if (result->readfile_res_u.part.bytes < MAXLEN)
break;
}
fclose(file);
fclose(log);
return 0;
}
int put_file(char *host, char *name, int serverno)//just to ensure all servers are not operating on same domain, we use serverno.
{
CLIENT *clnt;
char data[1024];
int total_bytes = 0, read_bytes;
int *result;
partsend part;
FILE *file;
int i;
part.sid = Id;
part.rid = serverno;
clnt = clnt_create(host, FTPROG, FTVER, "tcp");
if (clnt == NULL)
{
clnt_pcreateerror(host);
exit(1);
}
file = fopen(name, "r");
part.name = name;
FILE *log = NULL;
log = fopen(fileLog, "a");
for(i=0;i<5;i++)
part.ts[i] = cur_ts[i];
while (1)
{
part.bytes = total_bytes;
read_bytes = fread(part.data, 1, MAXLEN, file);
total_bytes += read_bytes;
part.bytes = read_bytes;
result = send_file_1(&part, clnt);
if (result == NULL)
{
clnt_perror(clnt, host);
exit(1);
}
if (*result != 0)
{
errno = *result;
perror(name);
exit(1);
}
for(i=0;i<5;i++)
cur_ts[i] = part.ts[i];
//log the transaction
fprintf(log,"P,");
for(i=0;i<5;i++)
fprintf(log,"%d,",cur_ts[i]);
fprintf(log,"%d,",part.sid);
fprintf(log,"%s,",part.name);
fprintf(log,"%d\n",part.bytes);
if (read_bytes < MAXLEN)
break;
}
fclose(file);
fclose(log);
return 0;
}
int read_command(char *host)
{
char command[MAXLEN], filepath[MAXLEN];
int serverno;
printf("> ");
fflush(stdin);
scanf("%s",command);
if(strcmp(command, "exit") == 0)
{
exit(0);
}
scanf(" %s %d",filepath,&serverno);
if(serverno<=0 || serverno>=4)
{
printf("Choose a server number in [1,2,3].");
}
else
{
if (strcmp(command, "get") == 0)
{
return get_file(host,filepath,serverno);
}
else if(strcmp(command, "put") == 0)
{
int updateResult,replicationResult=-1;
updateResult = put_file(host,filepath,serverno);
/*if(updateResult == 0)
{
//explicit Replication
replicationResult = put_file(hostMap[serverno],filepath,idMap[serverno]);
}
else if(replicationResult != 0)
{
printf("Replication failed.");
}*/
return 0;
}
else
{
return -1;
}
}
}
int main(int argc, char *argv[])
{
int result;
if (argc != 2)
{
fprintf(stderr, "usage: %s host\n", argv[0]);
exit(1);
}
while(TRUE)
{
result = read_command(argv[1]);
}
return 0;
}
I am trying to use Maekawa algorithm to implement file replication explicitly through my client. However, it's being ridiculously impossible to run multiple servers on RPC on same localhost. Is it even possible? If I run the code on different computers, would that work?
Currently I am receiving segmentation fault from the server that is run after the first server. The client just blurts out Connection reset by peer. Is there anyway I can make this work?
I am trying to get a simple django app up on Http Server. The server is IBM Websphere Application Server. I have successfully compiled mod_scgi.c to the iseries.
I proceeded to create a server and edit the configuration file with the following code:
#Load the mod_scgi module
LoadModule scgi_module /qsys.lib/qgpl.lib/mod_scgi.srvpgm
# Set up location to be server by an SCGI server process
SCGIMount /dynamic 127.0.0.1:8080
This produces an error on the configuration file: "Directive name "SCGIMount" is not recognized."
I am not sure how to proceed from here. Also, the mod_scgi.c file has been modified to allow it to be compiled to the iseries. I have provided the code below:
/* mod_scgi.c
*
* Apache 2 implementation of the SCGI protocol.
*
*/
#define MOD_SCGI_VERSION "1.14"
#define SCGI_PROTOCOL_VERSION "1"
#include "ap_config.h"
#include "apr_version.h"
#include "apr_lib.h"
#include "apr_strings.h"
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_request.h"
#include "http_log.h"
#include "http_protocol.h"
#include "util_script.h"
#ifdef AS400
#include <strings.h>
#endif
#define DEFAULT_TIMEOUT 60 /* default socket timeout */
#define UNSET 0
#define ENABLED 1
#define DISABLED 2
#if APR_MAJOR_VERSION == 0
#define apr_socket_send apr_send
#define GET_PORT(port, addr) apr_sockaddr_port_get(&(port), addr)
#define CREATE_SOCKET(sock, family, pool) \
apr_socket_create(sock, family, SOCK_STREAM, pool)
#else
#define GET_PORT(port, addr) ((port) = (addr)->port)
#define CREATE_SOCKET(sock, family, pool) \
apr_socket_create(sock, family, SOCK_STREAM, APR_PROTO_TCP, pool)
#endif
typedef struct {
char *path;
char *addr;
apr_port_t port;
} mount_entry;
/*
* Configuration record. Used per-directory configuration data.
*/
typedef struct {
mount_entry mount;
int enabled; /* mod_scgi is enabled from this directory */
int timeout;
} scgi_cfg;
/* Server level configuration */
typedef struct {
apr_array_header_t *mounts;
int timeout;
} scgi_server_cfg;
/*
* Declare ourselves so the configuration routines can find and know us.
* We'll fill it in at the end of the module.
*/
module AP_MODULE_DECLARE_DATA scgi_module;
/*
* Locate our directory configuration record for the current request.
*/
static scgi_cfg *
our_dconfig(request_rec *r)
{
return (scgi_cfg *) ap_get_module_config(r->per_dir_config, &scgi_module);
}
static scgi_server_cfg *our_sconfig(server_rec *s)
{
return (scgi_server_cfg *) ap_get_module_config(s->module_config,
&scgi_module);
}
static int
mount_entry_matches(const char *url, const char *prefix,
const char **path_info)
{
int i;
for (i=0; prefix[i] != '\0'; i++) {
if (url[i] == '\0' || url[i] != prefix[i])
return 0;
}
if (url[i] == '\0' || url[i] == '/') {
*path_info = url + i;
return 1;
}
return 0;
}
static int scgi_translate(request_rec *r)
{
scgi_cfg *cfg = our_dconfig(r);
if (cfg->enabled == DISABLED) {
return DECLINED;
}
if (cfg->mount.addr != UNSET) {
ap_assert(cfg->mount.port != UNSET);
r->handler = "scgi-handler";
r->filename = r->uri;
return OK;
}
else {
int i;
scgi_server_cfg *scfg = our_sconfig(r->server);
mount_entry *entries = (mount_entry *) scfg->mounts->elts;
for (i = 0; i < scfg->mounts->nelts; ++i) {
const char *path_info;
mount_entry *mount = &entries[i];
if (mount_entry_matches(r->uri, mount->path, &path_info)) {
r->handler = "scgi-handler";
r->path_info = apr_pstrdup(r->pool, path_info);
r->filename = r->uri;
ap_set_module_config(r->request_config, &scgi_module, mount);
return OK;
}
}
}
return DECLINED;
}
static int scgi_map_location(request_rec *r)
{
if (r->handler && strcmp(r->handler, "scgi-handler") == 0) {
return OK; /* We don't want directory walk. */
}
return DECLINED;
}
static void log_err(const char *file, int line, request_rec *r,
apr_status_t status, const char *msg)
{
ap_log_rerror(file, line, APLOG_ERR, status, r, "scgi: %s", msg);
}
static void log_debug(const char *file, int line, request_rec *r, const
char *msg)
{
ap_log_rerror(file, line, APLOG_DEBUG, APR_SUCCESS, r, msg);
}
static char *http2env(apr_pool_t *p, const char *name)
{
char *env_name = apr_pstrcat(p, "HTTP_", name, NULL);
char *cp;
for (cp = env_name + 5; *cp != 0; cp++) {
if (*cp == '-') {
*cp = '_';
}
else {
*cp = apr_toupper(*cp);
}
}
return env_name;
}
static char *lookup_name(apr_table_t *t, const char *name)
{
const apr_array_header_t *hdrs_arr = apr_table_elts(t);
apr_table_entry_t *hdrs = (apr_table_entry_t *) hdrs_arr->elts;
int i;
for (i = 0; i < hdrs_arr->nelts; ++i) {
if (hdrs[i].key == NULL)
continue;
if (strcasecmp(hdrs[i].key, name) == 0)
return hdrs[i].val;
}
return NULL;
}
static char *lookup_header(request_rec *r, const char *name)
{
return lookup_name(r->headers_in, name);
}
static void add_header(apr_table_t *t, const char *name, const char *value)
{
if (name != NULL && value != NULL)
apr_table_addn(t, name, value);
}
static int find_path_info(const char *uri, const char *path_info)
{
int n;
n = strlen(uri) - strlen(path_info);
ap_assert(n >= 0);
return n;
}
/* This code is a duplicate of what's in util_script.c. We can't use
* r->unparsed_uri because it gets changed if there was a redirect. */
static char *original_uri(request_rec *r)
{
char *first, *last;
if (r->the_request == NULL) {
return (char *) apr_pcalloc(r->pool, 1);
}
first = r->the_request; /* use the request-line */
while (*first && !apr_isspace(*first)) {
++first; /* skip over the method */
}
while (apr_isspace(*first)) {
++first; /* and the space(s) */
}
last = first;
while (*last && !apr_isspace(*last)) {
++last; /* end at next whitespace */
}
return apr_pstrmemdup(r->pool, first, last - first);
}
/* buffered socket implementation (buckets are overkill) */
#define BUFFER_SIZE 8000
struct sockbuff {
apr_socket_t *sock;
char buf[BUFFER_SIZE];
int used;
};
static void binit(struct sockbuff *s, apr_socket_t *sock)
{
s->sock = sock;
s->used = 0;
}
static apr_status_t sendall(apr_socket_t *sock, char *buf, apr_size_t len)
{
apr_status_t rv;
apr_size_t n;
while (len > 0) {
n = len;
if ((rv = apr_socket_send(sock, buf, &n))) return rv;
buf += n;
len -= n;
}
return APR_SUCCESS;
}
static apr_status_t bflush(struct sockbuff *s)
{
apr_status_t rv;
ap_assert(s->used >= 0 && s->used <= BUFFER_SIZE);
if (s->used) {
if ((rv = sendall(s->sock, s->buf, s->used))) return rv;
s->used = 0;
}
return APR_SUCCESS;
}
static apr_status_t bwrite(struct sockbuff *s, char *buf, apr_size_t len)
{
apr_status_t rv;
if (len >= BUFFER_SIZE - s->used) {
if ((rv = bflush(s))) return rv;
while (len >= BUFFER_SIZE) {
if ((rv = sendall(s->sock, buf, BUFFER_SIZE))) return rv;
buf += BUFFER_SIZE;
len -= BUFFER_SIZE;
}
}
if (len > 0) {
ap_assert(len < BUFFER_SIZE - s->used);
memcpy(s->buf + s->used, buf, len);
s->used += len;
}
return APR_SUCCESS;
}
static apr_status_t bputs(struct sockbuff *s, char *buf)
{
return bwrite(s, buf, strlen(buf));
}
static apr_status_t bputc(struct sockbuff *s, char c)
{
char buf[1];
buf[0] = c;
return bwrite(s, buf, 1);
}
static apr_status_t
send_headers(request_rec *r, struct sockbuff *s)
{
/* headers to send */
apr_table_t *t;
const apr_array_header_t *hdrs_arr, *env_arr;
apr_table_entry_t *hdrs, *env;
unsigned long int n = 0;
char *buf;
int i;
apr_status_t rv = 0;
apr_port_t port = 0;
GET_PORT(port, r->connection->remote_addr);
log_debug(APLOG_MARK,r, "sending headers");
t = apr_table_make(r->pool, 40);
if (!t)
return APR_ENOMEM;
/* CONTENT_LENGTH must come first and always be present */
buf = lookup_header(r, "Content-Length");
if (buf == NULL)
buf = "0";
add_header(t, "CONTENT_LENGTH", buf);
add_header(t, "SCGI", SCGI_PROTOCOL_VERSION);
add_header(t, "SERVER_SOFTWARE", ap_get_server_version());
add_header(t, "SERVER_PROTOCOL", r->protocol);
add_header(t, "SERVER_NAME", ap_get_server_name(r));
add_header(t, "SERVER_ADMIN", r->server->server_admin);
add_header(t, "SERVER_ADDR", r->connection->local_ip);
add_header(t, "SERVER_PORT", apr_psprintf(r->pool, "%u",
ap_get_server_port(r)));
add_header(t, "REMOTE_ADDR", r->connection->remote_ip);
add_header(t, "REMOTE_PORT", apr_psprintf(r->pool, "%d", port));
add_header(t, "REMOTE_USER", r->user);
add_header(t, "REQUEST_METHOD", r->method);
add_header(t, "REQUEST_URI", original_uri(r));
add_header(t, "QUERY_STRING", r->args ? r->args : "");
if (r->path_info) {
int path_info_start = find_path_info(r->uri, r->path_info);
add_header(t, "SCRIPT_NAME", apr_pstrndup(r->pool, r->uri,
path_info_start));
add_header(t, "PATH_INFO", r->path_info);
}
else {
/* skip PATH_INFO, don't know it */
add_header(t, "SCRIPT_NAME", r->uri);
}
add_header(t, "CONTENT_TYPE", lookup_header(r, "Content-type"));
add_header(t, "DOCUMENT_ROOT", ap_document_root(r));
/* HTTP headers */
hdrs_arr = apr_table_elts(r->headers_in);
hdrs = (apr_table_entry_t *) hdrs_arr->elts;
for (i = 0; i < hdrs_arr->nelts; ++i) {
if (hdrs[i].key) {
add_header(t, http2env(r->pool, hdrs[i].key), hdrs[i].val);
}
}
/* environment variables */
env_arr = apr_table_elts(r->subprocess_env);
env = (apr_table_entry_t*) env_arr->elts;
for (i = 0; i < env_arr->nelts; ++i) {
add_header(t, env[i].key, env[i].val);
}
hdrs_arr = apr_table_elts(t);
hdrs = (apr_table_entry_t*) hdrs_arr->elts;
/* calculate length of header data (including nulls) */
for (i = 0; i < hdrs_arr->nelts; ++i) {
n += strlen(hdrs[i].key) + 1;
n += strlen(hdrs[i].val) + 1;
}
buf = apr_psprintf(r->pool, "%lu:", n);
if (!buf)
return APR_ENOMEM;
rv = bputs(s, buf);
if (rv)
return rv;
for (i = 0; i < hdrs_arr->nelts; ++i) {
rv = bputs(s, hdrs[i].key);
if (rv) return rv;
rv = bputc(s, '\0');
if (rv) return rv;
rv = bputs(s, hdrs[i].val);
if (rv) return rv;
rv = bputc(s, '\0');
if (rv) return rv;
}
rv = bputc(s, ',');
if (rv)
return rv;
return APR_SUCCESS;
}
static apr_status_t send_request_body(request_rec *r, struct sockbuff *s)
{
if (ap_should_client_block(r)) {
char buf[BUFFER_SIZE];
apr_status_t rv;
apr_off_t len;
while ((len = ap_get_client_block(r, buf, sizeof buf)) > 0) {
if ((rv = bwrite(s, buf, len))) return rv;
}
if (len == -1)
return HTTP_INTERNAL_SERVER_ERROR; /* what to return? */
}
return APR_SUCCESS;
}
#define CONFIG_VALUE(value, fallback) ((value) != UNSET ? (value) : (fallback))
static apr_status_t
open_socket(apr_socket_t **sock, request_rec *r)
{
int timeout;
int retries = 4;
int sleeptime = 1;
apr_status_t rv;
apr_sockaddr_t *sockaddr;
scgi_server_cfg *scfg = our_sconfig(r->server);
scgi_cfg *cfg = our_dconfig(r);
mount_entry *m = (mount_entry *) ap_get_module_config(r->request_config,
&scgi_module);
if (!m) {
m = &cfg->mount;
}
timeout = CONFIG_VALUE(cfg->timeout, CONFIG_VALUE(scfg->timeout,
DEFAULT_TIMEOUT));
rv = apr_sockaddr_info_get(&sockaddr,
CONFIG_VALUE(m->addr, "localhost"),
APR_UNSPEC,
CONFIG_VALUE(m->port, 4000),
0,
r->pool);
if (rv) {
log_err(APLOG_MARK, r, rv, "apr_sockaddr_info_get() error");
return rv;
}
restart:
*sock = NULL;
rv = CREATE_SOCKET(sock, sockaddr->family, r->pool);
if (rv) {
log_err(APLOG_MARK, r, rv, "apr_socket_create() error");
return rv;
}
rv = apr_socket_timeout_set(*sock, apr_time_from_sec(timeout));
if (rv) {
log_err(APLOG_MARK, r, rv, "apr_socket_timeout_set() error");
return rv;
}
rv = apr_socket_connect(*sock, sockaddr);
if (rv) {
apr_socket_close(*sock);
if ((APR_STATUS_IS_ECONNREFUSED(rv) |
APR_STATUS_IS_EINPROGRESS(rv)) && retries > 0) {
/* server may be temporarily down, retry */
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, rv, r,
"scgi: connection failed, retrying");
apr_sleep(apr_time_from_sec(sleeptime));
--retries;
sleeptime *= 2;
goto restart;
}
log_err(APLOG_MARK, r, rv, "scgi: can't connect to server");
return rv;
}
#ifdef APR_TCP_NODELAY
/* disable Nagle, we don't send small packets */
apr_socket_opt_set(*sock, APR_TCP_NODELAY, 1);
#endif
return APR_SUCCESS;
}
#ifdef AS400
static int getsfunc_BRIGADE(char *buf, int len, void *arg)
{
apr_bucket_brigade *bb = (apr_bucket_brigade *)arg;
const char *dst_end = buf + len - 1; /* leave room for terminating null */
char *dst = buf;
apr_bucket *e = APR_BRIGADE_FIRST(bb);
apr_status_t rv;
int done = 0;
while ((dst < dst_end) && !done && e != APR_BRIGADE_SENTINEL(bb)
&& !APR_BUCKET_IS_EOS(e)) {
const char *bucket_data;
apr_size_t bucket_data_len;
const char *src;
const char *src_end;
apr_bucket * next;
rv = apr_bucket_read(e, &bucket_data, &bucket_data_len,
APR_BLOCK_READ);
if (rv != APR_SUCCESS || (bucket_data_len == 0)) {
*dst = '\0';
return APR_STATUS_IS_TIMEUP(rv) ? -1 : 0;
}
src = bucket_data;
src_end = bucket_data + bucket_data_len;
while ((src < src_end) && (dst < dst_end) && !done) {
if (*src == '\n') {
done = 1;
}
else if (*src != '\r') {
*dst++ = *src;
}
src++;
}
if (src < src_end) {
apr_bucket_split(e, src - bucket_data);
}
next = APR_BUCKET_NEXT(e);
APR_BUCKET_REMOVE(e);
apr_bucket_destroy(e);
e = next;
}
*dst = 0;
return done;
}
#endif
static int scgi_handler(request_rec *r)
{
apr_status_t rv = 0;
int http_status = 0;
struct sockbuff s;
apr_socket_t *sock;
apr_bucket_brigade *bb = NULL;
apr_bucket *b = NULL;
const char *location;
if (strcmp(r->handler, "scgi-handler"))
return DECLINED;
http_status = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR);
if (http_status != OK)
return http_status;
log_debug(APLOG_MARK, r, "connecting to server");
rv = open_socket(&sock, r);
if (rv) {
return HTTP_INTERNAL_SERVER_ERROR;
}
binit(&s, sock);
rv = send_headers(r, &s);
if (rv) {
log_err(APLOG_MARK, r, rv, "error sending request headers");
return HTTP_INTERNAL_SERVER_ERROR;
}
rv = send_request_body(r, &s);
if (rv) {
log_err(APLOG_MARK, r, rv, "error sending request body");
return HTTP_INTERNAL_SERVER_ERROR;
}
rv = bflush(&s);
if (rv) {
log_err(APLOG_MARK, r, rv, "error sending request");
return HTTP_INTERNAL_SERVER_ERROR;
}
log_debug(APLOG_MARK, r, "reading response headers");
bb = apr_brigade_create(r->connection->pool, r->connection->bucket_alloc);
b = apr_bucket_socket_create(sock, r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, b);
b = apr_bucket_eos_create(r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, b);
#ifdef AS400
rv = ap_scan_script_header_err_core(r, NULL, getsfunc_BRIGADE, bb);
#else
rv = ap_scan_script_header_err_brigade(r, bb, NULL);
#endif
if (rv) {
if (rv == HTTP_INTERNAL_SERVER_ERROR) {
log_err(APLOG_MARK, r, rv, "error reading response headers");
}
else {
/* Work around an Apache bug whereby the returned status is
* ignored and status_line is used instead. This bug is
* present at least in 2.0.54.
*/
r->status_line = NULL;
}
apr_brigade_destroy(bb);
return rv;
}
location = apr_table_get(r->headers_out, "Location");
if (location && location[0] == '/' &&
((r->status == HTTP_OK) || ap_is_HTTP_REDIRECT(r->status))) {
apr_brigade_destroy(bb);
/* Internal redirect -- fake-up a pseudo-request */
r->status = HTTP_OK;
/* This redirect needs to be a GET no matter what the original
* method was.
*/
r->method = apr_pstrdup(r->pool, "GET");
r->method_number = M_GET;
/* We already read the message body (if any), so don't allow
* the redirected request to think it has one. We can ignore
* Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR.
*/
apr_table_unset(r->headers_in, "Content-Length");
ap_internal_redirect_handler(location, r);
return OK;
}
rv = ap_pass_brigade(r->output_filters, bb);
if (rv) {
log_err(APLOG_MARK, r, rv, "ap_pass_brigade()");
return HTTP_INTERNAL_SERVER_ERROR;
}
return OK;
}
static int scgi_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
server_rec *base_server)
{
ap_add_version_component(p, "mod_scgi/" MOD_SCGI_VERSION);
return OK;
}
static void *
create_dir_config(apr_pool_t *p, char *dirspec)
{
scgi_cfg *cfg = apr_pcalloc(p, sizeof(scgi_cfg));
cfg->enabled = UNSET;
cfg->mount.addr = UNSET;
cfg->mount.port = UNSET;
cfg->timeout = UNSET;
return cfg;
}
#define MERGE(b, n, a) (n->a == UNSET ? b->a : n->a)
static void *
merge_dir_config(apr_pool_t *p, void *basev, void *newv)
{
scgi_cfg* cfg = apr_pcalloc(p, sizeof(scgi_cfg));
scgi_cfg* base = basev;
scgi_cfg* new = newv;
cfg->enabled = MERGE(base, new, enabled);
cfg->mount.addr = MERGE(base, new, mount.addr);
cfg->mount.port = MERGE(base, new, mount.port);
cfg->timeout = MERGE(base, new, timeout);
return cfg;
}
static void *
create_server_config(apr_pool_t *p, server_rec *s)
{
scgi_server_cfg *c =
(scgi_server_cfg *) apr_pcalloc(p, sizeof(scgi_server_cfg));
c->mounts = apr_array_make(p, 20, sizeof(mount_entry));
c->timeout = UNSET;
return c;
}
static void *
merge_server_config(apr_pool_t *p, void *basev, void *overridesv)
{
scgi_server_cfg *c = (scgi_server_cfg *)
apr_pcalloc(p, sizeof(scgi_server_cfg));
scgi_server_cfg *base = (scgi_server_cfg *) basev;
scgi_server_cfg *overrides = (scgi_server_cfg *) overridesv;
c->mounts = apr_array_append(p, overrides->mounts, base->mounts);
c->timeout = MERGE(base, overrides, timeout);
return c;
}
static const char *
cmd_mount(cmd_parms *cmd, void *dummy, const char *path, const char *addr)
{
int n;
apr_status_t rv;
char *scope_id = NULL; /* A ip6 parameter - not used here. */
scgi_server_cfg *scfg = our_sconfig(cmd->server);
mount_entry *new = apr_array_push(scfg->mounts);
n = strlen(path);
while (n > 0 && path[n-1] == '/') {
n--; /* strip trailing slashes */
}
new->path = apr_pstrndup(cmd->pool, path, n);
rv = apr_parse_addr_port(&new->addr, &scope_id, &new->port, addr,
cmd->pool);
if (rv)
return "error parsing address:port string";
return NULL;
}
static const char *
cmd_server(cmd_parms *cmd, void *pcfg, const char *addr_and_port)
{
apr_status_t rv;
scgi_cfg *cfg = pcfg;
char *scope_id = NULL; /* A ip6 parameter - not used here. */
if (cmd->path == NULL)
return "not a server command";
rv = apr_parse_addr_port(&cfg->mount.addr, &scope_id, &cfg->mount.port,
addr_and_port, cmd->pool);
if (rv)
return "error parsing address:port string";
return NULL;
}
static const char *
cmd_handler(cmd_parms* cmd, void* pcfg, int flag)
{
scgi_cfg *cfg = pcfg;
if (cmd->path == NULL) /* server command */
return "not a server command";
if (flag)
cfg->enabled = ENABLED;
else
cfg->enabled = DISABLED;
return NULL;
}
static const char *
cmd_timeout(cmd_parms *cmd, void* pcfg, const char *strtimeout)
{
scgi_cfg *dcfg = pcfg;
int timeout = atoi(strtimeout);
if (cmd->path == NULL) {
scgi_server_cfg *scfg = our_sconfig(cmd->server);
scfg->timeout = timeout;
}
else {
dcfg->timeout = timeout;
}
return NULL;
}
static const command_rec scgi_cmds[] =
{
AP_INIT_TAKE2("SCGIMount", cmd_mount, NULL, RSRC_CONF,
"path prefix and address of SCGI server"),
AP_INIT_TAKE1("SCGIServer", cmd_server, NULL, ACCESS_CONF,
"Address and port of an SCGI server (e.g. localhost:4000)"),
AP_INIT_FLAG( "SCGIHandler", cmd_handler, NULL, ACCESS_CONF,
"On or Off to enable or disable the SCGI handler"),
AP_INIT_TAKE1("SCGIServerTimeout", cmd_timeout, NULL, ACCESS_CONF|RSRC_CONF,
"Timeout (in seconds) for communication with the SCGI server."),
{NULL}
};
static void scgi_register_hooks(apr_pool_t *p)
{
ap_hook_post_config(scgi_init, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_handler(scgi_handler, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_translate_name(scgi_translate, NULL, NULL, APR_HOOK_LAST);
ap_hook_map_to_storage(scgi_map_location, NULL, NULL, APR_HOOK_FIRST);
}
/* Dispatch list for API hooks */
module AP_MODULE_DECLARE_DATA scgi_module = {
STANDARD20_MODULE_STUFF,
create_dir_config, /* create per-dir config structs */
merge_dir_config, /* merge per-dir config structs */
create_server_config, /* create per-server config structs */
merge_server_config, /* merge per-server config structs */
scgi_cmds, /* table of config file commands */
scgi_register_hooks, /* register hooks */
};
UPDATE to the UPDATE:
I have narrowed down the problem to the following Error Message MCH3601:
MCH3601 Escape 40 06/05/15 15:41:10.884937 MOD_SCGI QGPL *STMT MOD_SCGI QGPL *STMT
From module . . . . . . . . : MOD_SCGI
From procedure . . . . . . : our_dconfig
Statement . . . . . . . . . : 1
To module . . . . . . . . . : MOD_SCGI
To procedure . . . . . . . : our_dconfig
Statement . . . . . . . . . : 1
Thread . . . . : 00000039
Message . . . . : Pointer not set for location referenced.
Cause . . . . . : A pointer was used, either directly or as a basing
pointer, that has not been set to an address.
It looks like the web server is actually Apache, not WAS. What does the Apache log say?
Is the Apache user profile authorised to the mod_scgi service program, and to the library QGPL?
Updated
So I am trying to decode a mp4 file, crop the video into a square, and then re encode it back out to another mp4 file. This is my current code but there are a few issues with it.
One is that the video doesn't keep its rotation after the video has been re encoded
Second is that the frames get outputted in a very fast video file that is not the same length as the original
Third is that there is no sound
Lastly and most importantly is do I need AVFilter to do the frame cropping or can it just be done per frame as a resize of the frame and then encoded back out.
const char *inputPath = "test.mp4";
const char *outPath = "cropped.mp4";
const char *outFileType = "mp4";
static AVFrame *oframe = NULL;
static AVFilterGraph *filterGraph = NULL;
static AVFilterContext *crop_ctx = NULL;
static AVFilterContext *buffersink_ctx = NULL;
static AVFilterContext *buffer_ctx = NULL;
int err;
int crop_video(int width, int height) {
av_register_all();
avcodec_register_all();
avfilter_register_all();
AVFormatContext *inCtx = NULL;
// open input file
err = avformat_open_input(&inCtx, inputPath, NULL, NULL);
if (err < 0) {
printf("error at open input in\n");
return err;
}
// get input file stream info
err = avformat_find_stream_info(inCtx, NULL);
if (err < 0) {
printf("error at find stream info\n");
return err;
}
// get info about video
av_dump_format(inCtx, 0, inputPath, 0);
// find video input stream
int vs = -1;
int s;
for (s = 0; s < inCtx->nb_streams; ++s) {
if (inCtx->streams[s] && inCtx->streams[s]->codec && inCtx->streams[s]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
vs = s;
break;
}
}
// check if video stream is valid
if (vs == -1) {
printf("error at open video stream\n");
return -1;
}
// set output format
AVOutputFormat * outFmt = av_guess_format(outFileType, NULL, NULL);
if (!outFmt) {
printf("error at output format\n");
return -1;
}
// get an output context to write to
AVFormatContext *outCtx = NULL;
err = avformat_alloc_output_context2(&outCtx, outFmt, NULL, NULL);
if (err < 0 || !outCtx) {
printf("error at output context\n");
return err;
}
// input and output stream
AVStream *outStrm = avformat_new_stream(outCtx, NULL);
AVStream *inStrm = inCtx->streams[vs];
// add a new codec for the output stream
AVCodec *codec = NULL;
avcodec_get_context_defaults3(outStrm->codec, codec);
outStrm->codec->thread_count = 1;
outStrm->codec->coder_type = AVMEDIA_TYPE_VIDEO;
if(outCtx->oformat->flags & AVFMT_GLOBALHEADER) {
outStrm->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
outStrm->codec->sample_aspect_ratio = outStrm->sample_aspect_ratio = inStrm->sample_aspect_ratio;
err = avio_open(&outCtx->pb, outPath, AVIO_FLAG_WRITE);
if (err < 0) {
printf("error at opening outpath\n");
return err;
}
outStrm->disposition = inStrm->disposition;
outStrm->codec->bits_per_raw_sample = inStrm->codec->bits_per_raw_sample;
outStrm->codec->chroma_sample_location = inStrm->codec->chroma_sample_location;
outStrm->codec->codec_id = inStrm->codec->codec_id;
outStrm->codec->codec_type = inStrm->codec->codec_type;
if (!outStrm->codec->codec_tag) {
if (! outCtx->oformat->codec_tag
|| av_codec_get_id (outCtx->oformat->codec_tag, inStrm->codec->codec_tag) == outStrm->codec->codec_id
|| av_codec_get_tag(outCtx->oformat->codec_tag, inStrm->codec->codec_id) <= 0) {
outStrm->codec->codec_tag = inStrm->codec->codec_tag;
}
}
outStrm->codec->bit_rate = inStrm->codec->bit_rate;
outStrm->codec->rc_max_rate = inStrm->codec->rc_max_rate;
outStrm->codec->rc_buffer_size = inStrm->codec->rc_buffer_size;
const size_t extra_size_alloc = (inStrm->codec->extradata_size > 0) ?
(inStrm->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE) :
0;
if (extra_size_alloc) {
outStrm->codec->extradata = (uint8_t*)av_mallocz(extra_size_alloc);
memcpy( outStrm->codec->extradata, inStrm->codec->extradata, inStrm->codec->extradata_size);
}
outStrm->codec->extradata_size = inStrm->codec->extradata_size;
AVRational input_time_base = inStrm->time_base;
AVRational frameRate = {25, 1};
if (inStrm->r_frame_rate.num && inStrm->r_frame_rate.den
&& (1.0 * inStrm->r_frame_rate.num / inStrm->r_frame_rate.den < 1000.0)) {
frameRate.num = inStrm->r_frame_rate.num;
frameRate.den = inStrm->r_frame_rate.den;
}
outStrm->r_frame_rate = frameRate;
outStrm->codec->time_base = inStrm->codec->time_base;
outStrm->codec->pix_fmt = inStrm->codec->pix_fmt;
outStrm->codec->width = width;
outStrm->codec->height = height;
outStrm->codec->has_b_frames = inStrm->codec->has_b_frames;
if (!outStrm->codec->sample_aspect_ratio.num) {
AVRational r0 = {0, 1};
outStrm->codec->sample_aspect_ratio =
outStrm->sample_aspect_ratio =
inStrm->sample_aspect_ratio.num ? inStrm->sample_aspect_ratio :
inStrm->codec->sample_aspect_ratio.num ?
inStrm->codec->sample_aspect_ratio : r0;
}
avformat_write_header(outCtx, NULL);
filterGraph = avfilter_graph_alloc();
if (!filterGraph) {
printf("could not open filter graph");
return -1;
}
AVFilter *crop = avfilter_get_by_name("crop");
AVFilter *buffer = avfilter_get_by_name("buffer");
AVFilter *buffersink = avfilter_get_by_name("buffersink");
char args[512];
snprintf(args, sizeof(args), "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
width, height, inStrm->codec->pix_fmt,
inStrm->codec->time_base.num, inStrm->codec->time_base.den,
inStrm->codec->sample_aspect_ratio.num, inStrm->codec->sample_aspect_ratio.den);
err = avfilter_graph_create_filter(&buffer_ctx, buffer, NULL, args, NULL, filterGraph);
if (err < 0) {
printf("error initializing buffer filter\n");
return err;
}
err = avfilter_graph_create_filter(&buffersink_ctx, buffersink, NULL, NULL, NULL, filterGraph);
if (err < 0) {
printf("unable to create buffersink filter\n");
return err;
}
snprintf(args, sizeof(args), "%d:%d", width, height);
err = avfilter_graph_create_filter(&crop_ctx, crop, NULL, args, NULL, filterGraph);
if (err < 0) {
printf("error initializing crop filter\n");
return err;
}
err = avfilter_link(buffer_ctx, 0, crop_ctx, 0);
if (err < 0) {
printf("error linking filters\n");
return err;
}
err = avfilter_link(crop_ctx, 0, buffersink_ctx, 0);
if (err < 0) {
printf("error linking filters\n");
return err;
}
err = avfilter_graph_config(filterGraph, NULL);
if (err < 0) {
printf("error configuring the filter graph\n");
return err;
}
printf("filtergraph configured\n");
for (;;) {
AVPacket packet = {0};
av_init_packet(&packet);
err = AVERROR(EAGAIN);
while (AVERROR(EAGAIN) == err)
err = av_read_frame(inCtx, &packet);
if (err < 0) {
if (AVERROR_EOF != err && AVERROR(EIO) != err) {
printf("eof error\n");
return 1;
} else {
break;
}
}
if (packet.stream_index == vs) {
//
// AVPacket pkt_temp_;
// memset(&pkt_temp_, 0, sizeof(pkt_temp_));
// AVPacket *pkt_temp = &pkt_temp_;
//
// *pkt_temp = packet;
//
// int error, got_frame;
// int new_packet = 1;
//
// error = avcodec_decode_video2(inStrm->codec, frame, &got_frame, pkt_temp);
// if(error < 0) {
// LOGE("error %d", error);
// }
//
// // if (error >= 0) {
//
// // push the video data from decoded frame into the filtergraph
// int err = av_buffersrc_write_frame(buffer_ctx, frame);
// if (err < 0) {
// LOGE("error writing frame to buffersrc");
// return -1;
// }
// // pull filtered video from the filtergraph
// for (;;) {
// int err = av_buffersink_get_frame(buffersink_ctx, oframe);
// if (err == AVERROR_EOF || err == AVERROR(EAGAIN))
// break;
// if (err < 0) {
// LOGE("error reading buffer from buffersink");
// return -1;
// }
// }
//
// LOGI("output frame");
err = av_interleaved_write_frame(outCtx, &packet);
if (err < 0) {
printf("error at write frame");
return -1;
}
//}
}
av_free_packet(&packet);
}
av_write_trailer(outCtx);
if (!(outCtx->oformat->flags & AVFMT_NOFILE) && outCtx->pb)
avio_close(outCtx->pb);
avformat_free_context(outCtx);
avformat_close_input(&inCtx);
return 0;
}
It looks like you are looking for vf_crop.
The CropContext contains a x, y, w, and h, which should be what you need to crop a video to a specific width and height.