Compare commits

...

47 Commits

Author SHA1 Message Date
d795dd76a6 bugfix for older compilers: have all declarations before instructions 2020-11-16 17:58:01 +01:00
Andrew Johnson
45924d28e0 Add -v (verbose) flag to softIoc
Only display the startup steps taken if -v was given.
Show each step *before* running it, so error messages follow it.
2020-11-16 17:44:51 +01:00
Andrew Johnson
b1d0a0d036 Build: Do clean before uninstall actions (if requested) 2020-11-16 17:44:21 +01:00
Andrew Johnson
45e9cf9a94 Warn about NULL dbevEventUserFreeList 2020-11-16 17:44:01 +01:00
Andrew Johnson
a8dcff2f0d Merge fix-wrong-order-phas fixes from 3.15 branch 2020-11-16 17:41:08 +01:00
53a7d25923 allow constant links with numeric 1 element arrays like [42] 2020-11-16 17:34:20 +01:00
Ralph Lange
c701e7e98e Redo d3d40689 that was lost in upmerging 2020-11-16 17:33:25 +01:00
Michael Davidsaver
bf8e097756 compat IPPORT_USERRESERVED
musl libc doesn't define IPPORT_USERRESERVED
2020-11-16 17:32:29 +01:00
Andrew Johnson
837a2bbdde const init a char array from a string value
Conflicts:
	documentation/RELEASE_NOTES.md
2020-11-16 17:31:08 +01:00
Andrew Johnson
6fb361a965 Fix Cygwin TCP_NODELAY issue from Paul Chu & Freddie
Conflicts:
	documentation/RELEASE_NOTES.md
2020-11-16 17:27:56 +01:00
1db2cba81d Merge commit '10d472202dc2bf1fa5c569d2a14d460e95030564' into PSI-7.0
This is before PVA is modified
2020-11-16 17:06:22 +01:00
ce43a67cbd re-add removed .ci submodule 2020-11-13 10:07:34 +01:00
7ac8f056ed added missing header for close() in VxWorks 6.3 2020-11-12 11:21:26 +01:00
d157e96aac remove compiler warning 2020-11-12 10:59:54 +01:00
1d1e3e9527 calc backward compatibility: allow incomplete conditional 2020-11-12 10:54:11 +01:00
Andrew Johnson
10d472202d Fix some ca/perl builds
Use the pre-expanded Perl configuration variables.
Conda builds of Perl need these (and a fix to the Perl
config files, see https://github.com/conda/conda/issues/8425
for details).
2020-07-21 15:17:37 -05:00
Andrew Johnson
f99bb637b9 ca: Minor cleanups in capr.pl 2020-07-20 18:22:37 -05:00
Andrew Johnson
c55a95fc98 ca: Support DBF_INT64 and DBF_UINT64 in capr.pl 2020-07-20 18:21:46 -05:00
Andrew Johnson
7d9746003b ca: Fix capr.pl to handle missing fields properly
When using an EPICS 7 softIoc.dbd file with a PV from an older version
of Base which didn't have all the fields, our attempts to read those
fields will time out, but the internal logic was buggy. Don't try to
print the values of timed out fields at all. The user will still see a
warning about connection timeouts at the top.
2020-07-20 18:20:45 -05:00
Ralph Lange
7d2e352f6a Merge changes from 3.15 branch into 7.0
- merged 3.15 branch up to bf7a1605

# Conflicts:
#	modules/database/src/ioc/db/dbChannel.c
2020-07-15 11:46:45 +02:00
Andrew Johnson
5c03f8ba79 Simplify epicsMessageQueueTest using joinable threads
Fixes issues with thread shutdown
2020-07-02 16:17:04 -05:00
Andrew Johnson
1eeac6da2f Switch RTEMS to the default osdMessageQueue 2020-07-02 16:14:08 -05:00
Michael Davidsaver
d4781bca28 Merge branch 'recnames' into 7.0
* recnames:
  validate alias names as well
  yet more record name validation
  Further record name validation
  popFirstTemp() may return NULL
  fix crash on bad record name
  Extend record name validation
2020-06-30 19:54:43 -07:00
Michael Davidsaver
32ff3b2ed9 update ci-scripts 3.0 2020-06-29 20:08:13 -07:00
Michael Davidsaver
25681eca4c ci: set EPICS_TEST_IMPRECISE_TIMING 2020-06-29 20:07:06 -07:00
Michael Davidsaver
dcee015f71 validate alias names as well 2020-06-29 14:44:04 -07:00
Michael Davidsaver
fddd65ccb1 yet more record name validation 2020-06-29 11:33:21 -07:00
Michael Davidsaver
7f9fefc2a4 Further record name validation 2020-06-26 13:22:11 -07:00
Ralph Lange
bf7a1605c6 Name generated junitfiles '<testname>-results.xml'
- following an idea by Freddie Akeroyd,
  to allow better distinction from other xml files
2020-06-23 13:47:33 +02:00
Ralph Lange
0fbfc74182 Fix missing deletion in 97b29129 from 'fix/misc'
- fixes 97b29129 that was replacing two assert() statements
  without removing the original (offending) lines
2020-06-23 11:23:57 +02:00
Michael Davidsaver
b34aa594c8 popFirstTemp() may return NULL
This indicates an earlier error, which should already
been printed.
2020-06-22 12:09:26 -07:00
Michael Davidsaver
3124d972bf fix crash on bad record name 2020-06-22 12:09:26 -07:00
Michael Davidsaver
49889d8549 Extend record name validation
Begin enforcing earlier check (and tab).
Add new warning for record names beginning
with numeric or '{'.
2020-06-22 12:09:26 -07:00
Michael Davidsaver
a4bdee82c3 travis fixup networking 2020-06-20 23:11:12 -07:00
Michael Davidsaver
4160610885 libCom: test osdSockAddrReuse
Ensure that epicsSocketEnableAddressReuseDuringTimeWaitState()
and epicsSocketEnableAddressUseForDatagramFanout()
have the desired effects.
2020-06-20 12:01:40 -07:00
Ralph Lange
b248023eb2 Merge Ralph's 'fix/misc' branch into 3.15
(closes #77)
2020-06-10 18:39:22 +02:00
Ralph Lange
92374b2be2 libcom/osi: fix potential leak in vxWorks/osdThread.c
(found by sonar/cppcheck)
2020-06-10 14:26:40 +02:00
Ralph Lange
579fc9d0c7 libcom/osi: fix potential leak in default/osdThreadHooks.c
(found by sonar/cppcheck)
2020-06-10 14:26:40 +02:00
Ralph Lange
cd47bbf99b libcom/osi: fix debug printf() in default/osdNetIntf.c
(found by sonar/cppcheck)
2020-06-10 14:26:40 +02:00
Ralph Lange
d3d40689c8 libcom/osi: fix dangerous usage of strncat (WIN32)
(found by sonar/cppcheck)
2020-06-10 14:26:40 +02:00
Ralph Lange
d5eb055bb7 libcom/flex: fix sscanf() argument types
(code smell found by sonar/cppcheck)
2020-06-10 14:26:40 +02:00
Ralph Lange
97b29129af libcom/test: don't modify operand in assert() statement
(code smell found by sonar/cppcheck)
2020-06-10 14:26:40 +02:00
Ralph Lange
801710b8c7 db: fix possible null pointer dereference
(found by sonar/cppcheck)
2020-06-10 14:26:40 +02:00
Ralph Lange
30f5c3b301 db: fix incomplete initialization in dbChannelOpen()
(found by sonar/cppcheck)
2020-06-10 14:26:40 +02:00
Ralph Lange
69d4c238e7 ca/tools: free() all allocated buffers
(found by sonar/cppcheck)
2020-06-09 15:52:14 +02:00
Ralph Lange
7d1ff1411f ca/tools: fix type errors in option parsing
(found by sonar/cppcheck)
2020-06-09 15:51:35 +02:00
Ralph Lange
f0e143b907 ca/client: fix possible null pointer dereference
(found by sonar/cppcheck)
2020-06-09 15:48:33 +02:00
35 changed files with 595 additions and 477 deletions

View File

@@ -37,6 +37,8 @@ skip_commits:
# build matrix configuration #
#---------------------------------#
image: Visual Studio 2015
# Build Configurations: dll/static, regular/debug
configuration:
- dynamic
@@ -49,6 +51,7 @@ environment:
# common / default variables for all jobs
SETUP_PATH: .ci-local:.ci
BASE: SELF
EPICS_TEST_IMPRECISE_TIMING: YES
matrix:
- CMP: vs2019
@@ -59,7 +62,7 @@ environment:
- CMP: vs2013
- CMP: vs2012
- CMP: vs2010
- CMP: mingw
- CMP: gcc
# Platform: processor architecture
platform:
@@ -89,17 +92,17 @@ matrix:
install:
- cmd: git submodule update --init --recursive
- cmd: python .ci/appveyor/do.py prepare
- cmd: python .ci/cue.py prepare
build_script:
- cmd: python .ci/appveyor/do.py build
- cmd: python .ci/cue.py build
test_script:
- cmd: python .ci/appveyor/do.py test
- cmd: python .ci/cue.py test
on_finish:
- ps: Get-ChildItem *.tap -Recurse -Force | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
- cmd: python .ci/appveyor/do.py build test-results -s
- cmd: python .ci/cue.py build test-results -s
#---------------------------------#
# debugging #

1
.ci Submodule

Submodule .ci added at 87942a7c29

19
.ci-local/travis-fixup.sh Executable file
View File

@@ -0,0 +1,19 @@
#!/bin/sh
set -e -u -x
env|grep TRAVIS
[ "$TRAVIS_OS_NAME" = "linux" ] || exit 0
# Ensure there is an interface with a (correct) broadcast address
# eg. 'trusty' VMs have interface broadcast address mis-configured
# (why oh why do people insist on setting this explicitly?)
sudo ip tuntap add dev tap42 mode tap
sudo ip addr add 192.168.240.1/24 broadcast + dev tap42
sudo ip link set dev tap42 up
# note that this device will be UP but not RUNNING
# so java will see it as not UP since java confuses UP and RUNNING

View File

@@ -13,6 +13,7 @@ env:
global:
- SETUP_PATH=.ci-local:.ci
- BASE=SELF
- EPICS_TEST_IMPRECISE_TIMING=YES
addons:
apt:
@@ -35,10 +36,13 @@ addons:
update: true
install:
- ./.ci/travis/prepare.sh
- ./.ci-local/travis-fixup.sh
- python .ci/cue.py prepare
script:
- ./.ci/travis/build.sh
- python .ci/cue.py build
- python .ci/cue.py test
- python .ci/cue.py test-results
# Define build jobs
@@ -51,7 +55,7 @@ jobs:
- dist: xenial
- dist: bionic
env: STATIC=YES EXTRA="CMD_CXXFLAGS=-std=c++11"
env: BCFG=static EXTRA="CMD_CXXFLAGS=-std=c++11"
- dist: trusty
env: EXTRA="CMD_CXXFLAGS=-std=c++11"
@@ -63,15 +67,13 @@ jobs:
- dist: trusty
compiler: clang
env: STATIC=YES
env: BCFG=static
# Cross-compilations to Windows using MinGW and WINE
- env: WINE=32 TEST=NO STATIC=YES
compiler: mingw
- env: WINE=32 TEST=NO BCFG=static
- env: WINE=32 TEST=NO STATIC=NO
compiler: mingw
- env: WINE=32 TEST=NO
# Cross-compilation to RTEMS

View File

@@ -133,7 +133,7 @@ ifneq (,$(filter $(T_A), $(EPICS_HOST_ARCH) $(CROSS_COMPILER_RUNTEST_ARCHS)))
RUNTESTS_ENABLED = YES
TESTSCRIPTS.t = $(filter %.t, $(TESTSCRIPTS))
TAPFILES.t += $(TESTSCRIPTS.t:.t=.tap)
JUNITFILES.t += $(TESTSCRIPTS.t:.t=.xml)
JUNITFILES.t += $(TESTSCRIPTS.t:.t=-results.xml)
TAPFILES += $(TAPFILES.t)
JUNITFILES += $(JUNITFILES.t)
endif
@@ -403,7 +403,7 @@ ifdef RUNTESTS_ENABLED
$(PERL) $< -tap > $@
endif
$(JUNITFILES.t): %.xml: %.tap
$(JUNITFILES.t): %-results.xml: %.tap
$(TAPTOJUNIT) --puretap --output $@ --input $< $*
# If there's a perl test script (.plt) available, use it

View File

@@ -33,7 +33,7 @@ UNINSTALL_DIRS += $(INSTALL_INCLUDE) $(INSTALL_TEMPLATES) $(DIRECTORY_TARGETS)
ifneq ($(INSTALL_LOCATION),$(TOP))
UNINSTALL_DIRS += $(INSTALL_CONFIG)
endif
uninstallDirs:
uninstallDirs: | clean
$(RMDIR) $(UNINSTALL_DIRS)
# Remove the bin and lib directories if they have no sub-directories
@@ -41,12 +41,12 @@ uninstallDirs:
EMPTY_INSTALL_DIRS = \
$(if $(wildcard $(INSTALL_LOCATION_BIN)/*),,$(INSTALL_LOCATION_BIN)) \
$(if $(wildcard $(INSTALL_LOCATION_LIB)/*),,$(INSTALL_LOCATION_LIB))
uninstall: archuninstall uninstallDirs
uninstall: archuninstall uninstallDirs | clean
$(RMDIR) $(EMPTY_INSTALL_DIRS)
archuninstall: $(addprefix uninstall$(DIVIDER),$(BUILD_ARCHS))
uninstall$(DIVIDER)%:
uninstall$(DIVIDER)%: | clean
$(RMDIR) $(addsuffix /$(subst uninstall$(DIVIDER),,$@), \
$(INSTALL_LOCATION_BIN) $(INSTALL_LOCATION_LIB))

View File

@@ -1329,6 +1329,15 @@ header and removed the need for dbScan.c to reach into the internals of its
# Changes incorporated from the 3.15 branch
## Changes made on the 3.15 branch since 3.15.8
### Change to the `junitfiles` self-test build target
The names of the generated junit xml test output files have been changed
from `<testname>.xml` to `<testname>-results.xml`, to allow better
distinction from other xml files. (I.e., for easy wildcard matching.)
## Changes made between 3.15.7 and 3.15.8
### Bug fixes
@@ -1352,7 +1361,6 @@ The following launchpad bugs have fixes included in this release:
- [lp: 1868486](https://bugs.launchpad.net/epics-base/+bug/1868486),
epicsMessageQueue lost messages
### Improvements to the self-test build targets
This release contains changes that make it possible to integrate another test
@@ -1368,7 +1376,7 @@ results; previously the `-k` flag to make was needed and even that didn't always
work.
Continuous Integration systems are recommended to run `make tapfiles` (or if
they can read junittest output instead of TAP `make junitests`) followed by
they can read junittest output instead of TAP `make junitfiles`) followed by
`make -s test-results` to display the results of the tests. If multiple CPUs are
available the `-j` flag can be used to run tests in parallel, giving the maximum
jobs that should be allowed so `make -j4 tapfiles` for a system with 4 CPUs say.
@@ -1616,8 +1624,8 @@ cases. This fixes
Some documentation has been added to the `dbdToHtml.pl` script
explaining how Perl POD (Plain Old Documentation) markup can be added to
`.dbd` files to generate HTML documentation for the record types. To see
these instructions, run `perl bin/<host>/dbdToHtml.pl -H`
or `perldoc bin/<host>/dbdToHtml.pl`.
these instructions, run `perl bin/<host>/dbdToHtml.pl -H`
or `perldoc bin/<host>/dbdToHtml.pl`.
### Fix problem with numeric soft events

View File

@@ -603,7 +603,7 @@ void epicsStdCall ca_signal_formated ( long ca_status, const char *pfilenm,
}
else {
fprintf ( stderr, "CA exception in thread w/o CA ctx: status=%s file=%s line=%d: \n",
ca_message ( ca_status ), pfilenm, lineno );
ca_message ( ca_status ), pfilenm ? pfilenm : "<null>", lineno );
if ( pFormat ) {
vfprintf ( stderr, pFormat, theArgs );
}

View File

@@ -13,11 +13,11 @@ ifdef T_A
PERL_ARCHNAME = $(shell $(PERL) ../perlConfig.pl archname)
PERL_ARCHPATH := $(PERL_VERSION)/$(PERL_ARCHNAME)
PERL_ARCHLIB := $(shell $(PERL) ../perlConfig.pl archlib)
PERL_ARCHLIB := $(shell $(PERL) ../perlConfig.pl archlibexp)
PERL_h = $(PERL_ARCHLIB)/CORE/perl.h
EXTUTILS := $(shell $(PERL) ../perlConfig.pl privlib)/ExtUtils
PERLBIN := $(shell $(PERL) ../perlConfig.pl bin)
EXTUTILS := $(shell $(PERL) ../perlConfig.pl privlibexp)/ExtUtils
PERLBIN := $(shell $(PERL) ../perlConfig.pl binexp)
XSUBPP := $(firstword $(wildcard $(PERLBIN)/xsubpp $(EXTUTILS)/xsubpp))
# Special settings for Darwin:

View File

@@ -35,9 +35,11 @@ my %fieldType = (
DBF_DOUBLE => 'DBF_FLOAT',
DBF_FLOAT => 'DBF_FLOAT',
DBF_LONG => 'DBF_LONG',
DBF_INT64 => 'DBF_FLOAT',
DBF_SHORT => 'DBF_LONG',
DBF_ULONG => 'DBF_LONG',
DBF_USHORT => 'DBF_LONG',
DBF_UINT64 => 'DBF_FLOAT',
DBF_DEVICE => 'DBF_STRING',
DBF_ENUM => 'DBF_STRING',
DBF_FWDLINK => 'DBF_STRING',
@@ -86,7 +88,7 @@ if (@ARGV) {
printRecord($_, @ARGV);
} else {
if (m/^ \s* ([]+:;<>0-9A-Za-z[-]+) (?:\. \w+)? \s* , \s* (\d+) \s* $/x) {
# Recognizes ",n" as an interest leve, drops any ".FIELD" part
# Recognizes ",n" as an interest level, drops any ".FIELD" part
printRecord($1, $2);
} else {
# Drop any ".FIELD" part
@@ -235,8 +237,9 @@ sub printField {
$outStr = sprintf('%-5s %.8f', $field, $fieldData);
} elsif ( $dataType eq 'DBF_CHAR' ) {
$outStr = sprintf('%-5s %d', $field, ord($fieldData));
}else {
# DBF_LONG, DBF_SHORT, DBF_UCHAR, DBF_ULONG, DBF_USHORT
} else {
# DBF_INT64, DBF_LONG, DBF_SHORT,
# DBF_UINT64, DBF_ULONG, DBF_USHORT, DBF_UCHAR,
$outStr = sprintf('%-5s %d', $field, $fieldData);
}
@@ -270,17 +273,18 @@ sub printField {
sub caget {
my @chans = map { CA->new($_); } @_;
#clear results;
#clear any previous results;
%callback_data = ();
%timed_out = ();
eval { CA->pend_io($opt_w); };
if ($@) {
if ($@ =~ m/^ECA_TIMEOUT/) {
my $err = (@chans > 1) ? 'some PV(s)' : '"' . $chans[0]->name . '"';
my $name = $chans[0]->name;
my $err = (@chans > 1) ? 'some fields' : "'$name'";
print "Channel connect timed out: $err not found.\n";
foreach my $chan (@chans) {
$timed_out{$chan->name} = $chan->is_connected;
$timed_out{$chan->name} = !$chan->is_connected;
}
@chans = grep { $_->is_connected } @chans;
} else {
@@ -289,14 +293,12 @@ sub caget {
}
map {
my $type;
$type = $_->field_type;
$_->get_callback(\&caget_callback, $type);
$_->get_callback(\&caget_callback, $_->field_type);
} @chans;
my $fields_read = @chans;
$callback_incomplete = @chans;
CA->pend_event(0.1) while $callback_incomplete;
my $fields_read = $callback_incomplete = @chans;
CA->pend_event(0.1)
while $callback_incomplete;
return $fields_read;
}
@@ -325,9 +327,10 @@ sub printRecord {
my @bases = (); #bases, from parser
foreach my $field (sort keys %{$record{$recType}}) {
# Skip DTYP field if this rec type doesn't have device support defined
if ($field eq 'DTYP' && !(exists($device{$recType}))) { next; }
next if $field eq 'DTYP' && !exists($device{$recType});
my ($fType, $fInterest, $base) = getFieldParams($recType, $field);
# FIXME: Support waveform.VAL fields etc.
unless( $fType eq 'DBF_NOACCESS' ) {
if ($interest >= $fInterest ) {
my $fToGet = "$name.$field";
@@ -346,15 +349,10 @@ sub printRecord {
my $field = $fields_pr[$i];
my $fToGet = $readlist[$i];
my ($fType, $data, $base);
if ($timed_out{$fToGet}) {
$fType = $fieldType{DBF_STRING};
$data = '<timeout>';
}
else {
$fType = $ftypes[$i];
$base = $bases[$i];
$data = $callback_data{$fToGet};
}
next if $timed_out{$fToGet};
$fType = $ftypes[$i];
$base = $bases[$i];
$data = $callback_data{$fToGet};
$col = printField($field, $data, $fType, $base, $col);
}
print("\n"); # Final newline
@@ -387,8 +385,8 @@ sub printRecordList {
if (exists($record{$type}) ) {
print("Record type - $type\n");
foreach my $fkey (sort keys %{$record{$type}}) {
printf('%-4s', $fkey);
printf(" interest = $record{$type}{$fkey}[$iIdx]");
printf('%-8s', $fkey);
printf(" interest = $record{$type}{$fkey}[$iIdx]");
printf(" type = %-12s ",$record{$type}{$fkey}[$tIdx]);
print (" base = $record{$type}{$fkey}[$bIdx]\n");
}

View File

@@ -157,7 +157,7 @@ int main (int argc, char *argv[])
}
break;
case 's': /* ca_client_status interest level */
if (sscanf(optarg,"%du", &statLevel) != 1)
if (sscanf(optarg,"%u", &statLevel) != 1)
{
fprintf(stderr, "'%s' is not a valid interest level "
"- ignored. ('cainfo -h' for help.)\n", optarg);

View File

@@ -258,7 +258,7 @@ int main (int argc, char *argv[])
}
break;
case '#': /* Array count */
if (sscanf(optarg,"%ld", &reqElems) != 1)
if (sscanf(optarg,"%lu", &reqElems) != 1)
{
fprintf(stderr, "'%s' is not a valid array element count "
"- ignored. ('camonitor -h' for help.)\n", optarg);

View File

@@ -437,6 +437,7 @@ int main (int argc, char *argv[])
dbuf = calloc (count, sizeof(double));
if(!sbuf || !dbuf) {
fprintf(stderr, "Memory allocation failed\n");
free(sbuf); free(dbuf);
return 1;
}
@@ -450,6 +451,7 @@ int main (int argc, char *argv[])
result = ca_pend_io(caTimeout);
if (result == ECA_TIMEOUT) {
fprintf(stderr, "Read operation timed out: ENUM data was not read.\n");
free(sbuf); free(dbuf);
return 1;
}
@@ -460,6 +462,7 @@ int main (int argc, char *argv[])
if (*(argv+optind+i) == pend) { /* Conversion didn't work */
fprintf(stderr, "Enum index value '%s' is not a number.\n",
*(argv+optind+i));
free(sbuf); free(dbuf);
return 1;
}
if (dbuf[i] >= bufGrEnum.no_str) {
@@ -486,6 +489,7 @@ int main (int argc, char *argv[])
dbuf[i] = epicsStrtod(sbuf[i], &pend);
if (sbuf[i] == pend || enumAsString) {
fprintf(stderr, "Enum string value '%s' invalid.\n", sbuf[i]);
free(sbuf); free(dbuf);
return 1;
}
if (dbuf[i] >= bufGrEnum.no_str) {
@@ -503,6 +507,7 @@ int main (int argc, char *argv[])
ebuf = calloc(len, sizeof(char));
if(!ebuf) {
fprintf(stderr, "Memory allocation failed\n");
free(sbuf); free(dbuf); free(ebuf);
return 1;
}
count = epicsStrnRawFromEscaped(ebuf, len, cbuf, len-1) + 1;
@@ -537,12 +542,14 @@ int main (int argc, char *argv[])
}
if (result != ECA_NORMAL) {
fprintf(stderr, "Error from put operation: %s\n", ca_message(result));
free(sbuf); free(dbuf); free(ebuf);
return 1;
}
result = ca_pend_io(caTimeout);
if (result == ECA_TIMEOUT) {
fprintf(stderr, "Write operation timed out: Data was not written.\n");
free(sbuf); free(dbuf); free(ebuf);
return 1;
}
if (request == callback) { /* Also wait for callbacks */
@@ -556,6 +563,7 @@ int main (int argc, char *argv[])
if (result != ECA_NORMAL) {
fprintf(stderr, "Error occured writing data: %s\n", ca_message(result));
free(sbuf); free(dbuf); free(ebuf);
return 1;
}
@@ -567,6 +575,7 @@ int main (int argc, char *argv[])
/* Shut down Channel Access */
ca_context_destroy();
free(sbuf); free(dbuf); free(ebuf);
return result;
}

View File

@@ -603,6 +603,10 @@ long dbChannelOpen(dbChannel *chan)
probe.no_elements = dbChannelElements(chan);
probe.field_size = dbChannelFieldSize(chan);
probe.sevr = NO_ALARM;
probe.stat = NO_ALARM;
probe.time.secPastEpoch = 0;
probe.time.nsec = 0;
p = probe;
/*

View File

@@ -1047,7 +1047,11 @@ static void event_task (void *pParm)
epicsEventDestroy(evUser->pflush_sem);
epicsMutexDestroy(evUser->lock);
freeListFree(dbevEventUserFreeList, evUser);
if (dbevEventUserFreeList)
freeListFree(dbevEventUserFreeList, evUser);
else
fprintf(stderr, "%s exiting but dbevEventUserFreeList already NULL\n",
__FUNCTION__);
taskwdRemove(epicsThreadGetIdSelf());

View File

@@ -1075,13 +1075,10 @@ static void addToList(struct dbCommon *precord, scan_list *psl)
pse->pscan_list = psl;
ptemp = (scan_element *)ellLast(&psl->list);
while (ptemp) {
if (ptemp->precord->phas <= precord->phas) {
ellInsert(&psl->list, &ptemp->node, &pse->node);
break;
}
if (ptemp->precord->phas <= precord->phas) break;
ptemp = (scan_element *)ellPrevious(&ptemp->node);
}
if (ptemp == NULL) ellAdd(&psl->list, (void *)pse);
ellInsert(&psl->list, (ptemp ? &ptemp->node : NULL), &pse->node);
psl->modified = TRUE;
epicsMutexUnlock(psl->lock);
}
@@ -1107,7 +1104,7 @@ static void deleteFromList(struct dbCommon *precord, scan_list *psl)
return;
}
pse->pscan_list = NULL;
ellDelete(&psl->list, (void *)pse);
ellDelete(&psl->list, &pse->node);
psl->modified = TRUE;
epicsMutexUnlock(psl->lock);
}

View File

@@ -69,7 +69,7 @@ void recGblDbaddrError(long status, const struct dbAddr *paddr,
errPrintf(status,0,0,
"PV: %s.%s "
"error detected in routine: %s\n",
(paddr ? precord->name : "Unknown"),
(precord ? precord->name : "Unknown"),
(pdbFldDes ? pdbFldDes->name : ""),
(pmessage ? pmessage : "Unknown"));
return;
@@ -106,7 +106,7 @@ void recGblRecSupError(long status, const struct dbAddr *paddr,
" %s\n",
(psupport_name ? psupport_name : "Unknown"),
(pdbRecordType ? pdbRecordType->name : "Unknown"),
(paddr ? precord->name : "Unknown"),
(precord ? precord->name : "Unknown"),
(pdbFldDes ? pdbFldDes->name : ""),
(pmessage ? pmessage : ""));
return;

View File

@@ -136,12 +136,14 @@ static void allocTemp(void *pvoid)
static void *popFirstTemp(void)
{
tempListNode *ptempListNode;
void *ptemp;
void *ptemp = NULL;
ptempListNode = (tempListNode *)ellFirst(&tempList);
ptemp = ptempListNode->item;
ellDelete(&tempList,(ELLNODE *)ptempListNode);
freeListFree(freeListPvt,ptempListNode);
if(ptempListNode) {
ptemp = ptempListNode->item;
ellDelete(&tempList,(ELLNODE *)ptempListNode);
freeListFree(freeListPvt,ptempListNode);
}
return(ptemp);
}
@@ -477,12 +479,16 @@ static void dbMenuBody(void)
return;
}
pnewMenu = (dbMenu *)popFirstTemp();
if(!pnewMenu)
return;
pnewMenu->nChoice = nChoice = ellCount(&tempList)/2;
pnewMenu->papChoiceName = dbCalloc(pnewMenu->nChoice,sizeof(char *));
pnewMenu->papChoiceValue = dbCalloc(pnewMenu->nChoice,sizeof(char *));
for(i=0; i<nChoice; i++) {
pnewMenu->papChoiceName[i] = (char *)popFirstTemp();
pnewMenu->papChoiceValue[i] = (char *)popFirstTemp();
if(!pnewMenu->papChoiceName[i] || !pnewMenu->papChoiceValue[i])
return;
}
if(ellCount(&tempList)) yyerrorAbort("dbMenuBody: tempList not empty");
/* Add menu in sorted order */
@@ -703,6 +709,8 @@ static void dbRecordtypeBody(void)
return;
}
pdbRecordType= (dbRecordType *)popFirstTemp();
if(!pdbRecordType)
return;
pdbRecordType->no_fields = no_fields = ellCount(&tempList);
pdbRecordType->papFldDes = dbCalloc(no_fields,sizeof(dbFldDes *));
pdbRecordType->papsortFldName = dbCalloc(no_fields,sizeof(char *));
@@ -710,6 +718,8 @@ static void dbRecordtypeBody(void)
no_prompt = no_links = 0;
for(i=0; i<no_fields; i++) {
pdbFldDes = (dbFldDes *)popFirstTemp();
if(!pdbFldDes)
return;
pdbFldDes->pdbRecordType = pdbRecordType;
pdbFldDes->indRecordType = i;
pdbRecordType->papFldDes[i] = pdbFldDes;
@@ -974,6 +984,8 @@ static void dbBreakBody(void)
return;
}
pnewbrkTable = (brkTable *)popFirstTemp();
if(!pnewbrkTable)
return;
number = ellCount(&tempList);
if (number % 2) {
yyerrorAbort("breaktable: Raw value missing");
@@ -990,10 +1002,14 @@ static void dbBreakBody(void)
char *str;
str = (char *)popFirstTemp();
if(!str)
return;
(void) epicsScanDouble(str, &paBrkInt[i].raw);
free(str);
str = (char *)popFirstTemp();
if(!str)
return;
(void) epicsScanDouble(str, &paBrkInt[i].eng);
free(str);
}
@@ -1034,22 +1050,49 @@ static void dbBreakBody(void)
}
pgphentry->userPvt = pnewbrkTable;
}
static
int dbRecordNameValidate(const char *name)
{
size_t i=0u;
const char *pos = name;
if (!*name) {
yyerrorAbort("Error: Record/Alias name can't be empty");
return 1;
}
for(; *pos; i++, pos++) {
char c = *pos;
if(i==0) {
/* first character restrictions */
if(c=='-' || c=='+' || c=='[' || c=='{') {
errlogPrintf("Warning: Record/Alias name '%s' should not begin with '%c'\n", name, c);
}
}
/* any character restrictions */
if(c < ' ') {
errlogPrintf("Warning: Record/Alias name '%s' should not contain non-printable 0x%02u\n",
name, (unsigned)c);
} else if(c==' ' || c=='\t' || c=='"' || c=='\'' || c=='.' || c=='$') {
epicsPrintf("Error: Bad character '%c' in Record/Alias name \"%s\"\n",
c, name);
yyerrorAbort(NULL);
return 1;
}
}
return 0;
}
static void dbRecordHead(char *recordType, char *name, int visible)
{
char *badch;
DBENTRY *pdbentry;
long status;
if (!*name) {
yyerrorAbort("dbRecordHead: Record name can't be empty");
if(dbRecordNameValidate(name))
return;
}
badch = strpbrk(name, " \"'.$");
if (badch) {
epicsPrintf("Bad character '%c' in record name \"%s\"\n",
*badch, name);
}
pdbentry = dbAllocEntry(pdbbase);
if (ellCount(&tempList))
@@ -1180,10 +1223,9 @@ static void dbRecordAlias(char *name)
tempListNode *ptempListNode;
long status;
if (!*name) {
yyerrorAbort("dbRecordAlias: Alias name can't be empty");
if(dbRecordNameValidate(name))
return;
}
if (duplicate) return;
ptempListNode = (tempListNode *)ellFirst(&tempList);
pdbentry = ptempListNode->item;
@@ -1201,10 +1243,9 @@ static void dbAlias(char *name, char *alias)
DBENTRY dbEntry;
DBENTRY *pdbEntry = &dbEntry;
if (!*alias) {
yyerrorAbort("dbAlias: Alias name can't be empty");
if(dbRecordNameValidate(alias))
return;
}
dbInitEntry(pdbbase, pdbEntry);
if (dbFindRecord(pdbEntry, name)) {
epicsPrintf("Alias \"%s\" refers to unknown record \"%s\"\n",

View File

@@ -2330,8 +2330,7 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
}
/* Link may be an array constant */
if (pstr[0] == '[' && pstr[len-1] == ']' &&
(strchr(pstr, ',') || strchr(pstr, '"'))) {
if (pstr[0] == '[' && pstr[len-1] == ']') {
pinfo->ltype = CONSTANT;
return 0;
}

View File

@@ -488,8 +488,17 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
case sc40:
if (clink->jlink.debug)
printf(" sc40 '%s'\n", clink->value.scalar_string);
status = dbFastPutConvertRoutine[DBF_STRING][dbrType]
(clink->value.scalar_string, pbuffer, NULL);
if (dbrType != DBF_CHAR) {
status = dbFastPutConvertRoutine[DBF_STRING][dbrType]
(clink->value.scalar_string, pbuffer, NULL);
}
else {
/* Long string conversion */
strncpy(pbuffer, clink->value.scalar_string, *pnReq);
((char *)pbuffer)[*pnReq] = 0;
nElems = strlen(pbuffer) + 1;
status = 0;
}
break;
case ai64:

View File

@@ -46,13 +46,15 @@ extern "C" int softIoc_registerRecordDeviceDriver(struct dbBase *pdbbase);
namespace {
bool verbose = false;
static void exitSubroutine(subRecord *precord) {
epicsExitLater((precord->a == 0.0) ? EXIT_SUCCESS : EXIT_FAILURE);
}
void usage(const char *arg0, const std::string& base_dbd) {
std::cout<<"Usage: "<<arg0<<
" [-D softIoc.dbd] [-h] [-S] [-s] [-a ascf]\n"
" [-D softIoc.dbd] [-h] [-S] [-s] [-v] [-a ascf]\n"
"[-m macro=value,macro2=value2] [-d file.db]\n"
"[-x prefix] [st.cmd]\n"
"\n"
@@ -65,6 +67,8 @@ void usage(const char *arg0, const std::string& base_dbd) {
"\n"
" -s Previously caused a shell to be started. Now accepted and ignored.\n"
"\n"
" -v Verbose, display steps taken during startup.\n"
"\n"
" -a <acf> Access Security configuration file. Macro substitution is\n"
" performed.\n"
"\n"
@@ -102,12 +106,14 @@ void lazy_dbd(const std::string& dbd_file) {
if(lazy_dbd_loaded) return;
lazy_dbd_loaded = true;
if (verbose)
std::cout<<"dbLoadDatabase(\""<<dbd_file<<"\")\n";
errIf(dbLoadDatabase(dbd_file.c_str(), NULL, NULL),
std::string("Failed to load DBD file: ")+dbd_file);
std::cout<<"dbLoadDatabase(\""<<dbd_file<<"\")\n";
if (verbose)
std::cout<<"softIoc_registerRecordDeviceDriver(pdbbase)\n";
softIoc_registerRecordDeviceDriver(pdbbase);
std::cout<<"softIoc_registerRecordDeviceDriver(pdbbase)\n";
registryFunctionAdd("exit", (REGISTRYFUNCTION) exitSubroutine);
}
@@ -143,7 +149,7 @@ int main(int argc, char *argv[])
int opt;
while ((opt = getopt(argc, argv, "ha:D:d:m:Ssx:")) != -1) {
while ((opt = getopt(argc, argv, "ha:D:d:m:Ssx:v")) != -1) {
switch (opt) {
case 'h': /* Print usage */
usage(argv[0], dbd_file);
@@ -157,13 +163,15 @@ int main(int argc, char *argv[])
case 'a':
lazy_dbd(dbd_file);
if (!macros.empty()) {
if (verbose)
std::cout<<"asSetSubstitutions(\""<<macros<<"\")\n";
if(asSetSubstitutions(macros.c_str()))
throw std::bad_alloc();
std::cout<<"asSetSubstitutions(\""<<macros<<"\")\n";
}
if (verbose)
std::cout<<"asSetFilename(\""<<optarg<<"\")\n";
if(asSetFilename(optarg))
throw std::bad_alloc();
std::cout<<"asSetFilename(\""<<optarg<<"\")\n";
break;
case 'D':
if(lazy_dbd_loaded) {
@@ -173,12 +181,14 @@ int main(int argc, char *argv[])
break;
case 'd':
lazy_dbd(dbd_file);
if (verbose) {
std::cout<<"dbLoadRecords(\""<<optarg<<"\"";
if(!macros.empty())
std::cout<<", \""<<macros<<"\"";
std::cout<<")\n";
}
errIf(dbLoadRecords(optarg, macros.c_str()),
std::string("Failed to load: ")+optarg);
std::cout<<"dbLoadRecords(\""<<optarg<<"\"";
if(!macros.empty())
std::cout<<", \""<<macros<<"\"";
std::cout<<")\n";
loadedDb = true;
break;
case 'm':
@@ -189,6 +199,9 @@ int main(int argc, char *argv[])
break;
case 's':
break; // historical
case 'v':
verbose = true;
break;
case 'x':
lazy_dbd(dbd_file);
xmacro = "IOC=";
@@ -206,17 +219,20 @@ int main(int argc, char *argv[])
// run script
// ignore any extra positional args (historical)
std::cout<<"# Begin "<<argv[optind]<<"\n";
if (verbose)
std::cout<<"# Begin "<<argv[optind]<<"\n";
errIf(iocsh(argv[optind]),
std::string("Error in ")+argv[optind]);
std::cout<<"# End "<<argv[optind]<<"\n";
if (verbose)
std::cout<<"# End "<<argv[optind]<<"\n";
epicsThreadSleep(0.2);
loadedDb = true; /* Give it the benefit of the doubt... */
}
if (loadedDb) {
std::cout<<"iocInit()\n";
if (verbose)
std::cout<<"iocInit()\n";
iocInit();
epicsThreadSleep(0.2);
}

View File

@@ -216,6 +216,7 @@ LIBCOM_API long
int cond_count = 0;
char * const pdest = pout;
char *pnext;
const char* psrc_orig = psrc;
if (psrc == NULL || *psrc == '\0' ||
pout == NULL || perror == NULL) {
@@ -470,8 +471,12 @@ LIBCOM_API long
*pout = END_EXPRESSION;
if (cond_count != 0) {
fprintf(stderr, "Deprecated CALC \"%s\": %s\n",
psrc_orig, calcErrorStr(CALC_ERR_CONDITIONAL));
/*
*perror = CALC_ERR_CONDITIONAL;
goto bad;
*/
}
if (operand_needed || runtime_depth != 1) {
*perror = CALC_ERR_INCOMPLETE;

View File

@@ -438,7 +438,7 @@ int htoi(unsigned char *str)
{
int result;
(void) sscanf( (char *) str, "%x", &result );
(void) sscanf( (char *) str, "%x", (unsigned *) &result );
return ( result );
}
@@ -653,7 +653,7 @@ int otoi(Char *str)
{
int result;
(void) sscanf( (char *) str, "%o", &result );
(void) sscanf( (char *) str, "%o", (unsigned *) &result );
return ( result );
}

View File

@@ -28,6 +28,9 @@
#include <netdb.h>
#include <unistd.h> /* close() and others */
#ifndef IPPORT_USERRESERVED
#define IPPORT_USERRESERVED 5000
#endif
typedef int SOCKET;
#define INVALID_SOCKET (-1)

View File

@@ -1,250 +0,0 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author W. Eric Norum
* norume@aps.anl.gov
* 630 252 4793
*/
/*
* We want to access information which is
* normally hidden from application programs.
*/
#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ 1
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <rtems.h>
#include <rtems/error.h>
#include "epicsMessageQueue.h"
#include "errlog.h"
LIBCOM_API epicsMessageQueueId epicsStdCall
epicsMessageQueueCreate(unsigned int capacity, unsigned int maximumMessageSize)
{
rtems_status_code sc;
epicsMessageQueueId id = calloc(1, sizeof(*id));
rtems_interrupt_level level;
static char c1 = 'a';
static char c2 = 'a';
static char c3 = 'a';
if(!id)
return NULL;
sc = rtems_message_queue_create (rtems_build_name ('Q', c3, c2, c1),
capacity,
maximumMessageSize,
RTEMS_FIFO|RTEMS_LOCAL,
&id->id);
if (sc != RTEMS_SUCCESSFUL) {
free(id);
errlogPrintf ("Can't create message queue: %s\n", rtems_status_text (sc));
return NULL;
}
id->maxSize = maximumMessageSize;
id->localBuf = NULL;
rtems_interrupt_disable (level);
if (c1 == 'z') {
if (c2 == 'z') {
if (c3 == 'z') {
c3 = 'a';
}
else {
c3++;
}
c2 = 'a';
}
else {
c2++;
}
c1 = 'a';
}
else {
c1++;
}
rtems_interrupt_enable (level);
return id;
}
static rtems_status_code rtems_message_queue_send_timeout(
rtems_id id,
void *buffer,
uint32_t size,
rtems_interval timeout)
{
Message_queue_Control *the_message_queue;
Objects_Locations location;
CORE_message_queue_Status msg_status;
the_message_queue = _Message_queue_Get( id, &location );
switch ( location )
{
case OBJECTS_ERROR:
return RTEMS_INVALID_ID;
case OBJECTS_LOCAL:
msg_status = _CORE_message_queue_Send(
&the_message_queue->message_queue,
buffer,
size,
id,
NULL,
1,
timeout
);
_Thread_Enable_dispatch();
/*
* If we had to block, then this is where the task returns
* after it wakes up. The returned status is correct for
* non-blocking operations but if we blocked, then we need
* to look at the status in our TCB.
*/
if ( msg_status == CORE_MESSAGE_QUEUE_STATUS_UNSATISFIED_WAIT )
msg_status = _Thread_Executing->Wait.return_code;
return _Message_queue_Translate_core_message_queue_return_code( msg_status );
}
return RTEMS_INTERNAL_ERROR; /* unreached - only to remove warnings */
}
LIBCOM_API int epicsStdCall epicsMessageQueueSend(
epicsMessageQueueId id,
void *message,
unsigned int messageSize)
{
if (rtems_message_queue_send_timeout(id->id, message, messageSize, RTEMS_NO_TIMEOUT) == RTEMS_SUCCESSFUL)
return 0;
else
return -1;
}
LIBCOM_API int epicsStdCall epicsMessageQueueSendWithTimeout(
epicsMessageQueueId id,
void *message,
unsigned int messageSize,
double timeout)
{
rtems_interval delay;
extern double rtemsTicksPerSecond_double;
/*
* Convert time to ticks
*/
if (timeout <= 0.0)
return epicsMessageQueueTrySend(id, message, messageSize);
delay = (int)(timeout * rtemsTicksPerSecond_double);
if (delay == 0)
delay++;
if (rtems_message_queue_send_timeout(id->id, message, messageSize, delay) == RTEMS_SUCCESSFUL)
return 0;
else
return -1;
}
static int receiveMessage(
epicsMessageQueueId id,
void *buffer,
uint32_t size,
uint32_t wait,
rtems_interval delay)
{
size_t rsize;
rtems_status_code sc;
if (size < id->maxSize) {
if (id->localBuf == NULL) {
id->localBuf = malloc(id->maxSize);
if (id->localBuf == NULL)
return -1;
}
rsize = receiveMessage(id, id->localBuf, id->maxSize, wait, delay);
if (rsize > size)
return -1;
memcpy(buffer, id->localBuf, rsize);
}
else {
sc = rtems_message_queue_receive(id->id, buffer, &rsize, wait, delay);
if (sc != RTEMS_SUCCESSFUL)
return -1;
}
return rsize;
}
LIBCOM_API int epicsStdCall epicsMessageQueueTryReceive(
epicsMessageQueueId id,
void *message,
unsigned int size)
{
return receiveMessage(id, message, size, RTEMS_NO_WAIT, 0);
}
LIBCOM_API int epicsStdCall epicsMessageQueueReceive(
epicsMessageQueueId id,
void *message,
unsigned int size)
{
return receiveMessage(id, message, size, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
}
LIBCOM_API int epicsStdCall epicsMessageQueueReceiveWithTimeout(
epicsMessageQueueId id,
void *message,
unsigned int size,
double timeout)
{
rtems_interval delay;
uint32_t wait;
extern double rtemsTicksPerSecond_double;
/*
* Convert time to ticks
*/
if (timeout <= 0.0) {
wait = RTEMS_NO_WAIT;
delay = 0;
}
else {
wait = RTEMS_WAIT;
delay = (int)(timeout * rtemsTicksPerSecond_double);
if (delay == 0)
delay++;
}
return receiveMessage(id, message, size, wait, delay);
}
LIBCOM_API int epicsStdCall epicsMessageQueuePending(
epicsMessageQueueId id)
{
uint32_t count;
rtems_status_code sc;
sc = rtems_message_queue_get_number_pending(id->id, &count);
if (sc != RTEMS_SUCCESSFUL) {
errlogPrintf("Message queue %x get number pending failed: %s\n",
(unsigned int)id,
rtems_status_text(sc));
return -1;
}
return count;
}
LIBCOM_API void epicsStdCall epicsMessageQueueShow(
epicsMessageQueueId id,
int level)
{
int pending = epicsMessageQueuePending(id);
if (pending >= 0)
printf ("Message queue %lx -- Pending: %d\n", (unsigned long)id, pending);
}

View File

@@ -1,29 +0,0 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author W. Eric Norum
* norume@aps.anl.gov
* 630 252 4793
*/
/*
* Very thin shims around RTEMS routines
*/
#include <rtems.h>
struct epicsMessageQueueOSD {
rtems_id id;
unsigned int maxSize;
void *localBuf;
};
#define epicsMessageQueueDestroy(q) (rtems_message_queue_delete((q)->id))
#define epicsMessageQueueTrySend(q,m,l) (rtems_message_queue_send((q)->id, (m), (l)) == RTEMS_SUCCESSFUL ? 0 : -1)

View File

@@ -63,10 +63,10 @@ LIBCOM_API int epicsStdCall osiSockAttach()
DWORD titleLength = GetConsoleTitle(title, sizeof(title));
if (titleLength) {
titleLength = strlen (title);
strncat (title, " " EPICS_VERSION_STRING, sizeof(title));
strncat (title, " " EPICS_VERSION_STRING, sizeof(title)-1);
}
else {
strncpy(title, EPICS_VERSION_STRING, sizeof(title));
strncpy(title, EPICS_VERSION_STRING, sizeof(title)-1);
}
title[sizeof(title)-1]= '\0';
SetConsoleTitle(title);

View File

@@ -26,6 +26,9 @@
#include <net/if.h>
#include <netdb.h>
#include <unistd.h> /* close() and others */
#ifndef TCP_NODELAY
# include <netinet/tcp.h>
#endif
typedef int SOCKET;

View File

@@ -211,7 +211,7 @@ LIBCOM_API void epicsStdCall osiSockDiscoverBroadcastAddresses
pNewNode->addr.sa = pIfreqList->ifr_broadaddr;
ifDepenDebugPrintf ( ( "found broadcast addr = %x\n", ntohl ( baddr.ia.sin_addr.s_addr ) ) );
} else {
ifDepenDebugPrintf ( ( "Ignoring broadcast addr = \n", ntohl ( baddr.ia.sin_addr.s_addr ) ) );
ifDepenDebugPrintf ( ( "Ignoring broadcast addr = %x\n", ntohl ( baddr.ia.sin_addr.s_addr ) ) );
free ( pNewNode );
continue;
}

View File

@@ -71,6 +71,7 @@ LIBCOM_API int epicsThreadHookAdd(EPICS_THREAD_HOOK_ROUTINE hook)
return 0;
}
fprintf(stderr, "epicsThreadHookAdd: Locking problem\n");
free(pHook);
return -1;
}

View File

@@ -638,7 +638,7 @@ epicsFindAddr(void *addr, epicsSymbol *sym_p)
if ( nearest.raw && ( (idx = ARR(c,nearest,0,st_name)) < es->strMap->max ) ) {
sym_p->s_nam = strtab + idx;
sym_p->s_val = (char*) ARR(c, nearest, 0, st_value) + es->addr;
sym_p->s_val = (char*)(size_t) ARR(c, nearest, 0, st_value) + es->addr;
}
return 0;

View File

@@ -20,6 +20,7 @@
#include <fcntl.h>
#include <unistd.h>
#include <loadLib.h>
#include <ioLib.h>
#include "dbmf.h"
#include "epicsString.h"

View File

@@ -473,8 +473,9 @@ LIBCOM_API void epicsThreadMap ( EPICS_THREAD_HOOK_ROUTINE func )
while (noTasks == 0) {
noTasks = taskIdListGet(taskIdList, taskIdListSize);
if (noTasks == taskIdListSize) {
taskIdList = realloc(taskIdList, (taskIdListSize+ID_LIST_CHUNK)*sizeof(int));
assert(taskIdList);
int *newlist = realloc(taskIdList, (taskIdListSize+ID_LIST_CHUNK)*sizeof(int));
assert(newlist);
taskIdList = newlist;
taskIdListSize += ID_LIST_CHUNK;
noTasks = 0;
}

View File

@@ -25,12 +25,9 @@
static const char *msg1 = "1234567890This is a very long message.";
static volatile int sendExit = 0;
static volatile int recvExit = 0;
static epicsEventId finished;
static unsigned int mediumStack;
#define SLEEPY_TESTS 500
static int numSent, numReceived;
static epicsEventId complete;
/*
* In Numerical Recipes in C: The Art of Scientific Computing (William H.
@@ -116,7 +113,6 @@ receiver(void *arg)
if (!testOk1(errors == 0))
testDiag("Error count was %d", errors);
testDiag("%s exiting", myName);
epicsEventSignal(finished);
}
extern "C" void
@@ -133,15 +129,18 @@ fastReceiver(void *arg)
}
}
recvExit = 0;
epicsEventSignal(complete);
}
void sleepySender(double delay)
{
epicsThreadOpts opts = {epicsThreadPriorityMedium, epicsThreadStackMedium, 1};
epicsThreadId rxThread;
testDiag("sleepySender: sending every %.3f seconds", delay);
epicsMessageQueue q(4, 20);
epicsThreadCreate("Fast Receiver", epicsThreadPriorityMedium,
mediumStack, fastReceiver, &q);
rxThread = epicsThreadCreateOpt("Fast Receiver", fastReceiver, &q, &opts);
if (!rxThread)
testAbort("Task create failed");
numSent = 0;
for (int i = 0 ; i < SLEEPY_TESTS ; i++) {
@@ -159,7 +158,7 @@ void sleepySender(double delay)
recvExit = 1;
while (q.send((void *)msg1, 4) != 0)
epicsThreadSleep(0.01);
epicsEventMustWait(complete);
epicsThreadMustJoin(rxThread);
}
extern "C" void
@@ -179,11 +178,14 @@ fastSender(void *arg)
}
}
sendExit = 0;
epicsEventSignal(complete);
}
void sleepyReceiver(double delay)
{
epicsThreadOpts opts = {epicsThreadPriorityMedium,
epicsThreadStackMedium, 1};
epicsThreadId txThread;
testDiag("sleepyReceiver: acquiring every %.3f seconds", delay);
epicsMessageQueue q(4, 20);
@@ -192,8 +194,9 @@ void sleepyReceiver(double delay)
q.send((void *)msg1, 4);
}
epicsThreadCreate("Fast Sender", epicsThreadPriorityMedium,
mediumStack, fastSender, &q);
txThread = epicsThreadCreateOpt("Fast Sender", fastSender, &q, &opts);
if (!txThread)
testAbort("Task create failed");
epicsThreadSleep(0.5);
char cbuf[80];
@@ -208,21 +211,15 @@ void sleepyReceiver(double delay)
epicsThreadSleep(delay);
}
#ifdef __rtems__
testTodoBegin("RTEMS failure expected");
#endif
testOk(numSent == SLEEPY_TESTS, "Sent %d (should be %d)",
numSent, SLEEPY_TESTS);
#ifdef __rtems__
testTodoEnd();
#endif
testOk(numReceived == SLEEPY_TESTS, "Received %d (should be %d)",
numReceived, SLEEPY_TESTS);
sendExit = 1;
while (q.receive(cbuf, sizeof cbuf) <= 0)
epicsThreadSleep(0.01);
epicsEventMustWait(complete);
epicsThreadMustJoin(txThread);
}
extern "C" void
@@ -242,130 +239,136 @@ sender(void *arg)
testDiag("%s exiting, sent %d messages", epicsThreadGetNameSelf(), i);
}
#define NUM_SENDERS 4
extern "C" void messageQueueTest(void *parm)
{
epicsThreadId myThreadId = epicsThreadGetIdSelf();
epicsThreadId rxThread;
epicsThreadId senderId[NUM_SENDERS];
epicsThreadOpts opts = {epicsThreadPriorityMedium,
epicsThreadStackMedium, 1};
unsigned int i;
char cbuf[80];
int len;
int pass;
int want;
epicsMessageQueue *q1 = new epicsMessageQueue(4, 20);
epicsMessageQueue q1(4, 20);
testDiag("Simple single-thread tests:");
i = 0;
testOk1(q1->pending() == 0);
while (q1->trySend((void *)msg1, i ) == 0) {
i++;
testOk(q1->pending() == i, "q1->pending() == %d", i);
testOk1(q1.pending() == 0);
for (i = 0; i < 4;) {
int ret = q1.trySend((void *)msg1, i++);
testOk(ret == 0, "trySend succeeded (%d == 0)", ret);
testOk(q1.pending() == i, "loop: q1.pending() == %d", i);
}
testOk1(q1->pending() == 4);
testOk1(q1.pending() == 4);
want = 0;
len = q1->receive(cbuf, sizeof cbuf);
testOk1(q1->pending() == 3);
len = q1.receive(cbuf, sizeof cbuf);
testOk1(q1.pending() == 3);
if (!testOk1((len == want) && (strncmp(msg1, cbuf, len) == 0)))
testDiag("wanted:%d '%.*s' got:%d '%.*s'",
want, want, msg1, len, len, cbuf);
want++;
len = q1->receive(cbuf, sizeof cbuf);
testOk1(q1->pending() == 2);
len = q1.receive(cbuf, sizeof cbuf);
testOk1(q1.pending() == 2);
if (!testOk1((len == want) && (strncmp(msg1, cbuf, len) == 0)))
testDiag("wanted:%d '%.*s' got:%d '%.*s'",
want, want, msg1, len, len, cbuf);
q1->trySend((void *)msg1, i++);
q1.trySend((void *)msg1, i++);
want++;
len = q1->receive(cbuf, sizeof cbuf);
testOk1(q1->pending() == 2);
len = q1.receive(cbuf, sizeof cbuf);
testOk1(q1.pending() == 2);
if (!testOk1((len == want) && (strncmp(msg1, cbuf, len) == 0)))
testDiag("wanted:%d '%.*s' got:%d '%.*s'",
want, want, msg1, len, len, cbuf);
q1->trySend((void *)msg1, i++);
testOk1(q1->pending() == 3);
q1.trySend((void *)msg1, i++);
testOk1(q1.pending() == 3);
i = 3;
while ((len = q1->receive(cbuf, sizeof cbuf, 1.0)) >= 0) {
while ((len = q1.receive(cbuf, sizeof cbuf, 1.0)) >= 0) {
--i;
testOk(q1->pending() == i, "q1->pending() == %d", i);
testOk(q1.pending() == i, "loop: q1.pending() == %d", i);
want++;
if (!testOk1((len == want) & (strncmp(msg1, cbuf, len) == 0)))
testDiag("wanted:%d '%.*s' got:%d '%.*s'",
want, want, msg1, len, len, cbuf);
}
testOk1(q1->pending() == 0);
testOk1(q1.pending() == 0);
testDiag("Test sender timeout:");
i = 0;
testOk1(q1->pending() == 0);
while (q1->send((void *)msg1, i, 1.0 ) == 0) {
testOk1(q1.pending() == 0);
while (q1.send((void *)msg1, i, 1.0 ) == 0) {
i++;
testOk(q1->pending() == i, "q1->pending() == %d", i);
testOk(q1.pending() == i, "loop: q1.pending() == %d", i);
}
testOk1(q1->pending() == 4);
testOk1(q1.pending() == 4);
want = 0;
len = q1->receive(cbuf, sizeof cbuf);
testOk1(q1->pending() == 3);
len = q1.receive(cbuf, sizeof cbuf);
testOk1(q1.pending() == 3);
if (!testOk1((len == want) && (strncmp(msg1, cbuf, len) == 0)))
testDiag("wanted:%d '%.*s' got:%d '%.*s'",
want, want, msg1, len, len, cbuf);
want++;
len = q1->receive(cbuf, sizeof cbuf);
testOk1(q1->pending() == 2);
len = q1.receive(cbuf, sizeof cbuf);
testOk1(q1.pending() == 2);
if (!testOk1((len == want) && (strncmp(msg1, cbuf, len) == 0)))
testDiag("wanted:%d '%.*s' got:%d '%.*s'",
want, want, msg1, len, len, cbuf);
q1->send((void *)msg1, i++, 1.0);
q1.send((void *)msg1, i++, 1.0);
want++;
len = q1->receive(cbuf, sizeof cbuf);
testOk1(q1->pending() == 2);
len = q1.receive(cbuf, sizeof cbuf);
testOk1(q1.pending() == 2);
if (!testOk1((len == want) && (strncmp(msg1, cbuf, len) == 0)))
testDiag("wanted:%d '%.*s' got:%d '%.*s'",
want, want, msg1, len, len, cbuf);
q1->send((void *)msg1, i++, 1.0);
testOk1(q1->pending() == 3);
q1.send((void *)msg1, i++, 1.0);
testOk1(q1.pending() == 3);
i = 3;
while ((len = q1->receive(cbuf, sizeof cbuf, 1.0)) >= 0) {
while ((len = q1.receive(cbuf, sizeof cbuf, 1.0)) >= 0) {
--i;
testOk(q1->pending() == i, "q1->pending() == %d", i);
testOk(q1.pending() == i, "loop: q1.pending() == %d", i);
want++;
if (!testOk1((len == want) && (strncmp(msg1, cbuf, len) == 0)))
testDiag("wanted:%d '%.*s' got:%d '%.*s'",
want, want, msg1, len, len, cbuf);
}
testOk1(q1->pending() == 0);
testOk1(q1.pending() == 0);
testDiag("Test receiver with timeout:");
for (i = 0 ; i < 4 ; i++)
testOk1 (q1->send((void *)msg1, i, 1.0) == 0);
testOk1(q1->pending() == 4);
testOk1 (q1.send((void *)msg1, i, 1.0) == 0);
testOk1(q1.pending() == 4);
for (i = 0 ; i < 4 ; i++)
testOk(q1->receive((void *)cbuf, sizeof cbuf, 1.0) == (int)i,
"q1->receive(...) == %d", i);
testOk1(q1->pending() == 0);
testOk1(q1->receive((void *)cbuf, sizeof cbuf, 1.0) < 0);
testOk1(q1->pending() == 0);
testOk(q1.receive((void *)cbuf, sizeof cbuf, 1.0) == (int)i,
"q1.receive(...) == %d", i);
testOk1(q1.pending() == 0);
testOk1(q1.receive((void *)cbuf, sizeof cbuf, 1.0) < 0);
testOk1(q1.pending() == 0);
testDiag("Single receiver with invalid size, single sender tests:");
epicsThreadCreate("Bad Receiver", epicsThreadPriorityMedium,
mediumStack, badReceiver, q1);
rxThread = epicsThreadCreateOpt("Bad Receiver", badReceiver, &q1, &opts);
if (!rxThread)
testAbort("epicsThreadCreate failed");
epicsThreadSleep(1.0);
testOk(q1->send((void *)msg1, 10) == 0, "Send with waiting receiver");
epicsThreadSleep(2.0);
testOk(q1->send((void *)msg1, 10) == 0, "Send with no receiver");
testOk(q1.send((void *)msg1, 10) == 0, "Send with waiting receiver");
epicsThreadSleep(2.0);
testOk(q1.send((void *)msg1, 10) == 0, "Send with no receiver");
epicsThreadMustJoin(rxThread);
testDiag("6 Single receiver single sender 'Sleepy timeout' tests,");
testDiag(" these should take about %.2f seconds each:",
SLEEPY_TESTS * 0.010);
complete = epicsEventMustCreate(epicsEventEmpty);
sleepySender(0.009);
sleepySender(0.010);
sleepySender(0.011);
@@ -375,11 +378,12 @@ extern "C" void messageQueueTest(void *parm)
testDiag("Single receiver, single sender tests:");
epicsThreadSetPriority(myThreadId, epicsThreadPriorityHigh);
epicsThreadCreate("Receiver one", epicsThreadPriorityMedium,
mediumStack, receiver, q1);
rxThread = epicsThreadCreateOpt("Receiver one", receiver, &q1, &opts);
if (!rxThread)
testAbort("epicsThreadCreate failed");
for (pass = 1 ; pass <= 3 ; pass++) {
for (i = 0 ; i < 10 ; i++) {
if (q1->trySend((void *)msg1, i) < 0)
if (q1.trySend((void *)msg1, i) < 0)
break;
if (pass >= 3)
epicsThreadSleep(0.5);
@@ -408,18 +412,20 @@ extern "C" void messageQueueTest(void *parm)
*/
testDiag("Single receiver, multiple sender tests:");
testDiag("This test lasts 30 seconds...");
testOk(!!epicsThreadCreate("Sender 1", epicsThreadPriorityLow,
mediumStack, sender, q1),
"Created Sender 1");
testOk(!!epicsThreadCreate("Sender 2", epicsThreadPriorityMedium,
mediumStack, sender, q1),
"Created Sender 2");
testOk(!!epicsThreadCreate("Sender 3", epicsThreadPriorityHigh,
mediumStack, sender, q1),
"Created Sender 3");
testOk(!!epicsThreadCreate("Sender 4", epicsThreadPriorityHigh,
mediumStack, sender, q1),
"Created Sender 4");
for (i=0; i<NUM_SENDERS; i++) {
char name[16];
const int pri[NUM_SENDERS] = {
epicsThreadPriorityLow,
epicsThreadPriorityMedium,
epicsThreadPriorityHigh,
epicsThreadPriorityHigh
};
sprintf(name, "Sender %d", i+1);
opts.priority = pri[i];
senderId[i] = epicsThreadCreateOpt(name, sender, &q1, &opts);
if (!senderId[i])
testAbort("epicsThreadCreate failed");
}
for (i = 0; i < 6; i++) {
testDiag("... %2d", 6 - i);
@@ -428,23 +434,30 @@ extern "C" void messageQueueTest(void *parm)
sendExit = 1;
epicsThreadSleep(1.0);
for (i=0; i<NUM_SENDERS; i++) {
epicsThreadMustJoin(senderId[i]);
}
recvExit = 1;
testDiag("Scheduler exiting");
epicsThreadMustJoin(rxThread);
}
MAIN(epicsMessageQueueTest)
{
testPlan(74);
epicsThreadOpts opts = {
epicsThreadPriorityMedium,
epicsThreadStackMedium,
1
};
epicsThreadId testThread;
finished = epicsEventMustCreate(epicsEventEmpty);
mediumStack = epicsThreadGetStackSize(epicsThreadStackMedium);
testPlan(70 + NUM_SENDERS);
epicsThreadCreate("messageQueueTest", epicsThreadPriorityMedium,
mediumStack, messageQueueTest, NULL);
testThread = epicsThreadCreateOpt("messageQueueTest",
messageQueueTest, NULL, &opts);
if (!testThread)
testAbort("epicsThreadCreate failed");
epicsEventMustWait(finished);
testDiag("Main thread signalled");
epicsThreadSleep(1.0);
epicsThreadMustJoin(testThread);
return testDone();
}

View File

@@ -7,12 +7,18 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "epicsAssert.h"
#include "dbDefs.h"
#include "osiSock.h"
#include "epicsTime.h"
#include "epicsThread.h"
#include "epicsUnitTest.h"
#include "testMain.h"
/* This could easily be generalized to test more options */
static
void udpBroadcast(SOCKET s, int put)
{
int status;
@@ -27,6 +33,7 @@ void udpBroadcast(SOCKET s, int put)
"getsockopt BROADCAST => %d", flag);
}
static
void multiCastLoop(SOCKET s, int put)
{
int status;
@@ -42,6 +49,7 @@ void multiCastLoop(SOCKET s, int put)
"getsockopt MULTICAST_LOOP => %d", (int) flag);
}
static
void multiCastTTL(SOCKET s, int put)
{
int status;
@@ -57,10 +65,13 @@ void multiCastTTL(SOCKET s, int put)
"getsockopt IP_MULTICAST_TTL => %d", (int) flag);
}
static
void udpSockTest(void)
{
SOCKET s;
testDiag("udpSockTest()");
s = epicsSocketCreate(AF_INET, SOCK_DGRAM, 0);
testOk(s != INVALID_SOCKET, "epicsSocketCreate INET, DGRAM, 0");
@@ -107,11 +118,43 @@ int doBind(int expect, SOCKET S, unsigned* port)
}
}
void udpSockFanoutTest(void)
static
void tcpSockReuseBindTest(int reuse)
{
SOCKET A, B;
unsigned port=0; /* choose random port */
testDiag("tcpSockReuseBindTest(%d)", reuse);
A = epicsSocketCreate(AF_INET, SOCK_STREAM, 0);
B = epicsSocketCreate(AF_INET, SOCK_STREAM, 0);
if(A==INVALID_SOCKET || B==INVALID_SOCKET)
testAbort("Insufficient sockets");
if(reuse) {
testDiag("epicsSocketEnableAddressReuseDuringTimeWaitState");
epicsSocketEnableAddressReuseDuringTimeWaitState(A);
epicsSocketEnableAddressReuseDuringTimeWaitState(B);
}
doBind(0, A, &port);
if(listen(A, 4))
testFail("listen(A) -> %d", (int)SOCKERRNO);
doBind(1, B, &port);
epicsSocketDestroy(A);
epicsSocketDestroy(B);
}
static
void udpSockFanoutBindTest(void)
{
SOCKET A, B, C;
unsigned port=0; /* choose random port */
testDiag("udpSockFanoutBindTest()");
A = epicsSocketCreate(AF_INET, SOCK_DGRAM, 0);
B = epicsSocketCreate(AF_INET, SOCK_DGRAM, 0);
C = epicsSocketCreate(AF_INET, SOCK_DGRAM, 0);
@@ -138,16 +181,233 @@ void udpSockFanoutTest(void)
epicsSocketDestroy(C);
}
struct CASearch {
epicsUInt16 cmd, size, dtype, dcnt;
epicsUInt32 p1, p2;
char body[16];
};
STATIC_ASSERT(sizeof(struct CASearch)==32);
union CASearchU {
struct CASearch msg;
char bytes[sizeof(struct CASearch)];
};
static
unsigned nsuccess;
static
const unsigned nrepeat = 6u;
struct TInfo {
SOCKET sock;
unsigned id;
epicsUInt32 key;
epicsUInt8 rxmask;
epicsUInt8 dupmask;
};
static
void udpSockFanoutTestRx(void* raw)
{
struct TInfo *info = raw;
epicsTimeStamp start, now;
unsigned nremain = nrepeat;
#ifdef _WIN32
/* ms */
DWORD timeout = 10000;
#else
struct timeval timeout;
memset(&timeout, 0, sizeof(struct timeval));
timeout.tv_sec = 10;
timeout.tv_usec = 0;
#endif
(void)epicsTimeGetCurrent(&start);
now = start;
testDiag("RX%u start", info->id);
if(setsockopt(info->sock, SOL_SOCKET, SO_RCVTIMEO, (void*)&timeout, sizeof(timeout))) {
testFail("Unable to set socket timeout");
return;
}
while(epicsTimeDiffInSeconds(&now, &start)<=5.0) {
union CASearchU buf;
osiSockAddr src;
osiSocklen_t srclen = sizeof(src);
int n = recvfrom(info->sock, buf.bytes, sizeof(buf.bytes), 0, &src.sa, &srclen);
buf.bytes[sizeof(buf.bytes)-1] = '\0';
if(n<0) {
testDiag("recvfrom error (%d)", (int)SOCKERRNO);
break;
} else if((n==sizeof(buf.bytes)) && buf.msg.cmd==htons(6) && buf.msg.size==htons(16)
&&buf.msg.dtype==htons(5) && buf.msg.dcnt==0 && strcmp(buf.msg.body, "totallyinvalid")==0)
{
unsigned ord = ntohl(buf.msg.p1)-info->key;
testDiag("RX%u success %u", info->id, ord);
if(ord<8) {
const epicsUInt8 mask = 1u<<ord;
if(info->rxmask&mask)
info->dupmask|=mask;
info->rxmask|=mask;
}
if(0==--nremain)
break;
} else {
testDiag("RX ignore");
}
}
testDiag("RX%u end", info->id);
}
static
void udpSockFanoutTestIface(const osiSockAddr* addr)
{
SOCKET sender;
struct TInfo rx1, rx2;
epicsThreadId trx1, trx2;
epicsThreadOpts topts = EPICS_THREAD_OPTS_INIT;
int opt = 1;
unsigned i;
osiSockAddr any;
epicsUInt32 key = 0xdeadbeef ^ ntohl(addr->ia.sin_addr.s_addr);
union CASearchU buf;
topts.joinable = 1;
/* we bind to any for lack of a portable way to find the
* interface address from the interface broadcast address
*/
memset(&any, 0, sizeof(any));
any.ia.sin_family = AF_INET;
any.ia.sin_addr.s_addr = htonl(INADDR_ANY);
any.ia.sin_port = addr->ia.sin_port;
buf.msg.cmd = htons(6);
buf.msg.size = htons(16);
buf.msg.dtype = htons(5);
buf.msg.dcnt = htons(0); /* version 0, which newer servers should ignore */
/* .p1 and .p2 set below */
memcpy(buf.msg.body, "tota" "llyi" "nval" "id\0\0", 16);
sender = epicsSocketCreate(AF_INET, SOCK_DGRAM, 0);
rx1.sock = epicsSocketCreate(AF_INET, SOCK_DGRAM, 0);
rx2.sock = epicsSocketCreate(AF_INET, SOCK_DGRAM, 0);
if((sender==INVALID_SOCKET) || (rx1.sock==INVALID_SOCKET) || (rx2.sock==INVALID_SOCKET))
testAbort("Unable to allocate test socket(s)");
rx1.id = 1;
rx2.id = 2;
rx1.key = rx2.key = key;
rx1.rxmask = rx2.rxmask = 0u;
rx1.dupmask = rx2.dupmask = 0u;
if(setsockopt(sender, SOL_SOCKET, SO_BROADCAST, (void*)&opt, sizeof(opt))!=0) {
testFail("setsockopt SOL_SOCKET, SO_BROADCAST error -> %d", (int)SOCKERRNO);
}
epicsSocketEnableAddressUseForDatagramFanout(rx1.sock);
epicsSocketEnableAddressUseForDatagramFanout(rx2.sock);
if(bind(rx1.sock, &any.sa, sizeof(any)))
testFail("Can't bind test socket rx1 %d", (int)SOCKERRNO);
if(bind(rx2.sock, &any.sa, sizeof(any)))
testFail("Can't bind test socket rx2 %d", (int)SOCKERRNO);
trx1 = epicsThreadCreateOpt("rx1", &udpSockFanoutTestRx, &rx1, &topts);
trx2 = epicsThreadCreateOpt("rx2", &udpSockFanoutTestRx, &rx2, &topts);
for(i=0; i<nrepeat; i++) {
int ret;
/* don't spam */
epicsThreadSleep(0.5);
buf.msg.p1 = buf.msg.p2 = htonl(key + i);
ret = sendto(sender, buf.bytes, sizeof(buf.bytes), 0, &addr->sa, sizeof(*addr));
if(ret!=(int)sizeof(buf.bytes))
testDiag("sendto() error %d (%d)", ret, (int)SOCKERRNO);
}
epicsThreadMustJoin(trx1);
epicsThreadMustJoin(trx2);
testDiag("Result: RX1 %x:%x RX2 %x:%x",
rx1.rxmask, rx1.dupmask, rx2.rxmask, rx2.dupmask);
/* success if any one packet was seen by both sockets */
if(rx1.rxmask & rx2.rxmask)
nsuccess++;
epicsSocketDestroy(sender);
epicsSocketDestroy(rx1.sock);
epicsSocketDestroy(rx2.sock);
}
/* This test violates the principle of unittest isolation by broadcasting
* on the well known CA search port on all interfaces. There is no
* portable way to avoid this. (eg. 127.255.255.255 is Linux specific)
*/
static
void udpSockFanoutTest()
{
ELLLIST ifaces = ELLLIST_INIT;
ELLNODE *cur;
SOCKET dummy;
osiSockAddr match;
int foundNotLo = 0;
testDiag("udpSockFanoutTest()");
memset(&match, 0, sizeof(match));
match.ia.sin_family = AF_INET;
match.ia.sin_addr.s_addr = htonl(INADDR_ANY);
if((dummy = epicsSocketCreate(AF_INET, SOCK_DGRAM, 0))==INVALID_SOCKET)
testAbort("Unable to allocate discovery socket");
osiSockDiscoverBroadcastAddresses(&ifaces, dummy, &match);
for(cur = ellFirst(&ifaces); cur; cur = ellNext(cur)) {
char name[64];
osiSockAddrNode* node = CONTAINER(cur, osiSockAddrNode, node);
node->addr.ia.sin_port = htons(5064);
(void)sockAddrToDottedIP(&node->addr.sa, name, sizeof(name));
testDiag("Interface %s", name);
if(node->addr.ia.sin_addr.s_addr!=htonl(INADDR_LOOPBACK)) {
testDiag("Not LO");
foundNotLo = 1;
}
udpSockFanoutTestIface(&node->addr);
}
ellFree(&ifaces);
testOk(foundNotLo, "Found non-loopback interface");
testOk(nsuccess>0, "Successes %u", nsuccess);
epicsSocketDestroy(dummy);
}
MAIN(osiSockTest)
{
int status;
testPlan(18);
testPlan(24);
status = osiSockAttach();
testOk(status, "osiSockAttach");
udpSockTest();
udpSockFanoutBindTest();
udpSockFanoutTest();
tcpSockReuseBindTest(0);
tcpSockReuseBindTest(1);
osiSockRelease();
return testDone();