Log session timeout and connection drop
This commit is contained in:
1 parent
ef712de9e3
commit
342138d92e
3 files changed
+216
-155
No files matched your search
+214
-152
@@ -52,13 +52,37 @@ throwError = (err, httpResponse) ->
|
|||||||
throw err
|
throw err
|
||||||
|
|
||||||
|
|
||||||
writeResponse = (sessionContext, res) ->
|
writeResponse = (sessionContext, res, close) ->
|
||||||
|
# Close connection after last request in session
|
||||||
|
res.headers['Connection'] = 'close' if close
|
||||||
|
|
||||||
if config.get('DEBUG', sessionContext.deviceId)
|
if config.get('DEBUG', sessionContext.deviceId)
|
||||||
dump = "# RESPONSE #{new Date(Date.now())}\n" + JSON.stringify(res.headers) + "\n#{res.data}\n\n"
|
dump = "# RESPONSE #{new Date(Date.now())}\n" + JSON.stringify(res.headers) + "\n#{res.data}\n\n"
|
||||||
require('fs').appendFile("./debug/#{sessionContext.deviceId}.dump", dump, (err) ->
|
require('fs').appendFile("./debug/#{sessionContext.deviceId}.dump", dump, (err) ->
|
||||||
throwError(err) if err
|
throwError(err) if err
|
||||||
)
|
)
|
||||||
|
|
||||||
|
finish = () ->
|
||||||
|
stats.concurrentRequests -= 1
|
||||||
|
if sessionContext.httpRequest.connection.destroyed
|
||||||
|
logger.accessError({
|
||||||
|
sessionContext: sessionContext
|
||||||
|
message: 'Connection dropped'
|
||||||
|
})
|
||||||
|
else if close
|
||||||
|
endSession(sessionContext, (err, isNew) ->
|
||||||
|
return throwError(err) if err
|
||||||
|
|
||||||
|
if isNew
|
||||||
|
logger.accessInfo({
|
||||||
|
sessionContext: sessionContext
|
||||||
|
message: 'New device registered'
|
||||||
|
})
|
||||||
|
)
|
||||||
|
else
|
||||||
|
sessionContext.lastActivity = Date.now()
|
||||||
|
currentSessions.set(sessionContext.httpRequest.connection, sessionContext)
|
||||||
|
|
||||||
# respond using the same content-encoding as the request
|
# respond using the same content-encoding as the request
|
||||||
if sessionContext.httpRequest.headers['content-encoding']? and res.data.length > 0
|
if sessionContext.httpRequest.headers['content-encoding']? and res.data.length > 0
|
||||||
switch sessionContext.httpRequest.headers['content-encoding']
|
switch sessionContext.httpRequest.headers['content-encoding']
|
||||||
@@ -75,17 +99,13 @@ writeResponse = (sessionContext, res) ->
|
|||||||
res.headers['Content-Length'] = data.length
|
res.headers['Content-Length'] = data.length
|
||||||
sessionContext.httpResponse.writeHead(res.code, res.headers)
|
sessionContext.httpResponse.writeHead(res.code, res.headers)
|
||||||
sessionContext.httpResponse.end(data)
|
sessionContext.httpResponse.end(data)
|
||||||
delete sessionContext.httpRequest
|
finish()
|
||||||
delete sessionContext.httpResponse
|
|
||||||
stats.concurrentRequests -= 1
|
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
res.headers['Content-Length'] = res.data.length
|
res.headers['Content-Length'] = res.data.length
|
||||||
sessionContext.httpResponse.writeHead(res.code, res.headers)
|
sessionContext.httpResponse.writeHead(res.code, res.headers)
|
||||||
sessionContext.httpResponse.end(res.data)
|
sessionContext.httpResponse.end(res.data)
|
||||||
delete sessionContext.httpRequest
|
finish()
|
||||||
delete sessionContext.httpResponse
|
|
||||||
stats.concurrentRequests -= 1
|
|
||||||
|
|
||||||
|
|
||||||
recordFault = (sessionContext, fault, provisions, channels) ->
|
recordFault = (sessionContext, fault, provisions, channels) ->
|
||||||
@@ -112,7 +132,7 @@ recordFault = (sessionContext, fault, provisions, channels) ->
|
|||||||
sessionContext.faultsTouched ?= {}
|
sessionContext.faultsTouched ?= {}
|
||||||
sessionContext.faultsTouched[channel] = true
|
sessionContext.faultsTouched[channel] = true
|
||||||
|
|
||||||
logger.accessError({
|
logger.accessWarn({
|
||||||
sessionContext: sessionContext
|
sessionContext: sessionContext
|
||||||
message: 'Channel has faulted'
|
message: 'Channel has faulted'
|
||||||
fault: fault
|
fault: fault
|
||||||
@@ -452,8 +472,6 @@ nextRpc = (sessionContext) ->
|
|||||||
|
|
||||||
|
|
||||||
endSession = (sessionContext, callback) ->
|
endSession = (sessionContext, callback) ->
|
||||||
delete currentSessions.get(sessionContext.httpRequest.connection)[sessionContext.sessionId]
|
|
||||||
|
|
||||||
saveCache = sessionContext.cacheUntil?
|
saveCache = sessionContext.cacheUntil?
|
||||||
|
|
||||||
counter = 3
|
counter = 3
|
||||||
@@ -534,17 +552,7 @@ endSession = (sessionContext, callback) ->
|
|||||||
|
|
||||||
sendAcsRequest = (sessionContext, id, acsRequest) ->
|
sendAcsRequest = (sessionContext, id, acsRequest) ->
|
||||||
if not acsRequest?
|
if not acsRequest?
|
||||||
return endSession(sessionContext, (err, isNew) ->
|
return writeResponse(sessionContext, soap.response(null), true)
|
||||||
return throwError(err, sessionContext.httpResponse) if err
|
|
||||||
|
|
||||||
if isNew
|
|
||||||
logger.accessInfo({
|
|
||||||
sessionContext: sessionContext
|
|
||||||
message: 'New device registered'
|
|
||||||
})
|
|
||||||
|
|
||||||
writeResponse(sessionContext, soap.response(null))
|
|
||||||
)
|
|
||||||
|
|
||||||
if acsRequest.name is 'Download'
|
if acsRequest.name is 'Download'
|
||||||
if not acsRequest.url?
|
if not acsRequest.url?
|
||||||
@@ -585,42 +593,66 @@ sendAcsRequest = (sessionContext, id, acsRequest) ->
|
|||||||
writeResponse(sessionContext, res)
|
writeResponse(sessionContext, res)
|
||||||
|
|
||||||
|
|
||||||
getSession = (httpRequest, sessionId, callback) ->
|
getSession = (connection, sessionId, callback) ->
|
||||||
return callback() if not sessionId?
|
sessionContext = currentSessions.get(connection)
|
||||||
|
|
||||||
sessionContext = currentSessions.get(httpRequest.connection)?[sessionId]
|
if sessionContext
|
||||||
|
currentSessions.delete(connection)
|
||||||
if sessionContext?
|
|
||||||
return callback(null, sessionContext)
|
return callback(null, sessionContext)
|
||||||
|
|
||||||
|
return callback() if not sessionId
|
||||||
|
|
||||||
setTimeout(() ->
|
setTimeout(() ->
|
||||||
cache.pop("session_#{sessionId}", (err, sessionContextString) ->
|
cache.pop("session_#{sessionId}", (err, sessionContextString) ->
|
||||||
return callback(err) if err or not sessionContextString
|
return callback(err) if err or not sessionContextString
|
||||||
session.deserialize(sessionContextString, (err, sessionContext) ->
|
session.deserialize(sessionContextString, callback)
|
||||||
return callback(err) if err
|
|
||||||
currentSessions.get(httpRequest.connection)[sessionId] = sessionContext
|
|
||||||
callback(null, sessionContext)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
, 100
|
, 100)
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
currentSessions = new WeakMap()
|
currentSessions = new WeakMap()
|
||||||
|
|
||||||
# When socket closes, store active sessions in cache
|
# When socket closes, store active sessions in cache
|
||||||
onConnection = (socket) ->
|
onConnection = (socket) ->
|
||||||
currentSessions.set(socket, {})
|
# The property remoteAddress may be undefined after the connection is
|
||||||
|
# closed, unless we read it at least once (caching?)
|
||||||
|
socket.remoteAddress
|
||||||
|
|
||||||
socket.on('close', () ->
|
socket.on('close', () ->
|
||||||
sessions = currentSessions.get(socket)
|
sessionContext = currentSessions.get(socket)
|
||||||
for sessionId, sessionContext of sessions
|
return if not sessionContext
|
||||||
session.serialize(sessionContext, (err, sessionContextString) ->
|
currentSessions.delete(socket)
|
||||||
|
now = Date.now()
|
||||||
|
|
||||||
|
lastActivity = sessionContext.lastActivity
|
||||||
|
timeoutMsg = logger.flatten({
|
||||||
|
sessionContext: sessionContext
|
||||||
|
message: 'Session timeout'
|
||||||
|
sessionTimestamp: sessionContext.timestamp
|
||||||
|
})
|
||||||
|
|
||||||
|
timeout = (sessionContext.lastActivity + sessionContext.timeout * 1000) - now
|
||||||
|
if timeout <= 0
|
||||||
|
return logger.accessError(timeoutMsg)
|
||||||
|
|
||||||
|
setTimeout(() ->
|
||||||
|
cache.get("session_#{sessionContext.sessionId}", (err, sessionContextString) ->
|
||||||
return throwError(err) if err
|
return throwError(err) if err
|
||||||
# TODO don't set if process is shutting down
|
return if not sessionContextString
|
||||||
cache.set("session_#{sessionId}", sessionContextString, sessionContext.timeout, (err) ->
|
session.deserialize(sessionContextString, (err, sessionContext) ->
|
||||||
return throwError(err) if err
|
return throwError(err) if err
|
||||||
|
if sessionContext.lastActivity == lastActivity
|
||||||
|
logger.accessError(timeoutMsg)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
, timeout + 1000).unref()
|
||||||
|
|
||||||
|
session.serialize(sessionContext, (err, sessionContextString) ->
|
||||||
|
return throwError(err) if err
|
||||||
|
cache.set("session_#{sessionContext.sessionId}", sessionContextString, Math.ceil(timeout / 1000) + 3, (err) ->
|
||||||
|
return throwError(err) if err
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
setInterval(() ->
|
setInterval(() ->
|
||||||
@@ -701,10 +733,73 @@ cacheDueTasksAndFaultsAndOperations = (deviceId, tasks, faults, operations, cach
|
|||||||
cache.set("#{deviceId}_tasks_faults_operations", JSON.stringify(v), ttl, callback)
|
cache.set("#{deviceId}_tasks_faults_operations", JSON.stringify(v), ttl, callback)
|
||||||
|
|
||||||
|
|
||||||
|
processRequest = (sessionContext, rpc) ->
|
||||||
|
if rpc.cpeRequest?
|
||||||
|
if rpc.cpeRequest.name is 'Inform'
|
||||||
|
logger.accessInfo({
|
||||||
|
sessionContext: sessionContext
|
||||||
|
message: 'Inform'
|
||||||
|
rpc: rpc
|
||||||
|
})
|
||||||
|
inform(sessionContext, rpc)
|
||||||
|
else if rpc.cpeRequest.name is 'TransferComplete'
|
||||||
|
logger.accessInfo({
|
||||||
|
sessionContext: sessionContext
|
||||||
|
message: 'CPE request'
|
||||||
|
rpc: rpc
|
||||||
|
})
|
||||||
|
transferComplete(sessionContext, rpc)
|
||||||
|
else if rpc.cpeRequest.name is 'GetRPCMethods'
|
||||||
|
logger.accessInfo({
|
||||||
|
sessionContext: sessionContext
|
||||||
|
message: 'CPE request'
|
||||||
|
rpc: rpc
|
||||||
|
})
|
||||||
|
res = soap.response({
|
||||||
|
id : rpc.id
|
||||||
|
acsResponse : {name: 'GetRPCMethodsResponse', methodList: ['Inform', 'GetRPCMethods', 'TransferComplete']}
|
||||||
|
cwmpVersion : sessionContext.cwmpVersion
|
||||||
|
})
|
||||||
|
writeResponse(sessionContext, res)
|
||||||
|
else
|
||||||
|
return throwError(new Error('ACS method not supported'), sessionContext.httpResponse)
|
||||||
|
else if rpc.cpeResponse
|
||||||
|
session.rpcResponse(sessionContext, rpc.id, rpc.cpeResponse, (err) ->
|
||||||
|
return throwError(err, sessionContext.httpResponse) if err
|
||||||
|
nextRpc(sessionContext)
|
||||||
|
)
|
||||||
|
else if rpc.cpeFault
|
||||||
|
logger.accessWarn({
|
||||||
|
sessionContext: sessionContext
|
||||||
|
message: 'CPE fault'
|
||||||
|
rpc:rpc
|
||||||
|
})
|
||||||
|
session.rpcFault(sessionContext, rpc.id, rpc.cpeFault, (err, fault) ->
|
||||||
|
return throwError(err, sessionContext.httpResponse) if err
|
||||||
|
|
||||||
|
if fault
|
||||||
|
recordFault(sessionContext, fault)
|
||||||
|
session.clearProvisions(sessionContext)
|
||||||
|
nextRpc(sessionContext)
|
||||||
|
)
|
||||||
|
else # CPE sent empty response
|
||||||
|
session.timeoutOperations(sessionContext, (err, faults, operations) ->
|
||||||
|
return throwError(err, sessionContext.httpResponse) if err
|
||||||
|
|
||||||
|
for fault, i in faults
|
||||||
|
for k, v of operations[i].retries
|
||||||
|
sessionContext.retries[k] = v
|
||||||
|
|
||||||
|
recordFault(sessionContext, fault, operations[i].provisions, operations[i].channels)
|
||||||
|
|
||||||
|
nextRpc(sessionContext)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
listener = (httpRequest, httpResponse) ->
|
listener = (httpRequest, httpResponse) ->
|
||||||
stats.totalRequests += 1
|
stats.totalRequests += 1
|
||||||
if httpRequest.method != 'POST'
|
if httpRequest.method != 'POST'
|
||||||
httpResponse.writeHead 405, {'Allow': 'POST'}
|
httpResponse.writeHead 405, {'Allow': 'POST', 'Connection': 'close'}
|
||||||
httpResponse.end('405 Method Not Allowed')
|
httpResponse.end('405 Method Not Allowed')
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -716,7 +811,7 @@ listener = (httpRequest, httpResponse) ->
|
|||||||
|
|
||||||
# If overloaded, ask CPE to retry in 60 seconds
|
# If overloaded, ask CPE to retry in 60 seconds
|
||||||
if not sessionId and stats.concurrentRequests > MAX_CONCURRENT_REQUESTS
|
if not sessionId and stats.concurrentRequests > MAX_CONCURRENT_REQUESTS
|
||||||
httpResponse.writeHead(503, {'Retry-after': 60})
|
httpResponse.writeHead(503, {'Retry-after': 60, 'Connection': 'close'})
|
||||||
httpResponse.end('503 Service Unavailable')
|
httpResponse.end('503 Service Unavailable')
|
||||||
stats.droppedRequests += 1
|
stats.droppedRequests += 1
|
||||||
return
|
return
|
||||||
@@ -728,12 +823,19 @@ listener = (httpRequest, httpResponse) ->
|
|||||||
when 'deflate'
|
when 'deflate'
|
||||||
stream = httpRequest.pipe(zlib.createInflate())
|
stream = httpRequest.pipe(zlib.createInflate())
|
||||||
else
|
else
|
||||||
httpResponse.writeHead(415)
|
httpResponse.writeHead(415, {'Connection': 'close'})
|
||||||
httpResponse.end('415 Unsupported Media Type')
|
httpResponse.end('415 Unsupported Media Type')
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
stream = httpRequest
|
stream = httpRequest
|
||||||
|
|
||||||
|
stats.concurrentRequests += 1
|
||||||
|
httpRequest.on('aborted', () ->
|
||||||
|
stats.concurrentRequests -= 1
|
||||||
|
# In some cases event end can be emitted after aborted event
|
||||||
|
httpRequest.removeAllListeners('end')
|
||||||
|
)
|
||||||
|
|
||||||
chunks = []
|
chunks = []
|
||||||
bytes = 0
|
bytes = 0
|
||||||
|
|
||||||
@@ -742,63 +844,15 @@ listener = (httpRequest, httpResponse) ->
|
|||||||
bytes += chunk.length
|
bytes += chunk.length
|
||||||
)
|
)
|
||||||
|
|
||||||
httpRequest.getBody = () ->
|
stream.on('end', () ->
|
||||||
# Write all chunks into a Buffer
|
|
||||||
body = new Buffer(bytes)
|
body = new Buffer(bytes)
|
||||||
offset = 0
|
offset = 0
|
||||||
chunks.forEach((chunk) ->
|
chunks.forEach((chunk) ->
|
||||||
chunk.copy(body, offset, 0, chunk.length)
|
chunk.copy(body, offset, 0, chunk.length)
|
||||||
offset += chunk.length
|
offset += chunk.length
|
||||||
)
|
)
|
||||||
return body
|
|
||||||
|
|
||||||
stream.on('end', () ->
|
|
||||||
stats.concurrentRequests += 1
|
|
||||||
rpc = null
|
|
||||||
parseWarnings = []
|
|
||||||
getSession(httpRequest, sessionId, f = (err, sessionContext) ->
|
|
||||||
return throwError(err, httpResponse) if err
|
|
||||||
|
|
||||||
rpc ?= soap.request(httpRequest, sessionContext?.cwmpVersion, parseWarnings)
|
|
||||||
if not sessionContext?
|
|
||||||
if rpc.cpeRequest?.name isnt 'Inform'
|
|
||||||
httpResponse.writeHead(400)
|
|
||||||
httpResponse.end('Session is expired')
|
|
||||||
stats.concurrentRequests -= 1
|
|
||||||
return
|
|
||||||
|
|
||||||
stats.initiatedSessions += 1
|
|
||||||
deviceId = common.generateDeviceId(rpc.cpeRequest.deviceId)
|
|
||||||
return session.init(deviceId, rpc.cwmpVersion, rpc.sessionTimeout ? config.get('SESSION_TIMEOUT', deviceId), (err, sessionContext) ->
|
|
||||||
return throwError(err, httpResponse) if err
|
|
||||||
|
|
||||||
sessionContext.sessionId = crypto.randomBytes(8).toString('hex')
|
|
||||||
|
|
||||||
currentSessions.get(httpRequest.connection)[sessionContext.sessionId] = sessionContext
|
|
||||||
|
|
||||||
httpRequest.connection.setTimeout(sessionContext.timeout * 1000)
|
|
||||||
|
|
||||||
getDueTasksAndFaultsAndOperations(deviceId, sessionContext.timestamp, (err, dueTasks, faults, operations, cacheUntil) ->
|
|
||||||
return throwError(err, httpResponse) if err
|
|
||||||
sessionContext.tasks = dueTasks
|
|
||||||
sessionContext.faults = faults
|
|
||||||
sessionContext.retries = {}
|
|
||||||
for k, v of faults
|
|
||||||
sessionContext.retries[k] = v.retries
|
|
||||||
sessionContext.operations = operations
|
|
||||||
sessionContext.cacheUntil = cacheUntil
|
|
||||||
|
|
||||||
# Delete expired faults
|
|
||||||
for k, v of sessionContext.faults
|
|
||||||
if v.expiry >= sessionContext.timestamp
|
|
||||||
delete sessionContext.faults[k]
|
|
||||||
sessionContext.faultsTouched ?= {}
|
|
||||||
sessionContext.faultsTouched[k] = true
|
|
||||||
|
|
||||||
f(null, sessionContext)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
parsedRpc = (sessionContext, rpc, parseWarnings) ->
|
||||||
sessionContext.httpRequest = httpRequest
|
sessionContext.httpRequest = httpRequest
|
||||||
sessionContext.httpResponse = httpResponse
|
sessionContext.httpResponse = httpResponse
|
||||||
|
|
||||||
@@ -808,71 +862,79 @@ listener = (httpRequest, httpResponse) ->
|
|||||||
logger.accessWarn(w)
|
logger.accessWarn(w)
|
||||||
|
|
||||||
if config.get('DEBUG', sessionContext.deviceId)
|
if config.get('DEBUG', sessionContext.deviceId)
|
||||||
dump = "# REQUEST #{new Date(Date.now())}\n" + JSON.stringify(httpRequest.headers) + "\n#{httpRequest.getBody()}\n\n"
|
dump = "# REQUEST #{new Date(Date.now())}\n" + JSON.stringify(httpRequest.headers) + "\n#{body}\n\n"
|
||||||
require('fs').appendFile("./debug/#{sessionContext.deviceId}.dump", dump, (err) ->
|
require('fs').appendFile("./debug/#{sessionContext.deviceId}.dump", dump, (err) ->
|
||||||
return throwError(err) if err
|
return throwError(err) if err
|
||||||
)
|
)
|
||||||
|
|
||||||
if rpc.cpeRequest?
|
processRequest(sessionContext, rpc)
|
||||||
if rpc.cpeRequest.name is 'Inform'
|
|
||||||
logger.accessInfo({
|
getSession(httpRequest.connection, sessionId, (err, sessionContext) ->
|
||||||
sessionContext: sessionContext
|
return throwError(err, httpResponse) if err
|
||||||
message: 'Inform'
|
|
||||||
rpc: rpc
|
if sessionContext and (sessionContext.sessionId != sessionId or
|
||||||
})
|
sessionContext.lastActivity + sessionContext.timeout * 1000 < Date.now())
|
||||||
inform(sessionContext, rpc)
|
logger.accessError({message: 'Invalid session', sessionContext: sessionContext})
|
||||||
else if rpc.cpeRequest.name is 'TransferComplete'
|
httpResponse.writeHead(400, {'Connection': 'close'})
|
||||||
logger.accessInfo({
|
httpResponse.end('Invalid session')
|
||||||
sessionContext: sessionContext
|
stats.concurrentRequests -= 1
|
||||||
message: 'CPE request'
|
return
|
||||||
rpc: rpc
|
|
||||||
})
|
# Check again just in case device included old session ID from the previous session
|
||||||
transferComplete(sessionContext, rpc)
|
if not sessionContext and stats.concurrentRequests > MAX_CONCURRENT_REQUESTS
|
||||||
else if rpc.cpeRequest.name is 'GetRPCMethods'
|
httpResponse.writeHead(503, {'Retry-after': 60, 'Connection': 'close'})
|
||||||
logger.accessInfo({
|
httpResponse.end('503 Service Unavailable')
|
||||||
sessionContext: sessionContext
|
stats.droppedRequests += 1
|
||||||
message: 'CPE request'
|
stats.concurrentRequests -= 1
|
||||||
rpc: rpc
|
return
|
||||||
})
|
|
||||||
res = soap.response({
|
parseWarnings = []
|
||||||
id : rpc.id
|
rpc = soap.request(body, sessionContext?.cwmpVersion, parseWarnings)
|
||||||
acsResponse : {name: 'GetRPCMethodsResponse', methodList: ['Inform', 'GetRPCMethods', 'TransferComplete']}
|
|
||||||
cwmpVersion : sessionContext.cwmpVersion
|
return parsedRpc(sessionContext, rpc, parseWarnings) if sessionContext
|
||||||
})
|
|
||||||
writeResponse(sessionContext, res)
|
if rpc.cpeRequest?.name isnt 'Inform'
|
||||||
else
|
msg = {
|
||||||
return throwError(new Error('ACS method not supported'), sessionContext.httpResponse)
|
message: 'Invalid session'
|
||||||
else if rpc.cpeResponse
|
sessionContext: sessionContext or {}
|
||||||
session.rpcResponse(sessionContext, rpc.id, rpc.cpeResponse, (err) ->
|
}
|
||||||
return throwError(err, sessionContext.httpResponse) if err
|
msg.sessionContext.httpRequest = httpRequest
|
||||||
nextRpc(sessionContext)
|
msg.sessionContext.httpResponse = httpResponse
|
||||||
)
|
logger.accessError(msg)
|
||||||
else if rpc.cpeFault
|
httpResponse.writeHead(400, {'Connection': 'close'})
|
||||||
logger.accessWarn({
|
httpResponse.end('Invalid session')
|
||||||
sessionContext: sessionContext
|
stats.concurrentRequests -= 1
|
||||||
message: 'CPE fault'
|
return
|
||||||
rpc:rpc
|
|
||||||
})
|
stats.initiatedSessions += 1
|
||||||
session.rpcFault(sessionContext, rpc.id, rpc.cpeFault, (err, fault) ->
|
deviceId = common.generateDeviceId(rpc.cpeRequest.deviceId)
|
||||||
return throwError(err, sessionContext.httpResponse) if err
|
return session.init(deviceId, rpc.cwmpVersion, rpc.sessionTimeout ? config.get('SESSION_TIMEOUT', deviceId), (err, sessionContext) ->
|
||||||
|
return throwError(err, httpResponse) if err
|
||||||
if fault
|
|
||||||
recordFault(sessionContext, fault)
|
sessionContext.sessionId = crypto.randomBytes(8).toString('hex')
|
||||||
session.clearProvisions(sessionContext)
|
httpRequest.connection.setTimeout(sessionContext.timeout * 1000)
|
||||||
nextRpc(sessionContext)
|
|
||||||
)
|
getDueTasksAndFaultsAndOperations(deviceId, sessionContext.timestamp, (err, dueTasks, faults, operations, cacheUntil) ->
|
||||||
else # CPE sent empty response
|
return throwError(err, httpResponse) if err
|
||||||
session.timeoutOperations(sessionContext, (err, faults, operations) ->
|
|
||||||
return throwError(err, sessionContext.httpResponse) if err
|
sessionContext.tasks = dueTasks
|
||||||
|
sessionContext.faults = faults
|
||||||
for fault, i in faults
|
sessionContext.retries = {}
|
||||||
for k, v of operations[i].retries
|
for k, v of faults
|
||||||
sessionContext.retries[k] = v
|
sessionContext.retries[k] = v.retries
|
||||||
|
sessionContext.operations = operations
|
||||||
recordFault(sessionContext, fault, operations[i].provisions, operations[i].channels)
|
sessionContext.cacheUntil = cacheUntil
|
||||||
|
|
||||||
nextRpc(sessionContext)
|
# Delete expired faults
|
||||||
|
for k, v of sessionContext.faults
|
||||||
|
if v.expiry >= sessionContext.timestamp
|
||||||
|
delete sessionContext.faults[k]
|
||||||
|
sessionContext.faultsTouched ?= {}
|
||||||
|
sessionContext.faultsTouched[k] = true
|
||||||
|
|
||||||
|
parsedRpc(sessionContext, rpc, parseWarnings)
|
||||||
)
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -311,6 +311,7 @@ function accessError(details) {
|
|||||||
|
|
||||||
exports.init = init;
|
exports.init = init;
|
||||||
exports.close = close;
|
exports.close = close;
|
||||||
|
exports.flatten = flatten;
|
||||||
exports.info = info;
|
exports.info = info;
|
||||||
exports.warn = warn;
|
exports.warn = warn;
|
||||||
exports.error = error;
|
exports.error = error;
|
||||||
|
|||||||
+1
-3
@@ -410,15 +410,13 @@ function fault(xml, cwmpVersion) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function request(httpRequest, cwmpVersion, warn) {
|
function request(data, cwmpVersion, warn) {
|
||||||
warnings = warn;
|
warnings = warn;
|
||||||
|
|
||||||
const rpc = {
|
const rpc = {
|
||||||
cwmpVersion: cwmpVersion
|
cwmpVersion: cwmpVersion
|
||||||
};
|
};
|
||||||
|
|
||||||
const data = httpRequest.getBody();
|
|
||||||
|
|
||||||
if (!data.length)
|
if (!data.length)
|
||||||
return rpc;
|
return rpc;
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user