.include "DS.S"
#-----------------------------------------------
# S T A T I C V A R I A B L E S
#-----------------------------------------------
.data
.global C.csP
C.csP: .int 0 # -->CS
.text
#-----------------------------------------------
# M A I N R O U T I N E
#-----------------------------------------------
# takes values from ENV, establishes task for comm nodes and waits for their completion
ARGS
DS prgP # -->progname
# returns nothing
PROLOC
DL this, CSL # CS - top level attr vector
DL deP # -->Debug
DL status # status returned from wait
DL pid # PID returned from wait
DL bad # cummulative subtask rc
DL s, 256 # string buf
EPILOC
#-----------------------------------------------
.global _start
_start:
PROLOG
lea this(bp), b # -->CS
mov b, C.csP # save -->CS
lea C.debug(b), a # -->Debug
mov a, deP(bp)
# initialize static debug vars
push prgP(bp) # argv[0] -->prgname
call D.init # initialize static debug vars
push D.prgNameP
# indetify itself
DEBID "client/server demo"
movl $1, C.debMaxLev(b) # default debug level
# initialize top level ctrl values vector
ShareA # allocate shared structure
mov C.csP, b
mov a, C.shP(b) # save -->shared struct in vector
movl $0, S.msgs(a) # init msg cntr
movl $0, S.conns(a) # init connection cntr
push $1 # initial semaphore value
push $1 # semaphore shared between processes
lea S.counter_sem(a), c
push c
# call sem_init # initialize shared counters semaphore
# cmp $0, a
# jz 0f
# SYSERR "sem_init of shared counters semaphore"
#0:
SYS sem_init
# set default values
mov C.csP, b
movl $3, C.ttl(b) # default TTL
movl $11000, C.rp0(b) # default bind port for the 1. node in ring
movl $12000, C.mp0(b) # default bind port for the 1. node in mash
movl $0, C.rn(b) # default # of nodes in ring
movl $0, C.mn(b) # default # of nodes in mash
movl $0, C.ssl(b) # default ssl switch - 0=noSSL
movl $77, C.connTh(b) # conn retries threshold
mov $0f, a
mov a, C.txtP(b) # default payload text
jmp 1f
0: .ascii "bla bla\0"
1:
# get control values from ENV
# get max debug level
GETINTENV "DEB"
mov C.csP, b
mov a, C.debMaxLev(b)
cmp $-1, a # debug level -1 means search subroutines
jne 0f
call D.subr
jmp C.ret
0:
# get message payload text
push $0f
call getenv
cmp $0, a
jz 1f
mov C.csP, b
mov a, C.txtP(b)
jmp 1f
0: .asciz "T"
1:
# get TTL
GETINTENV "TTL"
jz 0f
mov a, C.ttl(b)
0:
# get # of nodes in each topology
GETINTENV "I"
jz 0f
mov a, C.rn(b)
mov a, C.mn(b)
0:
# get # of nodes in ring
GETINTENV "RN"
jz 0f
mov a, C.rn(b)
0:
# get # of nodes in mash
GETINTENV "MN"
jz 0f
mov a, C.mn(b)
0:
add C.rn(b), a
cmp $3, C.ssl(b)
jne 1f
add a, a # double # of nodes when both SSL and nonSSL
1: mov C.shP(b), c # -->shared counters
mov a, S.act(c) # save # of active nodes
# get first ring node's bind port#
GETINTENV "RP0"
jz 0f
mov a, C.rp0(b)
0:
# get first mash node's bind port#
GETINTENV "MP0"
jz 0f
mov a, C.mp0(b)
0:
# get random() seed
GETINTENV "RS"
jz 0f
push a
call srandom
0:
# get pacing interval (real num in seconds)
movl $0, C.pace.tv_sec(b)
movl $0, C.pace.tv_nsec(b)
movl $0, C.pacing(b)
push $0f
call getenv
jmp 1f
0: .asciz "P"
1:
test a, a # env P set ?
jz 3f # no
push a
call atof # convert to double
fstl (sp) # tempor save
mov C.csP, b
fisttpl C.pace.tv_sec(b) # truncated integral part = secs
fldl (sp)
fisubl C.pace.tv_sec(b) # fraction part
fimull 1f # * 10^9 = nanosecs
fistl C.pace.tv_nsec(b)
jmp 2f
0: .double 0
1: .int 1000000000 # 10^9
2:
cmp $0, C.pace.tv_sec(b)
jnz 0f
cmp $0, C.pace.tv_nsec(b)
jz 3f
0: movl $1, C.pacing(b)
3:
# get ssl switch value and save it as mask
# switch: 0 = noSSL, 1 = SSL, 2 = both
# mask: 01B=noSSL, 10B=SSL, 11B=both
GETINTENV "SSL" # returned zero means SSL=0 or SSL by default 0
inc a # change switch to mask
mov a, C.ssl(b)
cmp $1, a
je C.cont # no SSL
cmp $2, a
je 0f # only SSL
mov C.shP(b), a # -->shared mem
shll $1, S.act(a) # double # of active nodes when running both SSL and nonSSL
# get SSL CA cert dir path
0:
push $0f
call getenv
jmp 1f
0: .asciz "CAP"
1:
test a, a
jnz 1f
mov $0f, a
jmp 1f
0: .asciz "/home/local/etc/ssl/certs/"
1:
mov C.csP, b
mov a, C.caPathP(b) # save -->SSL CA certs path
# get SSL dir path
push $0f
call getenv
jmp 1f
0: .asciz "CEP"
1:
test a, a
jz 0f # ceP not set, try to determine
mov C.csP, b
mov a, C.cePathP(b) # save -->SSL dir path
jmp 1f
# determine home path (needed to locate SSL keys & certificates)
0:
push prgP(bp) # -->first parm - progname w/ path
call dirname # get prog dirname
push a
call strlen # dirname length
lea 1f-0f(a), a # + suffix length
sub a, sp # allocate space for cePath
mov C.csP, b
mov sp, C.cePathP(b) # save -->SSL path
push prgP(bp)
call dirname # get home dirname
push a # -->home dirname
mov C.csP, b
push C.cePathP(b) # -->SSL path
call strcpy # copy dirname to SSL path
call strlen # end of dirname
push $0f # -->suffix
mov C.csP, b
mov C.cePathP(b), c
lea (c, a), a # -->end of dirname
push a
call strcpy # copy suffix to SSL path
jmp 1f
0: .asciz "/../CS/"
1:
# testing sandbox
mov C.csP, b
pushl C.debMaxLev(b)
cmp $9, C.debMaxLev(b)
jne C.cont
LOG 9, "debug=%u, testing...", 1
DebugA
mov a, deP(bp)
DEBID "TEST"
LOG 9, "progress"
mov C.csP, b
mov C.shP(b), a
push S.act(a)
LOG 9, "shared act=%u"
jmp C.ret
# normal execution
C.cont:
push C.debMaxLev(b)
push C.ssl(b)
push C.pace.tv_nsec(b)
push C.pace.tv_sec(b)
push C.ttl(b)
push C.rn(b)
push C.mn(b)
push D.prgNameP
LOG 1, "pgm=%s, mash nodes=%d, ring nodes=%d, ttl=%d, pacing=%ld.%09ld, SSL mask=0x%02x, debug=%u", 8
testl $2, C.ssl(b)
jz 0f
push C.caPathP(b)
push C.cePathP(b)
LOG 1, "SSL path=%s, SSL CA path=%s"
0:
# create constellation processes RING/MASH, nonSSL/SSL
mov $0, c # iter counter
mov C.ssl(b), d # SSL mask (01b = noSSL, 10b = SSL, 11b = both)
# iterate on SSL variants
C.iterateOnSsl:
test $1, d # check lowest bit of mask
jz C.nextSsslVar # next SSL variant
pusha
# create RING
SYS fork
jnz 1f # parent
popa
pushl $Cn.ring # RING topology
push c # use iter ctr as SSL switch
call Constellation # create RING constellation
1: push a
LOG 5, "RING started in process %d"
lea 4(sp), sp
# create MASH
SYS fork
jnz 1f # parent
popa
pushl $Cn.mash # MASH topology
push c # use iter ctr as SSL switch
call Constellation # create MASH constellation
1: push a
LOG 5, "MASH started in process %d"
lea 4(sp), sp
popa
C.nextSsslVar:
shr $1, d # shift to test next SSL bit
inc c # incr ctr
cmp $2, c
jl C.iterateOnSsl
# wait for constellation processes completion
LOG 5, "waiting for constellations to terminate"
movl $0, bad(bp) # clear cummulative rc
C.iterateOnWait:
lea status(bp), a
push a # -->return status of task
call wait
mov a, pid(bp) # save pid
cmp $-1, a # a task ended?
jne 0f # yes
call __errno_location
cmp $10, (a) # error == ECHILD ?
je C.ret # yes, no other subtasks
SYSERR "wait"
0:
# push status(bp) # status of task
# push a # pid
# LOG 5, "status returned from task %u: 0x%08x"
mov status(bp), d
test $0x7f, d
jnz 1f # task killed, ABEND
and $0xff00, d # task exited, extract rc
shr $8, d
or d, bad(bp) # accumulate rc
push d # task rc
push pid(bp) # task pid
LOG 5, "constellation task %u ended with exit(%d)"
jmp C.iterateOnWait # wait for other tasks
1: push d
push pid(bp)
LOG 5, "constellation task %u killed, status=0x%x", 2
2:
# ABEND
LOG 0, "ABEND, kill all tasks"
pushl $15 # SIGTERM
pushl $0 # all tasks
# call kill
SYS kill
pushl $1
call exit
# normal end
C.ret: movl C.csP, b # -->CS vector
movl C.shP(b), b # -->Share
pushl S.conns(b) # no. of connections made
pushl S.msgs(b) # no. of messages sent
LOG 1, "END, forwards=%d, connections=%d", 2
push bad(bp)
call exit
#-----------------------------------------------
# C O N S T E L L A T I O N O P E R A T I O N S
#-----------------------------------------------
ARGS
DS ssl # ssl switch
DS topo # topology
# returns: nothing
PROLOC
DL this, ConstellationL # this Constellation instance
DL thisP # -->this Constellation
DL deP # -->Debug
DL last # last node#
DL pid # pid returned from wait
DL stat # stat returned from wait
DL bad # "some node BAD" exit indicator
DL catched # count of returned node tasks
DL killed # count of killed node tasks
EPILOC
#-----------------------------------------------
.global Constellation
Constellation:
PROLOG
lea this(bp), b # -->this Constellation
mov b, thisP(bp) # save -->this Constellation
# set debid
lea Cn.debug(b), a # -->Debug
mov a, deP(bp) # save -->Debug locally
mov C.csP, c # -->CS
cmp $Cn.ring, topo(bp) # ring topology ?
je 0f
mov C.mn(c), a # num. of nodes
mov a, Cn.nodes(b)
mov C.mp0(c), a # port # of fist node
mov a, Cn.first(b)
movl $Cn.mash, Cn.topo(b)
push $8f
jmp 1f
0: mov C.rn(c), a # num. of nodes
mov a, Cn.nodes(b)
mov C.rp0(c), a # port # of fist node
mov a, Cn.first(b)
movl $Cn.ring, Cn.topo(b)
push $7f
1: cmp $0, ssl(bp) # SSL ?
jz 2f # no
movl $1, Cn.ssl(b)
addl $500, Cn.first(b) # first SSL port #
push $6f
jmp 9f
2: movl $0, Cn.ssl(b)
push $5f
jmp 9f
5: .ascii "non\0"
6: .ascii "\0"
7: .ascii "RING\0"
8: .ascii "MASH\0"
9: DEBID "%sSSL %s", 2
# check # of nodes
movL $0, bad(bp)
cmp $1, Cn.nodes(b) # num of nodes
jl Cn.ret # < 1 ? nothing to do
jg 0f
LOG 0, "1 node configuration not implemented yet"
jmp Cn.ret
0: LOG 5, "initializing..."
# determine divisor for random next node choise
mov $1, a
shl $31, a
not a # MAX_INT
xor d, d
divl Cn.nodes(b)
mov a, Cn.div(b) # save divisor (MAX_INT / nodes)
# allocate "forward" indicator shared by nodes in constellation
push $0
push $-1
push $0x21 # PROT_READ | PROT_WRITE
push $0x03 # MAP_SHARED | MAP_ANONYMOUS
push $4
push $0
# call mmap
# cmp $-1, a
# jne 0f
# SYSERR "mmap"
#0: mov thisP(bp), b
SYS mmap
mov a, Cn.forwP(b) # save -->forw
movl $1, (a) # enable forwarding
push Cn.nodes(b)
LOG 1, "%u nodes starting..."
# start processes for all nodes in constellation
mov Cn.first(b), d # first node#
mov d, c
add Cn.nodes(b), c # last node + 1
Cn.iterateOnFork:
pusha
# call fork
SYS fork
cmp $0, a
jnz 1f # parent
popa
push d # node's port#
push b # -->Cnstlln
call Node
1: mov a, pid(bp)
popa
push pid(bp) # nodes's pid
push d # node's port#
LOG 4, "node %u established in process %u", 2
inc d
cmp d, c # last node ?
jg Cn.iterateOnFork # no, continue forking
# wait for completion of node processes
LOG 2, "all nodes established, waiting for them to terminate..."
movl $0, bad(bp) # accumulated return status of node tasks
movl $0, killed(bp) # num. of killed node tasks
movl $0, catched(bp) # num. of returned node tasks
lea -12(sp), sp # prepare space for loop
Cn.iterateOnWait:
cmp $0, bad(bp) # constellation status still OK ?
je 1f # yes
mov Cn.forwP(b), a # -->forwarding switch
movl $0, (a) # disable forwarding between nodes
1:
lea stat(bp), c
mov c, (sp) # -->return status of task
call wait
mov thisP(bp), b
cmp $-1, a # normal return from wait?
jne 0f # yes
call __errno_location
cmp $10, (a) # error == ECHILD ?
je Cn.allFinished # yes, no subtasks
SYSERR "wait"
0:
incl catched(bp)
mov a, pid(bp) # save subtask's pid
mov a, (sp)
mov stat(bp), c # subtask return status
mov c, 4(sp)
test $0x7f, c # subtask ended by exit ?
jnz 2f # no, killed
and $0xff00, c # extract subtask rc
jz 1f # rc = 0
movl $1, bad(bp) # non zero rc, turn on BAD switch
1: shr $8, c
mov c, 4(sp) # rc
mov a, (sp) # pid
LOG 4, "node process %u ended by exit(%d)"
jmp Cn.iterateOnWait # continue waiting for other subtasks
2: movl $1, bad(bp) # subtask killed, turn on BAD switch
incl killed(bp) # counter of killed
mov c, 4(sp) # status
mov a, (sp) # pid
LOG 4, "node process %u killed, status=0x%x"
jmp Cn.iterateOnWait # continue waiting for other subtasks
# opers of all nodes finished
Cn.allFinished:
push killed(bp)
push catched(bp)
mov thisP(bp), b
push Cn.nodes(b)
cmp $0, bad(bp) # all nodes ended OK ?
je 0f # yes
push $7f
jmp 9f
0: push $8f
jmp 9f
7: .ascii "with ERROR\0"
8: .ascii "OK\0"
9: LOG 1, "ENDED %s, %u spawned, %u catched, %u killed"
Cn.ret:
push bad(bp)
call exit
#-----------------------------------------------
# G E T I N T V A L U E S F R O M E N V
#-----------------------------------------------
ARGS
DS key # -->env key string
# returns int value or 0 if not found
PROLOC
EPILOC
#-----------------------------------------------
C.getArg:
PROLOG
pushl key(bp) # -->env key string
call getenv # get value
test a, a
jz 0f # not found in ENV
push a
call atoi # convert to int
0:
EPILOG_R
#-----------------------------------------------
# A B N O R M A L E N D
#-----------------------------------------------
ARGS
DS deP # -->Debug
PROLOC
EPILOC
#-----------------------------------------------
.globl C.abend
C.abend:
PROLOG
LOG 0, "ABEND"
push $15 # SIGTERM
push $0 # kill all
# call kill
SYS kill
push $1
call exit
#-----------------------------------------------
.end