Is there a way to specify the ssh port to be used by libgit2 - libgit2

This code block works perfectly well if I use port 22 to connect in ssh (rather usual 22 basic port of ssh)
But for some reason, I need to connect to ssh on port 443. And at this moment the code doesn't work anymore and tries to connect always on port 22.
So I ask if there is a method to tell the libgit2 to use port 443 for ssh connection.
int creds(git_cred **out, const char *url, const char *username_from_url,
unsigned int allowed_types, void *payload) {
std::cout << "Calling creds" << std::endl;
int result = git_credential_ssh_key_new(out, username_from_url,"path/to/ssh_key_public", "path/to/ssh_key_private", "");
if (result != 0) {
std::cout << giterr_last()->message << std::endl;
throw;
return result;
}
return result;
}
int main() {
git_libgit2_init();
git_repository *repo = nullptr;
git_remote *local_remote = nullptr;
std::string repo_path = "/Users/luclambour/Desktop/repo_test_libgit/git-test-clone";
int error = 0;
error = git_repository_open(&repo, repo_path.data());
std::cout<<error<<std::endl;
if (error != 0) { std::cout << giterr_last()->message << std::endl;}
error =git_remote_create_anonymous(&local_remote, repo, "root#138.1.1.1:/root/luc_clone_des/clone_simple");
if (error != 0) { std::cout << giterr_last()->message << std::endl;}
git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
callbacks.credentials=creds;
error = git_remote_connect(local_remote, GIT_DIRECTION_PUSH, &callbacks, NULL, NULL);
if (error != 0) { std::cout << giterr_last()->message << std::endl;}
git_push_options opts = GIT_PUSH_OPTIONS_INIT;
opts.callbacks.credentials = creds;
opts.proxy_opts.type = GIT_PROXY_NONE;
error = git_remote_push(local_remote,NULL,&opts);
if (error != 0) { std::cout << giterr_last()->message << std::endl;}
git_remote_free(local_remote);
git_repository_free(repo);
git_libgit2_shutdown();
return 0;
}

scp-like syntax doesn't support port number, so you should use ssh:// URL syntax as:
git_remote_create_anonymous(&local_remote, repo, "ssh://root#138.1.1.1:443/root/luc_clone_des/clone_simple");
Details can be found in the "GIT URLS" section of git-clone(1).
https://git-scm.com/docs/git-clone#_git_urls

Related

Input/output error after first read from pseudo terminal

I have created pseudo terminal master/slave and read on master side using select with the following code:
fd_set read_fd;
struct timeval timeout;
while (is_running) {
FD_ZERO(&read_fd);
FD_SET(fd, &read_fd);
timeout.tv_sec = 0;
timeout.tv_usec = 500000;
int ret = select(fd + 1, &read_fd, NULL, NULL, &timeout);
std::cout << "select return:" << ret << std::endl;
if (ret == -1) {
std::cerr << "select error:" << strerror(errno) << " code:" << errno << std::endl;
is_running = false;
}
if (FD_ISSET(fd, &read_fd)) {
if (read(fd, buff, size) == -1) {
if (EIO == errno) {
// After first read - Input/output error code:5
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
std::cerr << "read error:" << strerror(errno) << " code:" << errno << std::endl;
} else {
std::cout << "read:" << buff << std::endl;
}
}
}
std::cout << "read exit" << std::endl;
In terminal I send data from slave to master using
echo "22222222222222" > /dev/pts/23
In case if data send on master side read operation work fine - I see that select returns 1 and data got read but on next iterations in while loop select also returns 1 but read function constantly fails with error EIO and it is not clear for me.
select return:1
read:22222222222222 <------------------------ data read: OK
select return:1
alloc:8 write:7 buff:hello14
read error:Input/output error code:5 <------------------- EIO
select return:1
read error:Input/output error code:5 <------------------- EIO
Could you please help me to understood on why after first read (echo "22222222222222" > /dev/pts/23 on slave) select returns 1 but all read operations fails with EIO error.

LDAP / SASL Client "unable to canonify user and get auxprops"

I'm trying to get some simple username / password authentification against a LDAP / AD server. To test my code I setup a openLDAP Server on my local Ubuntu 18.04. The Application is based on QT 5.12, but this shouldn't have a big influence.
My Goal is to get some wrapper with minimal reliance on system configuration.
To authenticate I tried this code:
int main(int argc, char *argv[])
{
qDebug() << "starting";
QCoreApplication a(argc, argv);
auto* testInst = new ldap_wrapper("ldap:///localhost");
try {
testInst->init();
testInst->authenticate("manager", "manager!");
} catch (char* e) {
qDebug() << "Error: " << e;
}
return a.exec();
}
void ldap_wrapper::authenticate(QString username, QString password) {
this->username = username;
this->password = password;
qDebug() << "starting bind";
int err = ldap_sasl_interactive_bind_s
(
this->handle,
nullptr, // const char * dn
nullptr, // pass null as mechs list, mech negotiated with server.
nullptr, // LDAPControl * sctrls[]
nullptr, // LDAPControl * cctrls[]
LDAP_SASL_QUIET, // unsigned flags
ldapexample_sasl_interact, // LDAP_SASL_INTERACT_PROC * interact
this // void* accessable in callback, we pass ourself.
);
if (err != LDAP_SUCCESS)
{
fprintf(stderr, "ldap_sasl_interactive_bind_s(): %s\n", ldap_err2string(err));
char* errmsg;
ldap_get_option(this->handle, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*)&errmsg);
fprintf(stderr, "ldap_sasl_interactive_bind_s(): %s\n", errmsg);
ldap_memfree(errmsg);
}
}
int ldap_wrapper::ldapexample_sasl_interact(LDAP * ld, unsigned flags, void * defaults, void * sin) {
ldap_wrapper * ldap_inst;
sasl_interact_t * interact;
if (!(ld))
return(LDAP_PARAM_ERROR);
if (!(defaults))
return(LDAP_PARAM_ERROR);
if (!(sin))
return(LDAP_PARAM_ERROR);
switch(flags)
{
case LDAP_SASL_AUTOMATIC:
case LDAP_SASL_INTERACTIVE:
case LDAP_SASL_QUIET:
default:
break;
};
ldap_inst = (ldap_wrapper*)defaults;
for(interact = (sasl_interact_t*)sin; (interact->id != SASL_CB_LIST_END); interact++)
{
qDebug() << "Callback fired";
interact->result = NULL;
interact->len = 0;
switch(interact->id)
{
case SASL_CB_GETREALM:
qDebug() << "realm";
interact->result = ldap_inst->realm.toStdString().c_str();
interact->len = (unsigned)ldap_inst->realm.length();
break;
case SASL_CB_AUTHNAME:
qDebug() << "auth";
case SASL_CB_USER:
qDebug() << "username";
interact->result = ldap_inst->username.toStdString().c_str();
interact->len = (unsigned)ldap_inst->username.length();
break;
case SASL_CB_PASS:
qDebug() << "password";
interact->result = ldap_inst->password.toStdString().c_str();
interact->len = (unsigned)ldap_inst->password.length();
break;
case SASL_CB_NOECHOPROMPT:
qDebug() << "SASL Data: SASL_CB_NOECHOPROMPT";
break;
case SASL_CB_ECHOPROMPT:
qDebug() << "SASL Data: SASL_CB_ECHOPROMPT";
break;
default:
qDebug() << "SASL Data: unknown option: %lu", interact->id;
break;
};
};
return(LDAP_SUCCESS);
}
with this result:
starting bind
Callback fired
username
Callback fired
auth
username
Callback fired
password
ldap_sasl_interactive_bind_s(): Insufficient access
ldap_sasl_interactive_bind_s(): SASL(-14): authorization failure: unable to canonify user and get auxprops
I tries reading the man ldap and googled for hours, but still have absolutly no clue what causes this result.

What is the problem with generated SPIR-V code and how to verify it?

I have some generated SPIR-V code which I want to use with the vulkan API. But I get an
Exception thrown at 0x00007FFB68D933CB (nvoglv64.dll) in vulkanCompute.exe: 0xC0000005: Access violation reading location 0x0000000000000008. when trying to create the pipline with vkCreateComputePipelines.
The API calls should be fine, because the same code works with a shader compiled with glslangValidator. Therefore I assume that the generated SPIR-V code must be illformed somehow.
I've checked the SPIR-V code with the validator tool from khronos, using spirv-val --target-env vulkan1.1 mainV.spv which exited without error. Anyhow it is also known that this tool is still incomplete.
I've also tried to use the Radeon GPU Analyzer to compile my SPIR-V code, which is also available online at the shader playground and this tool throws the error Error: Error: internal error: Bil::BilInstructionConvert::Create(60) Code Not Tested! which is not really helpful, but encourages the assumption that the code is malformed.
The SPIR-V code is unfortunately to long to post it here, but it is in the link of the shader playground.
Does anyone know what the problem is with my setting or has any idea how I can verify my SPIR-V code in a better way, without checking all 700 lines of code manually.
I don't thinkt the problem is there, but anyway here is the c++ host code:
#include "vulkan/vulkan.hpp"
#include <iostream>
#include <fstream>
#include <vector>
#define BAIL_ON_BAD_RESULT(result) \
if (VK_SUCCESS != (result)) \
{ \
fprintf(stderr, "Failure at %u %s\n", __LINE__, __FILE__); \
exit(-1); \
}
VkResult vkGetBestComputeQueueNPH(vk::PhysicalDevice &physicalDevice, uint32_t &queueFamilyIndex)
{
auto properties = physicalDevice.getQueueFamilyProperties();
int i = 0;
for (auto prop : properties)
{
vk::QueueFlags maskedFlags = (~(vk::QueueFlagBits::eTransfer | vk::QueueFlagBits::eSparseBinding) & prop.queueFlags);
if (!(vk::QueueFlagBits::eGraphics & maskedFlags) && (vk::QueueFlagBits::eCompute & maskedFlags))
{
queueFamilyIndex = i;
return VK_SUCCESS;
}
i++;
}
i = 0;
for (auto prop : properties)
{
vk::QueueFlags maskedFlags = (~(vk::QueueFlagBits::eTransfer | vk::QueueFlagBits::eSparseBinding) & prop.queueFlags);
if (vk::QueueFlagBits::eCompute & maskedFlags)
{
queueFamilyIndex = i;
return VK_SUCCESS;
}
i++;
}
return VK_ERROR_INITIALIZATION_FAILED;
}
int main(int argc, const char *const argv[])
{
(void)argc;
(void)argv;
try
{
// initialize the vk::ApplicationInfo structure
vk::ApplicationInfo applicationInfo("VecAdd", 1, "Vulkan.hpp", 1, VK_API_VERSION_1_1);
// initialize the vk::InstanceCreateInfo
std::vector<char *> layers = {
"VK_LAYER_LUNARG_api_dump",
"VK_LAYER_KHRONOS_validation"
};
vk::InstanceCreateInfo instanceCreateInfo({}, &applicationInfo, static_cast<uint32_t>(layers.size()), layers.data());
// create a UniqueInstance
vk::UniqueInstance instance = vk::createInstanceUnique(instanceCreateInfo);
auto physicalDevices = instance->enumeratePhysicalDevices();
for (auto &physicalDevice : physicalDevices)
{
auto props = physicalDevice.getProperties();
// get the QueueFamilyProperties of the first PhysicalDevice
std::vector<vk::QueueFamilyProperties> queueFamilyProperties = physicalDevice.getQueueFamilyProperties();
uint32_t computeQueueFamilyIndex = 0;
// get the best index into queueFamiliyProperties which supports compute and stuff
BAIL_ON_BAD_RESULT(vkGetBestComputeQueueNPH(physicalDevice, computeQueueFamilyIndex));
std::vector<char *>extensions = {"VK_EXT_external_memory_host", "VK_KHR_shader_float16_int8"};
// create a UniqueDevice
float queuePriority = 0.0f;
vk::DeviceQueueCreateInfo deviceQueueCreateInfo(vk::DeviceQueueCreateFlags(), static_cast<uint32_t>(computeQueueFamilyIndex), 1, &queuePriority);
vk::StructureChain<vk::DeviceCreateInfo, vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceShaderFloat16Int8Features> createDeviceInfo = {
vk::DeviceCreateInfo(vk::DeviceCreateFlags(), 1, &deviceQueueCreateInfo, 0, nullptr, static_cast<uint32_t>(extensions.size()), extensions.data()),
vk::PhysicalDeviceFeatures2(),
vk::PhysicalDeviceShaderFloat16Int8Features()
};
createDeviceInfo.get<vk::PhysicalDeviceFeatures2>().features.setShaderInt64(true);
createDeviceInfo.get<vk::PhysicalDeviceShaderFloat16Int8Features>().setShaderInt8(true);
vk::UniqueDevice device = physicalDevice.createDeviceUnique(createDeviceInfo.get<vk::DeviceCreateInfo>());
auto memoryProperties2 = physicalDevice.getMemoryProperties2();
vk::PhysicalDeviceMemoryProperties const &memoryProperties = memoryProperties2.memoryProperties;
const int32_t bufferLength = 16384;
const uint32_t bufferSize = sizeof(int32_t) * bufferLength;
// we are going to need two buffers from this one memory
const vk::DeviceSize memorySize = bufferSize * 3;
// set memoryTypeIndex to an invalid entry in the properties.memoryTypes array
uint32_t memoryTypeIndex = VK_MAX_MEMORY_TYPES;
for (uint32_t k = 0; k < memoryProperties.memoryTypeCount; k++)
{
if ((vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent) & memoryProperties.memoryTypes[k].propertyFlags &&
(memorySize < memoryProperties.memoryHeaps[memoryProperties.memoryTypes[k].heapIndex].size))
{
memoryTypeIndex = k;
std::cout << "found memory " << memoryTypeIndex + 1 << " out of " << memoryProperties.memoryTypeCount << std::endl;
break;
}
}
BAIL_ON_BAD_RESULT(memoryTypeIndex == VK_MAX_MEMORY_TYPES ? VK_ERROR_OUT_OF_HOST_MEMORY : VK_SUCCESS);
auto memory = device->allocateMemoryUnique(vk::MemoryAllocateInfo(memorySize, memoryTypeIndex));
auto in_buffer = device->createBufferUnique(vk::BufferCreateInfo(vk::BufferCreateFlags(), bufferSize, vk::BufferUsageFlagBits::eStorageBuffer, vk::SharingMode::eExclusive));
device->bindBufferMemory(in_buffer.get(), memory.get(), 0);
// create a DescriptorSetLayout
std::vector<vk::DescriptorSetLayoutBinding> descriptorSetLayoutBinding{
{0, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eCompute}};
vk::UniqueDescriptorSetLayout descriptorSetLayout = device->createDescriptorSetLayoutUnique(vk::DescriptorSetLayoutCreateInfo(vk::DescriptorSetLayoutCreateFlags(), static_cast<uint32_t>(descriptorSetLayoutBinding.size()), descriptorSetLayoutBinding.data()));
std::cout << "Memory bound" << std::endl;
std::ifstream myfile;
myfile.open("shaders/MainV.spv", std::ios::ate | std::ios::binary);
if (!myfile.is_open())
{
std::cout << "File not found" << std::endl;
return EXIT_FAILURE;
}
auto size = myfile.tellg();
std::vector<unsigned int> shader_spv(size / sizeof(unsigned int));
myfile.seekg(0);
myfile.read(reinterpret_cast<char *>(shader_spv.data()), size);
myfile.close();
std::cout << "Shader size: " << shader_spv.size() << std::endl;
auto shaderModule = device->createShaderModuleUnique(vk::ShaderModuleCreateInfo(vk::ShaderModuleCreateFlags(), shader_spv.size() * sizeof(unsigned int), shader_spv.data()));
// create a PipelineLayout using that DescriptorSetLayout
vk::UniquePipelineLayout pipelineLayout = device->createPipelineLayoutUnique(vk::PipelineLayoutCreateInfo(vk::PipelineLayoutCreateFlags(), 1, &descriptorSetLayout.get()));
vk::ComputePipelineCreateInfo computePipelineInfo(
vk::PipelineCreateFlags(),
vk::PipelineShaderStageCreateInfo(
vk::PipelineShaderStageCreateFlags(),
vk::ShaderStageFlagBits::eCompute,
shaderModule.get(),
"_ZTSZZ4mainENK3$_0clERN2cl4sycl7handlerEE6VecAdd"),
pipelineLayout.get());
auto pipeline = device->createComputePipelineUnique(nullptr, computePipelineInfo);
auto descriptorPoolSize = vk::DescriptorPoolSize(vk::DescriptorType::eStorageBuffer, 2);
auto descriptorPool = device->createDescriptorPool(vk::DescriptorPoolCreateInfo(vk::DescriptorPoolCreateFlags(), 1, 1, &descriptorPoolSize));
auto commandPool = device->createCommandPoolUnique(vk::CommandPoolCreateInfo(vk::CommandPoolCreateFlags(), computeQueueFamilyIndex));
auto commandBuffer = std::move(device->allocateCommandBuffersUnique(vk::CommandBufferAllocateInfo(commandPool.get(), vk::CommandBufferLevel::ePrimary, 1)).front());
commandBuffer->begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlags(vk::CommandBufferUsageFlagBits::eOneTimeSubmit)));
commandBuffer->bindPipeline(vk::PipelineBindPoint::eCompute, pipeline.get());
commandBuffer->dispatch(bufferSize / sizeof(int32_t), 1, 1);
commandBuffer->end();
auto queue = device->getQueue(computeQueueFamilyIndex, 0);
vk::SubmitInfo submitInfo(0, nullptr, nullptr, 1, &commandBuffer.get(), 0, nullptr);
queue.submit(1, &submitInfo, vk::Fence());
queue.waitIdle();
printf("all done\nWoohooo!!!\n\n");
}
}
catch (vk::SystemError &err)
{
std::cout << "vk::SystemError: " << err.what() << std::endl;
exit(-1);
}
catch (std::runtime_error &err)
{
std::cout << "std::runtime_error: " << err.what() << std::endl;
exit(-1);
}
catch (...)
{
std::cout << "unknown error\n";
exit(-1);
}
return EXIT_SUCCESS;
}
Well after checking out line per line it showed that the problem is when working with pointers of pointers. For me it is still not clear from the specification that it is not allowed, but it is understandable that it does not work with logical pointers.
Still the behaviour is strange that the validator is not able to note that and that compiling the SPIRV code crashes instead of throwing a clear error message.
So in the end, it was the Shader code which was wrong.

SIGSEGV on second call to boost::asio::udp socket::async_recv on worker boost::thread

I get a SIGSEGV in following class on the second time I call the start_receive(). It works correctly in my open() function, but seems to fail when input is received and I try restarting listen for more input:
#0 0x0000555555584154 in boost::asio::basic_io_object<boost::asio::datagram_socket_service<boost::asio::ip::udp>, true>::get_service (this=0x100007f00000000)
at /usr/include/boost/asio/basic_io_object.hpp:225
#1 0x000055555558398b in boost::asio::basic_datagram_socket<boost::asio::ip::udp, boost::asio::datagram_socket_service<boost::asio::ip::udp> >::async_receive_from<boost::asio::mutable_buffers_1, boost::_bi::bind_t<int, boost::_mfi::mf2<int, Vast::net_udpNC_MChandler, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<Vast::net_udpNC_MChandler*>, boost::arg<1> (*)(), boost::arg<2> (*)()> > > (this=0x100007f00000000, buffers=...,
sender_endpoint=..., handler=...)
at /usr/include/boost/asio/basic_datagram_socket.hpp:895
#2 0x000055555557a889 in Vast::net_udpNC_MChandler::start_receive (
this=0x7fffffff5c70) at net_udpnc_mchandler.cpp:58
#3 0x000055555557aa77 in Vast::net_udpNC_MChandler::handle_input (
this=0x7fffffff5c70, error=..., bytes_transferred=24)
at net_udpnc_mchandler.cpp:100
#4 0x000055555557abb3 in Vast::net_udpNC_MChandler::handle_buffer (
this=0x7fffffff5c70, buf=0x7fffffffdad0 "\035\300", bytes_transferred=24)
at net_udpnc_mchandler.cpp:114
#5 0x000055555556397f in test_process_encoded ()
at unittest_net_udpnc_mchandler.cpp:43
#6 0x000055555556400e in main () at unittest_net_udpnc_mchandler.cpp:101
Header:
class net_udpNC_MChandler
{
public:
net_udpNC_MChandler(ip::udp::endpoint local_endpoint);
//MChandler will run its own io_service
int open (AbstractRLNCMsgReceiver *msghandler);
int handle_buffer (char *buf, std::size_t bytes_transferred);
protected:
//Start the receiving loop
void start_receive ();
// handling incoming message
int handle_input (const boost::system::error_code& error,
std::size_t bytes_transferred);
private:
ip::udp::socket *_udp;
ip::udp::endpoint _remote_endpoint_;
ip::udp::endpoint _local_endpoint;
ip::udp::endpoint MC_address;
char _buf[VAST_BUFSIZ];
AbstractRLNCMsgReceiver *_msghandler = NULL;
io_service *_io_service;
boost::thread *_iosthread;
};
Source file:
net_udpNC_MChandler::net_udpNC_MChandler(ip::udp::endpoint local_endpoint) :
MC_address(ip::address::from_string("239.255.0.1"), 1037)
{
_io_service = new io_service();
_local_endpoint = local_endpoint;
}
int net_udpNC_MChandler::open(AbstractRLNCMsgReceiver *msghandler) {
_msghandler = msghandler;
if (_udp == NULL) {
_udp = new ip::udp::socket(*_io_service);
_udp->open(ip::udp::v4());
_udp->set_option(ip::udp::socket::reuse_address(true));
_udp->set_option(ip::multicast::join_group(MC_address.address ()));
boost::system::error_code ec;
_udp->bind(MC_address, ec);
std::cout << "net_udpnc_mchandler::open " + ec.message() << std::endl;
if (ec)
{
std::cout << "net_udpnc_mchandler:: open MC address failed" << ec.message() << std::endl;
}
//Add async receive to io_service queue
start_receive();
std::cout << "net_udpnc_mchandler::open _udp->_local_endpoint: " << _udp->local_endpoint() << " _local_endpoint" << _local_endpoint << std::endl;
//Start the thread handling async receives
_iosthread = new boost::thread(boost::bind(&boost::asio::io_service::run, _io_service));
}
return 0;
}
void net_udpNC_MChandler::start_receive()
{
_udp->async_receive_from(
boost::asio::buffer(_buf, VAST_BUFSIZ), _remote_endpoint_,
boost::bind(&net_udpNC_MChandler::handle_input, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
// handling incoming message
int net_udpNC_MChandler::handle_input (const boost::system::error_code& error,
std::size_t bytes_transferred)
{
RLNCHeader header;
if (!error)
{
//Store UDP messages
char *p = _buf;
memcpy(&header, p, sizeof(RLNCHeader));
if (RLNCHeader_factory::isRLNCHeader (header) && header.enc_packet_count > 1)
{
CPPDEBUG("net_udpnc_mchandler::handle_input: Encoded packet received" << std::endl);
process_encoded (bytes_transferred);
}
//Restart waiting for new packets
start_receive();
}
else {
CPPDEBUG("Error on UDP socket receive: " << error.message() << std::endl;);
}
return -1;
}
The strangest thing is that everything works if I use a default constructor without arguments (i.e. no local_endpoint), this SIGSEGV does not appear. But as soon as I change the constructor to the current one, I get the SIGSEGV.
The _io_service is a class object and it does not get destructed anywhere but the destructor, so I do not know how I can get a SIGSEGV for it...
Is there some requirement on the handler class that it has a no arguments constructor?

Apache thrift multi client server

I am writing simple chat in Qt + Apache Thrift but right now I need to face a problem with connecting multiple clients. On first sight everything looks good and I cannot find where the problem is.
Here is my server main.cpp:
int main(int argc, char **argv)
{
int port = 9090;
::apache::thrift::stdcxx::shared_ptr<UsersStorageHandler> handler(new UsersStorageHandler());
::apache::thrift::stdcxx::shared_ptr<TProcessor> processor(new UsersStorageProcessor(handler));
::apache::thrift::stdcxx::shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
::apache::thrift::stdcxx::shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
::apache::thrift::stdcxx::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
std::cout << "Users server started..." << std::endl;
std::cout << std::endl;
std::cout << std::endl;
server.serve();
return 0;
}
Here is my server handler.h:
class UsersStorageHandler : virtual public UsersStorageIf
{
public:
UsersStorageHandler();
int32_t subscribeUser(const std::string& username);
void unsubscribeUser(const int32_t userID);
private:
Users users;
};
Here is my server handler.cpp:
UsersStorageHandler::UsersStorageHandler()
{
srand(time(NULL));
}
int32_t UsersStorageHandler::subscribeUser(const std::string &username)
{
++idGenerator;
assert(username != "");
User user;
user.userId = idGenerator;
user.username = username;
user.colorR = (rand() % 255) + 0;
user.colorG = (rand() % 255) + 0;
user.colorB = (rand() % 255) + 0;
user.colorA = 0;
users[idGenerator] = user;
std::cout << "NEW USER CONNECTED" << std::endl;
std::cout << "==================" << std::endl;
std::cout << "Username:\t" << user.username << std::endl;
std::cout << "User ID:\t" << user.userId << std::endl;
std::cout << "User R:\t" << user.colorR << std::endl;
std::cout << "User G:\t" << user.colorG << std::endl;
std::cout << "User B:\t" << user.colorB << std::endl;
std::cout << "User A:\t" << user.colorA << std::endl;
std::cout << "==================" << std::endl;
std::cout << "CURRENT USERS COUNT:\t" << users.size() << std::endl;
std::cout << std::endl;
std::cout << std::endl;
/*
* SEND TO CLIENT INFO ABOUT NEW USER HERE
*/
return idGenerator;
}
void UsersStorageHandler::unsubscribeUser(const int32_t userID)
{
auto index = users.find(userID);
assert(index != users.end());
users.erase(index);
std::cout << "USER DISCONNECTED" << std::endl;
std::cout << "=================" << std::endl;
std::cout << "USER WITH ID " << userID << " ERASED" << std::endl;
std::cout << "USERS COUNT:\t" << users.size() << std::endl;
std::cout << std::endl;
std::cout << std::endl;
/*
* SEND TO CLIENT INFO ABOUT NEW USER HERE
*/
}
And right here is a method for connect to the server in client app:
void MainWindow::connectToServers(const std::string &ip, const uint32_t &port, const std::string &nick)
{
m_usersServerIP = ip;
m_usersServerPort = port;
try
{
::apache::thrift::stdcxx::shared_ptr<TTransport> socket(new TSocket(m_usersServerIP, m_usersServerPort));
::apache::thrift::stdcxx::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
::apache::thrift::stdcxx::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
m_usersServerClient = std::make_shared<UsersStorageClient>(protocol);
transport->open();
m_clientID = m_usersServerClient.get()->subscribeUser(nick);
QMessageBox::information(this, "Connected",
"You are connected "
"with users server");
createAndRegisterUsersServerReactor();
activateChatScreen();
}
catch (const std::exception &e)
{
qDebug() << e.what();
}
qDebug() << "ID FROM SERVER:\t" << m_clientID;
}
As far as I checked right now it is working like this:
Created two instances of client app. In one instance fill nickname, ip, port and clicked connect (connectToServers method). Client connected. In another instance done the same but after clicked connected ... nothing happens. App freezes at this line:
m_clientID = m_usersServerClient.get()->subscribeUser(nick);
After closing first client, second one connects to the server.
A TSimplerServer supports a single connection. You should try using TThreadedServer to support multiple simultaneous clients.
As Chris mentioned above either make a Threaded server to server multiple requests simultaneously. For me I have created a non-blocking server as below to be able to serve multiple clients in async manner for loose coupling.
public static void start(dataClass configData, String env, int port) throws TTransportException {
TNonblockingServerTransport transport = new TNonblockingServerSocket(port);
TNonblockingServer.Args nBlockServer = new TNonblockingServer.Args(transport);
ccmProviderServiceImpl impl = new ccmProviderServiceImpl(configData, env);
Processor<ccmProviderServiceImpl> processor = new ccmProviderService.Processor<>(impl);
TServer server = new TNonblockingServer(nBlockServer.processor(processor));
//custom event handling for tracking
ccmServerEventHandler cse = new ccmServerEventHandler();
server.setServerEventHandler(cse);
server.serve();
}