parent
70d08dd981
commit
36879aa9c5
@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
The license model for this software (TestModbus-Client) is not yet choosen.
|
||||||
|
At the moment you can use this software free of charge at your own risk.
|
||||||
|
|
||||||
|
27.Aug.2023 Steffen Pohle
|
||||||
|
|
@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
TARGETEXT = .exe
|
||||||
|
CONFIGSET = YES
|
||||||
|
CROSSENV = /opt/W64-cross-compile/
|
||||||
|
CPP = /usr/bin/x86_64-w64-mingw32-g++
|
||||||
|
CPPFLAGS = -ggdb -Wall -O0 `PKG_CONFIG_PATH=$(CROSSENV)/lib/pkgconfig pkg-config --cflags gtk+-3.0 gmodule-export-2.0` -Wl,--export-dynamic -DBUILD_WINDOWS=1 -Wdeprecated
|
||||||
|
INCLUDES =
|
||||||
|
LDFLAGS = -lws2_32
|
||||||
|
LIBS = `PKG_CONFIG_PATH=$(CROSSENV)/lib/pkgconfig pkg-config --libs gtk+-3.0 gmodule-export-2.0` -L/usr/lib -mwindows
|
@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
TARGETEXT =
|
||||||
|
CONFIGSET = YES
|
||||||
|
CPP = c++
|
||||||
|
CPPFLAGS = -ggdb -Wall -O0 `pkg-config --cflags gtk+-3.0 gmodule-export-2.0` -Wl,--export-dynamic -I/usr/include -DBUILD_LINUX=1
|
||||||
|
INCLUDES =
|
||||||
|
LDFLAGS =
|
||||||
|
LIBS = `pkg-config --libs gtk+-3.0 gmodule-export-2.0` -L/usr/lib
|
@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
TARGETEXT = .exe
|
||||||
|
CONFIGSET = YES
|
||||||
|
CPP = g++
|
||||||
|
CPPFLAGS = -ggdb -Wall -O0 `pkg-config --cflags gtk+-3.0 gmodule-export-2.0` -Wl,--export-dynamic -I/usr/include -DBUILD_WINDOWS=1
|
||||||
|
INCLUDES =
|
||||||
|
LDFLAGS = -lWs2_32
|
||||||
|
LIBS = `pkg-config --libs gtk+-3.0 gmodule-export-2.0` -L/usr/lib
|
@ -0,0 +1,52 @@
|
|||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "client.h"
|
||||||
|
|
||||||
|
#define BUILDER_FILE "testmodbus-client.ui"
|
||||||
|
|
||||||
|
/************************************************************************************
|
||||||
|
* Global Variables
|
||||||
|
*/
|
||||||
|
GtkBuilder *_builder_ = NULL; // work around for the thread situation
|
||||||
|
gboolean modbuscli_callback(gpointer data); // callback for threads
|
||||||
|
|
||||||
|
int main (int argc, char **argv) {
|
||||||
|
GtkBuilder *builder;
|
||||||
|
GObject *window;
|
||||||
|
|
||||||
|
#ifdef BUILD_WINDOWS
|
||||||
|
char buffer[16];
|
||||||
|
setvbuf (stdout, buffer, _IONBF, 16);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
printf ("TestModbus-Client - %s\n", VERSION);
|
||||||
|
printf (" https://steffen.gulpe.de/modbus-tcpip\n");
|
||||||
|
printf (" written by Steffen Pohle <steffen@gulpe.de>\n");
|
||||||
|
|
||||||
|
gtk_init (&argc, &argv);
|
||||||
|
_builder_ = builder = gtk_builder_new ();
|
||||||
|
gtk_builder_add_from_file (builder, BUILDER_FILE, NULL);
|
||||||
|
gtk_builder_connect_signals(builder, builder);
|
||||||
|
|
||||||
|
//
|
||||||
|
// #if defined _WIN32 || defined _WIN64 || defined __CYGWIN__
|
||||||
|
// #else
|
||||||
|
// #endif
|
||||||
|
//
|
||||||
|
|
||||||
|
// modbuscli.SetCallback(&modbus_callback);
|
||||||
|
window = gtk_builder_get_object (builder, "testmodbus-client");
|
||||||
|
gtk_widget_show_all (GTK_WIDGET(window));
|
||||||
|
gtk_main ();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gboolean modbuscli_callback(gpointer data) {
|
||||||
|
void *mdata = data;
|
||||||
|
free (mdata);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
};
|
@ -0,0 +1,35 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// client.h is part of TestModbus-Client.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef _CLIENT_H_
|
||||||
|
#define _CLIENT_H_
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <gdk/gdk.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// ***********************************************************************
|
||||||
|
//
|
||||||
|
// main windows call backs
|
||||||
|
//
|
||||||
|
|
||||||
|
G_MODULE_EXPORT gboolean modbus_callback (gpointer data);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,39 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
CROSS_DEST_DIR=/opt/W64-cross-compile/lib
|
||||||
|
CROSS_COMPILER_DIR=/usr/x86_64-w64-mingw32/lib
|
||||||
|
CROSS_GCC_DIR=/usr/lib/gcc/x86_64-w64-mingw32/10-win32
|
||||||
|
|
||||||
|
cp -v $CROSS_COMPILER_DIR/zlib1.dll ./
|
||||||
|
|
||||||
|
# copy dll dependencys
|
||||||
|
copy_dependency() {
|
||||||
|
local I
|
||||||
|
for I in `strings $1 | grep -i '\.dll$' | grep -e "^lib"`
|
||||||
|
do
|
||||||
|
if [ -e ./$I ]
|
||||||
|
then
|
||||||
|
echo "File Exist"
|
||||||
|
|
||||||
|
elif [ -e $CROSS_COMPILER_DIR/$I ]
|
||||||
|
then
|
||||||
|
cp -v $CROSS_COMPILER_DIR/$I ./
|
||||||
|
copy_dependency $CROSS_COMPILER_DIR/$I
|
||||||
|
|
||||||
|
elif [ -e $CROSS_GCC_DIR/$I ]
|
||||||
|
then
|
||||||
|
cp -v $CROSS_GCC_DIR/$I ./
|
||||||
|
copy_dependency $CROSS_GCC_DIR/$I
|
||||||
|
|
||||||
|
elif [ -e $CROSS_DEST_DIR/$I ]
|
||||||
|
then
|
||||||
|
cp -v $CROSS_DEST_DIR/$I ./
|
||||||
|
copy_dependency $CROSS_DEST_DIR/$I
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
copy_dependency testmodbus-server.exe
|
||||||
|
copy_dependency testmodbus-client.exe
|
||||||
|
|
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
CROSS_PREFIX=/opt/W64-cross-compile
|
||||||
|
|
||||||
|
mkdir share
|
||||||
|
cp -rf $CROSS_PREFIX/share/glib-2.0 share/glib-2.0
|
||||||
|
cp -rf $CROSS_PREFIX/share/gtk-2.0 share/gtk-4.0
|
||||||
|
cp -rf $CROSS_PREFIX/share/gtk-3.0 share/gtk-3.0
|
||||||
|
cp -rf $CROSS_PREFIX/share/icons share/icons
|
||||||
|
|
@ -0,0 +1,519 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// tcp.cc is part of TestModbus-Server.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "tcp.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
|
||||||
|
#else
|
||||||
|
#include <unistd.h> /* close() */
|
||||||
|
#endif
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h> /* memset() */
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int tcpinit;
|
||||||
|
//
|
||||||
|
// convert host and port to sockaddr_in6
|
||||||
|
//
|
||||||
|
int dns_filladdr (string host, string port, int ai_family, struct sockaddr_storage *sAddr) {
|
||||||
|
struct addrinfo hints, *res;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
bzero (&hints, sizeof (struct addrinfo));
|
||||||
|
hints.ai_family = ai_family;
|
||||||
|
hints.ai_socktype = SOCK_DGRAM;
|
||||||
|
|
||||||
|
if ((err = getaddrinfo (host.c_str(), port.c_str(), &hints, &res)) < 0) {
|
||||||
|
fprintf (stdout, "dns_filladdr (getaddrinfo):%s\n", gai_strerror (err));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy (sAddr, res->ai_addr, res->ai_addrlen);
|
||||||
|
freeaddrinfo (res);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// convert int to char*
|
||||||
|
//
|
||||||
|
char* itoa(char* buffer, int number, int size) {
|
||||||
|
snprintf (buffer, size, "%d", number);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TCP::~TCP() {
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
TCP::TCP() {
|
||||||
|
if (tcpinit == 0) {
|
||||||
|
#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) || defined(BUILD_WINDOWS)
|
||||||
|
|
||||||
|
WORD wVersionRequested;
|
||||||
|
WSADATA wsaData;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
|
||||||
|
wVersionRequested = MAKEWORD(2, 2);
|
||||||
|
|
||||||
|
err = WSAStartup(wVersionRequested, &wsaData);
|
||||||
|
if (err != 0) {
|
||||||
|
/* Tell the user that we could not find a usable */
|
||||||
|
/* Winsock DLL. */
|
||||||
|
printf("WSAStartup failed with error: %d\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
tcpinit = 1;
|
||||||
|
}
|
||||||
|
sock = 0;
|
||||||
|
writecnt = 0;
|
||||||
|
readcnt = 0;
|
||||||
|
islisten = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
TCP::TCP(int s) {
|
||||||
|
TCP();
|
||||||
|
sock = s;
|
||||||
|
// memset (&localaddr, 0x0, sizeof(localaddr));
|
||||||
|
// memset (&remoteaddr, 0x0, sizeof(remoteaddr));
|
||||||
|
writecnt = 0;
|
||||||
|
readcnt = 0;
|
||||||
|
islisten = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
TCP::TCP(string h, string p) {
|
||||||
|
TCP();
|
||||||
|
Connect (h,p);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* puts the tcp server to listen mode. This code works on linux with IPV4 and IPV6
|
||||||
|
*/
|
||||||
|
int TCP::Listen(int port) {
|
||||||
|
char buffer[NET_BUFFERSIZE];
|
||||||
|
int err, i;
|
||||||
|
struct addrinfo hints, *res, *rp;
|
||||||
|
|
||||||
|
if (sock > 0) Close();
|
||||||
|
bzero (&hints, sizeof (struct addrinfo));
|
||||||
|
hints.ai_flags = AI_PASSIVE;
|
||||||
|
#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
|
||||||
|
hints.ai_family = AF_INET;
|
||||||
|
#else
|
||||||
|
hints.ai_family = AF_INET6;
|
||||||
|
#endif
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
if ((err = getaddrinfo (NULL, itoa(buffer, port, 32), &hints, &res)) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// walk through all results until we could connect
|
||||||
|
//
|
||||||
|
for (rp = res; rp != NULL; rp = rp->ai_next) {
|
||||||
|
sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||||
|
if (sock == -1) continue;
|
||||||
|
|
||||||
|
i = 1;
|
||||||
|
if ((err = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (char*)&i, sizeof (i))) != 0) {
|
||||||
|
printf ("%s:%d setsockopt error\n", __FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((err = bind (sock, rp->ai_addr, rp->ai_addrlen)) < 0) {
|
||||||
|
close (sock);
|
||||||
|
sock = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (listen (sock, 8) < 0) { // maximum of 8 connections at the time
|
||||||
|
close (sock);
|
||||||
|
sock = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeaddrinfo (res);
|
||||||
|
|
||||||
|
if (rp == NULL) {
|
||||||
|
sock = -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
islisten = 1;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TCP* TCP::Accept() {
|
||||||
|
fd_set rfds;
|
||||||
|
struct timeval tv;
|
||||||
|
int retval;
|
||||||
|
SOCKET newsock;
|
||||||
|
struct sockaddr_storage cliaddr;
|
||||||
|
socklen_t cliaddr_len = sizeof(struct sockaddr_storage);
|
||||||
|
TCP *tcp = NULL;
|
||||||
|
|
||||||
|
if (sock <= 0) return NULL;
|
||||||
|
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
FD_SET(sock, &rfds);
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 1000;
|
||||||
|
|
||||||
|
retval = select (sock+1, &rfds, NULL, NULL, &tv);
|
||||||
|
if (retval == -1 && errno == EINTR) {
|
||||||
|
retval = 0;
|
||||||
|
}
|
||||||
|
else if (retval == -1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else if (retval) {
|
||||||
|
#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
|
||||||
|
newsock = accept (sock, (struct sockaddr *) &cliaddr, (int*) &cliaddr_len);
|
||||||
|
#else
|
||||||
|
newsock = accept (sock, (struct sockaddr *) &cliaddr, &cliaddr_len);
|
||||||
|
#endif
|
||||||
|
if (newsock < 0) return NULL;
|
||||||
|
tcp = new TCP();
|
||||||
|
tcp->SetSocket(newsock, &cliaddr, cliaddr_len);
|
||||||
|
|
||||||
|
return tcp;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int TCP::Connect(string h, string p) {
|
||||||
|
remote_host = h;
|
||||||
|
remote_port = p;
|
||||||
|
|
||||||
|
return Connect();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int TCP::Connect(string hostport, int defaultport) {
|
||||||
|
char buffer[32];
|
||||||
|
int pos = hostport.rfind(':', hostport.length());
|
||||||
|
if (pos == -1) {
|
||||||
|
remote_port = itoa (buffer, defaultport, 32);
|
||||||
|
remote_host = hostport;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
remote_port = hostport.substr (pos+1, hostport.length() - pos);
|
||||||
|
remote_host = hostport.substr (0, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Connect();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int TCP::Connect() {
|
||||||
|
int err, s;
|
||||||
|
struct addrinfo hints, *res, *rp;
|
||||||
|
struct timeval timeout;
|
||||||
|
|
||||||
|
memset(&hints, 0, sizeof(struct addrinfo));
|
||||||
|
hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_flags = 0;
|
||||||
|
hints.ai_protocol = 0;
|
||||||
|
|
||||||
|
err = getaddrinfo(remote_host.c_str(), remote_port.c_str(), &hints, &res);
|
||||||
|
if (err != 0) {
|
||||||
|
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// walk through all results until we could connect
|
||||||
|
//
|
||||||
|
for (rp = res; rp != NULL; rp = rp->ai_next) {
|
||||||
|
s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||||
|
|
||||||
|
// setup timeout to max 2 secs
|
||||||
|
timeout.tv_sec = 2;
|
||||||
|
timeout.tv_usec = 0;
|
||||||
|
setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout));
|
||||||
|
|
||||||
|
if (s == -1) continue;
|
||||||
|
if (connect(s, rp->ai_addr, rp->ai_addrlen) != -1) {
|
||||||
|
sock = s;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
close(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
freeaddrinfo(res);
|
||||||
|
|
||||||
|
//
|
||||||
|
// connect not successfull
|
||||||
|
//
|
||||||
|
if (rp == NULL) return 0;
|
||||||
|
|
||||||
|
writecnt = 0;
|
||||||
|
readcnt = 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
long int TCP::ReadPop (char *buffer, long int pktlen, long int bufferlen) {
|
||||||
|
memmove (buffer, buffer+pktlen, bufferlen-pktlen);
|
||||||
|
return bufferlen-pktlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
long int TCP::Read(char *buffer, long int len) {
|
||||||
|
long int len_ = len;
|
||||||
|
|
||||||
|
if (sock <= 0) return -2;
|
||||||
|
len_ = recv (sock, buffer, len, 0);
|
||||||
|
|
||||||
|
if (len_ < 0 && errno == EAGAIN) len_ = 0;
|
||||||
|
else if (len_ < 0 && errno != EAGAIN) {
|
||||||
|
#ifdef BUILD_WINDOWS
|
||||||
|
printf ("%s ERROR:%s\n", __FUNCTION__, strerror (errno));
|
||||||
|
#else
|
||||||
|
fprintf (stderr, "%s ERROR:%s\n", __FUNCTION__, strerror (errno));
|
||||||
|
#endif
|
||||||
|
len_ = -2;
|
||||||
|
}
|
||||||
|
else if (len_ == 0) len_ = -1;
|
||||||
|
if (len_ < 0) Close();
|
||||||
|
|
||||||
|
readcnt += len_;
|
||||||
|
|
||||||
|
return len_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
long int TCP::ReadTimeout(char *buffer, long int len, int timeout) {
|
||||||
|
int data = IsData (timeout);
|
||||||
|
|
||||||
|
if (data > 0) return Read (buffer, len);
|
||||||
|
else if (data < 0) return -1;
|
||||||
|
else return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// write data, generate no signal if some error occures
|
||||||
|
long int TCP::Write(char *buffer, long int len) {
|
||||||
|
int i;
|
||||||
|
int to = NET_MAX_RETRY;
|
||||||
|
|
||||||
|
if (sock <= 0) return -1;
|
||||||
|
|
||||||
|
do {
|
||||||
|
i = send (sock, buffer, len, MSG_NOSIGNAL);
|
||||||
|
} while (i == -1 && (to--) > 0 && errno == EINTR);
|
||||||
|
|
||||||
|
if (i < 0) Close ();
|
||||||
|
writecnt += i;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void TCP::Close() {
|
||||||
|
#ifdef BUILD_WINDOWS
|
||||||
|
closesocket(sock);
|
||||||
|
#else
|
||||||
|
if (sock > 0) close (sock);
|
||||||
|
#endif
|
||||||
|
sock = -1;
|
||||||
|
islisten = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void TCP::SetSocket(SOCKET s, struct sockaddr_storage *saddr, socklen_t saddrlen) {
|
||||||
|
char host[NET_HOSTLEN];
|
||||||
|
char port[NET_PORTLEN];
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (sock > 0) Close();
|
||||||
|
if (s > 0) {
|
||||||
|
sock = s;
|
||||||
|
|
||||||
|
if (saddr != NULL) {
|
||||||
|
memcpy (&peeraddr, saddr, sizeof(peeraddr));
|
||||||
|
if ((err = getnameinfo ((struct sockaddr*) saddr, saddrlen, host, NET_HOSTLEN,
|
||||||
|
port, NET_PORTLEN, NI_NUMERICHOST | NI_NUMERICSERV)) == 0) {
|
||||||
|
remote_host = host;
|
||||||
|
remote_port = port;
|
||||||
|
} else {
|
||||||
|
printf ("error: getnameinfo");
|
||||||
|
/* if (err == EAI_AGAIN) printf ("EAI_AGAIN\n");
|
||||||
|
if (err == EAI_BADFLAGS) printf ("EAI_BADFLAGS\n");
|
||||||
|
if (err == EAI_FAIL) printf ("EAI_FAIL\n");
|
||||||
|
if (err == EAI_FAMILY) printf ("EAI_FAMILY\n");
|
||||||
|
if (err == EAI_MEMORY) printf ("EAI_MEMORY\n");
|
||||||
|
if (err == EAI_NONAME) printf ("EAI_NONAME\n");
|
||||||
|
if (err == EAI_OVERFLOW) printf ("EAI_OVERFLOW\n");
|
||||||
|
if (err == EAI_SYSTEM) printf ("EAI_SYSTEM\n"); */ // windows seem to have different error codes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else sock = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int TCP::IsConnected() {
|
||||||
|
return (sock > 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int TCP::IsData(int timeout) {
|
||||||
|
fd_set sockset;
|
||||||
|
struct timeval tval;
|
||||||
|
|
||||||
|
if (sock <= 0) return -1;
|
||||||
|
|
||||||
|
FD_ZERO (&sockset);
|
||||||
|
FD_SET (sock, &sockset);
|
||||||
|
tval.tv_sec = timeout / 1000;
|
||||||
|
tval.tv_usec = (timeout % 1000);
|
||||||
|
if ((select (sock + 1, &sockset, NULL, NULL, &tval)) != -1) {
|
||||||
|
if (FD_ISSET (sock, &sockset)) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (errno == EBADF) sock = -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int TCP::WebGetFile (string url, char *buffer, int maxsize) {
|
||||||
|
char outdata[NET_BUFFERSIZE];
|
||||||
|
char indata[NET_BUFFERSIZE];
|
||||||
|
char host[NET_HOSTLEN];
|
||||||
|
char port[NET_PORTLEN];
|
||||||
|
int breakup, len, head, i, buffpos = 0;
|
||||||
|
|
||||||
|
if (!IsConnected()) {
|
||||||
|
strncpy (host, WebGetURLHost (url).c_str(), NET_HOSTLEN);
|
||||||
|
strncpy (port, WebGetURLPort (url).c_str(), NET_PORTLEN);
|
||||||
|
Connect (host, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsConnected()) return -1;
|
||||||
|
|
||||||
|
// send http request
|
||||||
|
snprintf (outdata, NET_BUFFERSIZE, "GET %s HTTP/1.0\nUser-Agent: unknown \nHost: %s\n\n", WebGetURLFile (url).c_str(), host);
|
||||||
|
Write (outdata, strlen (outdata));
|
||||||
|
|
||||||
|
// wait for data start
|
||||||
|
i = breakup = 0;
|
||||||
|
head = 1;
|
||||||
|
while (!breakup && head && (len = ReadTimeout (indata, NET_BUFFERSIZE-1, 2000)) >= 0) {
|
||||||
|
indata[len] = 0;
|
||||||
|
while (i < len -4 && head && !breakup) {
|
||||||
|
if (indata[i] == 0x0d && indata [i+1] == 0x0a && indata [i+2] == 0x0d && indata [i+3] == 0x0a) {
|
||||||
|
head = 0;
|
||||||
|
i = i + 4;
|
||||||
|
buffpos = len-i;
|
||||||
|
if (buffpos > maxsize) buffpos = maxsize;
|
||||||
|
memcpy (buffer, indata+i, buffpos);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (strncmp (indata+i, "Content-Length:", 15) == 0) {
|
||||||
|
i = i + 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (strncmp (indata+i, "403 ", 4) == 0) breakup = 1;
|
||||||
|
else i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// read data
|
||||||
|
while (!breakup && (len = ReadTimeout (indata, NET_BUFFERSIZE-1, 2000)) >= 0) {
|
||||||
|
i = len;
|
||||||
|
if (i > maxsize-buffpos) i = maxsize-buffpos;
|
||||||
|
if (i > 0) {
|
||||||
|
memcpy (buffer+buffpos, indata, i);
|
||||||
|
buffpos += i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffpos;
|
||||||
|
};
|
||||||
|
|
||||||
|
const string TCP::WebGetURLHost (string url) {
|
||||||
|
string result;
|
||||||
|
int posSServPort = 7; // begin server:port
|
||||||
|
int posEServPort = 0; // end Server:Port
|
||||||
|
int posPort = -1; // port Position
|
||||||
|
|
||||||
|
posEServPort = url.find("/", 7);
|
||||||
|
result = url.substr (posSServPort, posEServPort-posSServPort);
|
||||||
|
posPort = result.find(":");
|
||||||
|
if (posPort > 0)
|
||||||
|
result = url.substr (posSServPort, posPort);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const string TCP::WebGetURLPort (string url) {
|
||||||
|
string result;
|
||||||
|
int posSServPort = 7; // begin server:port
|
||||||
|
int posEServPort = 0; // end Server:Port
|
||||||
|
int posPort = -1; // port Position
|
||||||
|
|
||||||
|
posEServPort = url.find("/", 7);
|
||||||
|
result = url.substr (posSServPort, posEServPort-posSServPort);
|
||||||
|
posPort = result.find(":");
|
||||||
|
if (posPort > 0)
|
||||||
|
result = result.substr (posPort+1);
|
||||||
|
else
|
||||||
|
result = "80";
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const string TCP::WebGetURLFile (string url) {
|
||||||
|
string result;
|
||||||
|
int posEServPort = 0; // end Server:Port
|
||||||
|
|
||||||
|
posEServPort = url.find("/", 7);
|
||||||
|
result = url.substr (posEServPort);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const string TCP::GetRemoteAddr() {
|
||||||
|
string ret = "";
|
||||||
|
socklen_t addrlen = sizeof (peeraddr);
|
||||||
|
char host[256] = "";
|
||||||
|
char port[256] = "";
|
||||||
|
|
||||||
|
if (getnameinfo ((struct sockaddr*)&peeraddr, addrlen, host, 255, port, 255, NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
|
||||||
|
printf ("getnameinfo error: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = (string)host + ":" + (string)port;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const string TCP::GetLocalAddr() {
|
||||||
|
string ret;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
@ -0,0 +1,123 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// tcp.h is part of TestModbus-Server.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef _TCP_H_
|
||||||
|
#define _TCP_H_
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
|
#define _NTDDI_VERSION_FROM_WIN32_WINNT2(ver) ver##0000
|
||||||
|
#define _NTDDI_VERSION_FROM_WIN32_WINNT(ver) _NTDDI_VERSION_FROM_WIN32_WINNT2(ver)
|
||||||
|
|
||||||
|
#ifndef _WIN32_WINNT
|
||||||
|
# define _WIN32_WINNT 0x501
|
||||||
|
#endif
|
||||||
|
#ifndef NTDDI_VERSION
|
||||||
|
# define NTDDI_VERSION _NTDDI_VERSION_FROM_WIN32_WINNT(_WIN32_WINNT)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// #include <winsock.h>
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <io.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define socklen_t size_t
|
||||||
|
|
||||||
|
#ifndef bzero
|
||||||
|
#define bzero(__z__, __x__) memset (__z__, 0x0, __x__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MSG_NOSIGNAL
|
||||||
|
# define MSG_NOSIGNAL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#define SOCKET int
|
||||||
|
|
||||||
|
#define NET_HOSTLEN 256
|
||||||
|
#define NET_PORTLEN 6
|
||||||
|
#define NET_BUFFERSIZE 1024
|
||||||
|
#define NET_MAX_RETRY 5 // retry to send data EINTR
|
||||||
|
#define NET_MAX_TIMEOUT 30000 // timeout in ms
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
*
|
||||||
|
* global functions needed for networking
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int dns_filladdr (string host, string port, int ai_family,
|
||||||
|
struct sockaddr_storage *sAddr);
|
||||||
|
char *itoa(char* buffer, int number, int size);
|
||||||
|
void UDPTCPNetwork_Startup();
|
||||||
|
extern int UDPTCPNetwork_init;
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
* tcp related functions
|
||||||
|
*/
|
||||||
|
class TCP {
|
||||||
|
private:
|
||||||
|
SOCKET sock;
|
||||||
|
struct sockaddr_storage peeraddr;
|
||||||
|
string remote_host;
|
||||||
|
string remote_port;
|
||||||
|
int readcnt;
|
||||||
|
int writecnt;
|
||||||
|
int islisten;
|
||||||
|
public:
|
||||||
|
TCP();
|
||||||
|
TCP(SOCKET s);
|
||||||
|
TCP(string h, string p);
|
||||||
|
TCP(string hostport, int defaultport);
|
||||||
|
~TCP();
|
||||||
|
|
||||||
|
int Connect();
|
||||||
|
int Connect(string h, string p);
|
||||||
|
int Connect(string hostport, int defaultport);
|
||||||
|
long int ReadPop (char *buffer, long int pktlen, long int bufferlen);
|
||||||
|
long int ReadTimeout(char *buffer, long int len, int timeout);
|
||||||
|
long int Read(char *buffer, long int len);
|
||||||
|
long int Write(char *buffer, long int len);
|
||||||
|
void Close();
|
||||||
|
int IsConnected();
|
||||||
|
int IsData(int timeout); // timeout in ms;
|
||||||
|
int IsListen() { return islisten; };
|
||||||
|
|
||||||
|
int Listen(int port);
|
||||||
|
TCP* Accept();
|
||||||
|
|
||||||
|
SOCKET GetSocket() { return sock; };
|
||||||
|
void SetSocket(SOCKET s, struct sockaddr_storage *saddr, socklen_t saddrlen);
|
||||||
|
|
||||||
|
const string GetRemoteAddr();
|
||||||
|
const string GetLocalAddr();
|
||||||
|
|
||||||
|
const string WebGetURLHost (string url);
|
||||||
|
const string WebGetURLPort (string url);
|
||||||
|
const string WebGetURLFile (string url);
|
||||||
|
int WebGetFile (string url, char *buffer, int maxsize);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,289 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Generated with glade 3.40.0 -->
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk+" version="3.24"/>
|
||||||
|
<object class="GtkWindow" id="testmodbus-client">
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<signal name="destroy" handler="gtk_main_quit" swapped="no"/>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkFrame">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="margin-start">4</property>
|
||||||
|
<property name="margin-end">4</property>
|
||||||
|
<property name="margin-top">4</property>
|
||||||
|
<property name="margin-bottom">4</property>
|
||||||
|
<property name="label-xalign">0</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkAlignment">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="left-padding">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="spacing">4</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="spacing">4</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="spacing">4</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="spacing">4</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Host:</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="cli_host">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="text" translatable="yes">localhost</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Port:</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="cli_port">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="width-chars">6</property>
|
||||||
|
<property name="text" translatable="yes">502</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="spacing">4</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Refresh [ms]:</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="width-chars">4</property>
|
||||||
|
<property name="text" translatable="yes">1000</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="cli_cb_reconnect">
|
||||||
|
<property name="label" translatable="yes">Auto Reconnect</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="receives-default">False</property>
|
||||||
|
<property name="active">True</property>
|
||||||
|
<property name="draw-indicator">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="cli_cb_readonly">
|
||||||
|
<property name="label" translatable="yes">Read Only</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="receives-default">False</property>
|
||||||
|
<property name="active">True</property>
|
||||||
|
<property name="draw-indicator">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="spacing">3</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="cli_btnConnect">
|
||||||
|
<property name="label">gtk-connect</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="receives-default">True</property>
|
||||||
|
<property name="use-stock">True</property>
|
||||||
|
<property name="always-show-image">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="cli_btnClose">
|
||||||
|
<property name="label">gtk-disconnect</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="sensitive">False</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="receives-default">True</property>
|
||||||
|
<property name="use-stock">True</property>
|
||||||
|
<property name="always-show-image">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="pack-type">end</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="label" translatable="yes">last error | status</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="label">
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Destination Host</property>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="weight" value="bold"/>
|
||||||
|
<attribute name="scale" value="1"/>
|
||||||
|
</attributes>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</interface>
|
Loading…
Reference in new issue