// returns -1 for failures including the other end closing the socket // returns 0 if successful in reading data, but still not read the data fully // returns 1 if successful in reading all the data mDNSlocal int ProxyTCPRead(ProxyTCPInfo_t *tcpInfo) { long n; mDNSBool closed; if (tcpInfo->nread < 2) // First read the two-byte length preceeding the DNS message { mDNSu8 *lenptr = (mDNSu8 *)&tcpInfo->replyLen; n = mDNSPlatformReadTCP(&tcpInfo->sock, lenptr + tcpInfo->nread, 2 - tcpInfo->nread, &closed); if (n < 0 || closed) { LogMsg("ProxyTCPRead: attempt to read message length failed"); return -1; } tcpInfo->nread += n; if (tcpInfo->nread < 2) { LogMsg("ProxyTCPRead: nread %d, n %d", tcpInfo->nread, n); return 0; } tcpInfo->replyLen = (mDNSu16)((mDNSu16)lenptr[0] << 8 | lenptr[1]); if (tcpInfo->replyLen < sizeof(DNSMessageHeader)) { LogMsg("ProxyTCPRead: Message length too short (%d bytes)", tcpInfo->replyLen); return -1; } tcpInfo->reply = mallocL("ProxyTCPInfo", tcpInfo->replyLen); if (!tcpInfo->reply) { LogMsg("ProxyTCPRead: Memory failure"); return -1; } } n = mDNSPlatformReadTCP(&tcpInfo->sock, ((char *)tcpInfo->reply) + (tcpInfo->nread - 2), tcpInfo->replyLen - (tcpInfo->nread - 2), &closed); if (n < 0 || closed) { LogMsg("ProxyTCPRead: read failure n %d, closed %d", n, closed); return -1; } tcpInfo->nread += n; if ((tcpInfo->nread - 2) != tcpInfo->replyLen) return 0; else return 1; }
mDNSlocal void tcpConnectionCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEstablished, mStatus err) { mStatus status = mStatus_NoError; tcpLNTInfo *tcpInfo = (tcpLNTInfo *)context; mDNSBool closed = mDNSfalse; long n = 0; long nsent = 0; if (tcpInfo == mDNSNULL) { LogInfo("tcpConnectionCallback: no tcpInfo context"); status = mStatus_Invalid; goto exit; } // The handlers below expect to be called with the lock held mDNS_Lock(tcpInfo->m); if (err) { LogInfo("tcpConnectionCallback: received error"); goto exit; } if (ConnectionEstablished) // connection is established - send the message { LogInfo("tcpConnectionCallback: connection established, sending message"); nsent = mDNSPlatformWriteTCP(sock, (char *)tcpInfo->Request, tcpInfo->requestLen); if (nsent != (long)tcpInfo->requestLen) { LogMsg("tcpConnectionCallback: error writing"); status = mStatus_UnknownErr; goto exit; } } else { n = mDNSPlatformReadTCP(sock, (char *)tcpInfo->Reply + tcpInfo->nread, tcpInfo->replyLen - tcpInfo->nread, &closed); LogInfo("tcpConnectionCallback: mDNSPlatformReadTCP read %d bytes", n); if (n < 0) { LogInfo("tcpConnectionCallback - read returned %d", n); status = mStatus_ConnFailed; goto exit; } else if (closed) { LogInfo("tcpConnectionCallback: socket closed by remote end %d", tcpInfo->nread); status = mStatus_ConnFailed; goto exit; } tcpInfo->nread += n; LogInfo("tcpConnectionCallback tcpInfo->nread %d", tcpInfo->nread); if (tcpInfo->nread > LNT_MAXBUFSIZE) { LogInfo("result truncated..."); tcpInfo->nread = LNT_MAXBUFSIZE; } switch (tcpInfo->op) { case LNTDiscoveryOp: handleLNTDeviceDescriptionResponse (tcpInfo); break; case LNTExternalAddrOp: handleLNTGetExternalAddressResponse(tcpInfo); break; case LNTPortMapOp: handleLNTPortMappingResponse (tcpInfo); break; case LNTPortMapDeleteOp: status = mStatus_ConfigChanged; break; default: LogMsg("tcpConnectionCallback: bad tcp operation! %d", tcpInfo->op); status = mStatus_Invalid; break; } } exit: if (err || status) { mDNS *m = tcpInfo->m; switch (tcpInfo->op) { case LNTDiscoveryOp: if (m->UPnPSOAPAddressString == mDNSNULL) mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "failure", "SOAP Address", ""); if (m->UPnPSOAPURL == mDNSNULL) mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "failure", "SOAP path", ""); if (m->UPnPSOAPAddressString && m->UPnPSOAPURL) mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "success", "success", ""); break; case LNTExternalAddrOp: mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.AddressRequest", mDNSIPv4AddressIsZero(m->ExternalAddress) ? "failure" : "success", mDNSIPv4AddressIsZero(m->ExternalAddress) ? "failure" : "success", ""); break; case LNTPortMapOp: if (tcpInfo->parentNATInfo) mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", (tcpInfo->parentNATInfo->Result) ? "failure" : "success", (tcpInfo->parentNATInfo->Result) ? "failure" : "success", "Result: %d", tcpInfo->parentNATInfo->Result); break; case LNTPortMapDeleteOp: break; default: break; } mDNSPlatformTCPCloseConnection(tcpInfo->sock); tcpInfo->sock = mDNSNULL; if (tcpInfo->Request) { mDNSPlatformMemFree(tcpInfo->Request); tcpInfo->Request = mDNSNULL; } if (tcpInfo->Reply ) { mDNSPlatformMemFree(tcpInfo->Reply); tcpInfo->Reply = mDNSNULL; } } if (tcpInfo) mDNS_Unlock(tcpInfo->m); if (status == mStatus_ConfigChanged) DisposeInfoFromUnmapList(tcpInfo->m, tcpInfo); }